917a6dcbf4f8fdbedff2e544d648978d1ea6b353
[petitboot] / discover / resource.c
1
2 #define _GNU_SOURCE
3
4 #include <assert.h>
5 #include <stdbool.h>
6 #include <string.h>
7
8 #include <url/url.h>
9 #include <talloc/talloc.h>
10
11 #include "device-handler.h"
12 #include "resource.h"
13 #include "paths.h"
14
15 static int is_prefix_ignorecase(const char *str, const char *prefix)
16 {
17         return !strncasecmp(str, prefix, strlen(prefix));
18 }
19
20 struct devpath_resource_info {
21         char    *dev, *path;
22 };
23
24 static struct discover_device *parse_device_string(
25                 struct device_handler *handler, const char *devstr)
26 {
27         if (is_prefix_ignorecase(devstr, "uuid="))
28                 return device_lookup_by_uuid(handler, devstr + strlen("uuid"));
29
30         if (is_prefix_ignorecase(devstr, "label="))
31                 return device_lookup_by_label(handler,
32                                         devstr + strlen("label="));
33
34         return device_lookup_by_name(handler, devstr);
35 }
36 static void resolve_devpath_against_device(struct resource *res,
37         struct discover_device *dev, const char *path)
38 {
39         char *resolved_path = join_paths(res, dev->mount_path, path);
40         res->url = pb_url_parse(res, resolved_path);
41         res->resolved = true;
42 }
43
44 struct resource *create_devpath_resource(void *ctx,
45         struct discover_device *orig_device,
46         const char *devpath)
47 {
48         struct devpath_resource_info *info;
49         char *pos, *devstr, *path;
50         struct resource *res;
51         struct pb_url *url;
52
53         res = talloc(ctx, struct resource);
54
55         pos = strchr(devpath, ':');
56
57         /* do we have a "://" scheme separator? */
58         if (pos && pos[1] && pos[1] == '/' && pos[2] && pos[2] == '/') {
59                 url = pb_url_parse(res, devpath);
60
61                 if (url->scheme != pb_url_file) {
62                         /* not a file? we're ready to go */
63                         res->resolved = true;
64                         res->url = url;
65                 } else {
66                         /* we've been passed a file:// URL, which has no device
67                          * specifier. We can resolve against the original
68                          * device */
69                         resolve_devpath_against_device(res, orig_device,
70                                         url->path);
71                         talloc_free(url);
72                 }
73                 return res;
74         }
75
76         /* if there was no device specified, we can resolve now */
77         if (!pos) {
78                 resolve_devpath_against_device(res, orig_device, devpath);
79                 return res;
80         }
81
82         devstr = talloc_strndup(res, devpath, pos - devpath);
83         path = talloc_strdup(res, pos + 1);
84
85         /* defer resolution until we can find a suitable matching device */
86         info = talloc(res, struct devpath_resource_info);
87         info->dev = devstr;
88         info->path = path;
89
90         res->resolved = false;
91         res->info = info;
92
93         return res;
94 }
95
96 bool resolve_devpath_resource(struct device_handler *handler,
97                 struct resource *res)
98 {
99         struct devpath_resource_info *info = res->info;
100         struct discover_device *dev;
101
102         assert(!res->resolved);
103
104         dev = parse_device_string(handler, info->dev);
105
106         if (!dev)
107                 return false;
108
109         resolve_devpath_against_device(res, dev, info->path);
110         talloc_free(info);
111
112         return true;
113 }