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