partname: allow skipping existing 'rootfs_data' partition
[project/fstools.git] / libfstools / partname.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 #include "common.h"
4
5 #define BUFLEN 64
6
7 const char *const block_dir_name = "/sys/class/block";
8
9 struct devpath {
10 char prefix[5];
11 char device[11];
12 };
13
14 struct partname_volume {
15 struct volume v;
16 union {
17 char devpathstr[16];
18 struct devpath devpath;
19 } dev;
20
21 union {
22 char devpathstr[16];
23 struct devpath devpath;
24 } parent_dev;
25 };
26
27 static struct driver partname_driver;
28
29 static int partname_volume_identify(struct volume *v)
30 {
31 struct partname_volume *p = container_of(v, struct partname_volume, v);
32 int ret = FS_NONE;
33 FILE *f;
34
35 f = fopen(p->dev.devpathstr, "r");
36 if (!f)
37 return ret;
38
39 ret = block_file_identify(f, 0);
40
41 fclose(f);
42
43 return ret;
44 }
45
46 static int partname_volume_init(struct volume *v)
47 {
48 struct partname_volume *p = container_of(v, struct partname_volume, v);
49 char voldir[BUFLEN];
50 unsigned int volsize;
51
52 snprintf(voldir, sizeof(voldir), "%s/%s", block_dir_name, p->dev.devpath.device);
53
54 if (read_uint_from_file(voldir, "size", &volsize))
55 return -1;
56
57 v->type = BLOCKDEV;
58 v->size = volsize << 9; /* size is returned in sectors of 512 bytes */
59 v->blk = p->dev.devpathstr;
60
61 return block_volume_format(v, 0, p->parent_dev.devpathstr);
62 }
63
64 /* from procd/utils.c -> should go to libubox */
65 static char* get_cmdline_val(const char* name, char* out, int len)
66 {
67 char line[1024], *c, *sptr;
68 int fd = open("/proc/cmdline", O_RDONLY);
69 ssize_t r = read(fd, line, sizeof(line) - 1);
70 close(fd);
71
72 if (r <= 0)
73 return NULL;
74
75 line[r] = 0;
76
77 for (c = strtok_r(line, " \t\n", &sptr); c;
78 c = strtok_r(NULL, " \t\n", &sptr)) {
79 char *sep = strchr(c, '=');
80 if (sep == NULL)
81 continue;
82
83 ssize_t klen = sep - c;
84 if (strncmp(name, c, klen) || name[klen] != 0)
85 continue;
86
87 strncpy(out, &sep[1], len);
88 out[len-1] = '\0';
89 return out;
90 }
91
92 return NULL;
93 }
94
95 static char *rootdevname(char *devpath) {
96 int l;
97
98 l = strlen(devpath) - 1;
99
100 /* strip partition suffix from root=/dev/... string */
101 while (l > 0 && (devpath[l] >= '0' && devpath[l] <= '9'))
102 --l;
103
104 if (devpath[l] != 'p')
105 ++l;
106
107 devpath[l] = '\0';
108
109 return basename(devpath);
110 }
111
112 static struct volume *partname_volume_find(char *name)
113 {
114 struct partname_volume *p;
115 char volnamegstr[BUFLEN];
116 char namebuf[BUFLEN];
117 char rootparam[BUFLEN];
118 char *rootdev = NULL, *devname, *tmp;
119 int j;
120 bool found = false;
121 glob_t gl;
122
123 if (get_cmdline_val("fstools_ignore_partname", rootparam, sizeof(rootparam))) {
124 if (!strcmp("1", rootparam))
125 return NULL;
126 }
127
128 if (get_cmdline_val("root", rootparam, sizeof(rootparam))) {
129 rootdev = rootdevname(rootparam);
130 /* find partition on same device as rootfs */
131 snprintf(volnamegstr, sizeof(volnamegstr), "%s/%s/*/name", block_dir_name, rootdev);
132 } else {
133 /* no 'root=' kernel cmdline parameter, find on any block device */
134 snprintf(volnamegstr, sizeof(volnamegstr), "%s/*/name", block_dir_name);
135 }
136
137 if (!glob(volnamegstr, GLOB_NOESCAPE, NULL, &gl))
138 for (j = 0; j < gl.gl_pathc; j++) {
139 if (!read_string_from_file("", gl.gl_pathv[j], namebuf, sizeof(namebuf)))
140 continue;
141 if (!strncmp(namebuf, name, sizeof(namebuf))) {
142 found = 1;
143 break;
144 }
145 }
146
147 if (!found)
148 return NULL;
149
150 devname = gl.gl_pathv[j];
151 tmp = strrchr(devname, '/');
152 *tmp = '\0';
153 devname = strrchr(devname, '/') + 1;
154
155 p = calloc(1, sizeof(*p));
156 memcpy(p->dev.devpath.prefix, "/dev/", sizeof(p->dev.devpath.prefix));
157 strncpy(p->dev.devpath.device, devname, sizeof(p->dev.devpath.device) - 1);
158 p->dev.devpath.device[sizeof(p->dev.devpath.device)-1] = '\0';
159
160 memcpy(p->parent_dev.devpath.prefix, "/dev/", sizeof(p->parent_dev.devpath.prefix));
161 if (rootdev)
162 strncpy(p->parent_dev.devpath.device, rootdev, sizeof(p->parent_dev.devpath.device) - 1);
163 else
164 strncpy(p->parent_dev.devpath.device, rootdevname(devname), sizeof(p->parent_dev.devpath.device) - 1);
165
166 p->parent_dev.devpath.device[sizeof(p->parent_dev.devpath.device)-1] = '\0';
167
168 p->v.drv = &partname_driver;
169 p->v.blk = p->dev.devpathstr;
170 p->v.name = name;
171
172 return &p->v;
173 }
174
175 static struct driver partname_driver = {
176 .name = "partname",
177 .find = partname_volume_find,
178 .init = partname_volume_init,
179 .identify = partname_volume_identify,
180 };
181
182 DRIVER(partname_driver);