parser: Use list to hold parsers
[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
38 void resolve_resource_against_device(struct resource *res,
39         struct discover_device *dev, const char *path)
40 {
41         char *resolved_path = join_paths(res, dev->mount_path, path);
42         res->url = pb_url_parse(res, resolved_path);
43         res->resolved = true;
44 }
45
46 struct resource *create_devpath_resource(struct discover_boot_option *opt,
47         struct discover_device *orig_device,
48         const char *devpath)
49 {
50         struct devpath_resource_info *info;
51         char *pos, *devstr, *path;
52         struct resource *res;
53         struct pb_url *url;
54
55         res = talloc(opt, struct resource);
56
57         pos = strchr(devpath, ':');
58
59         /* do we have a "://" scheme separator? */
60         if (pos && pos[1] && pos[1] == '/' && pos[2] && pos[2] == '/') {
61                 url = pb_url_parse(res, devpath);
62
63                 if (url->scheme != pb_url_file) {
64                         /* not a file? we're ready to go */
65                         res->resolved = true;
66                         res->url = url;
67                 } else {
68                         /* we've been passed a file:// URL, which has no device
69                          * specifier. We can resolve against the original
70                          * device */
71                         resolve_resource_against_device(res, orig_device,
72                                         url->path);
73                         talloc_free(url);
74                 }
75                 return res;
76         }
77
78         /* if there was no device specified, we can resolve now */
79         if (!pos) {
80                 resolve_resource_against_device(res, orig_device, devpath);
81                 return res;
82         }
83
84         devstr = talloc_strndup(res, devpath, pos - devpath);
85         path = talloc_strdup(res, pos + 1);
86
87         pb_log("%s: resource depends on device %s\n", __func__, devstr);
88
89         /* defer resolution until we can find a suitable matching device */
90         info = talloc(res, struct devpath_resource_info);
91         info->dev = devstr;
92         info->path = path;
93
94         res->resolved = false;
95         res->info = info;
96
97         return res;
98 }
99
100 bool resolve_devpath_resource(struct device_handler *handler,
101                 struct resource *res)
102 {
103         struct devpath_resource_info *info = res->info;
104         struct discover_device *dev;
105
106         assert(!res->resolved);
107
108         dev = parse_device_string(handler, info->dev);
109
110         if (!dev)
111                 return false;
112
113         resolve_resource_against_device(res, dev, info->path);
114         talloc_free(info);
115
116         return true;
117 }
118
119 struct resource *create_url_resource(struct discover_boot_option *opt,
120                 struct pb_url *url)
121 {
122         struct resource *res;
123
124         res = talloc(opt, struct resource);
125         res->url = url;
126         res->resolved = true;
127
128         return res;
129 }