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