]> git.ipfire.org Git - thirdparty/systemd.git/blame - wait_for_sysfs.c
[PATCH] wait_for_sysfs debug cleanup
[thirdparty/systemd.git] / wait_for_sysfs.c
CommitLineData
a8b5267a
KS
1/*
2 * wait_for_sysfs.c - small program to delay the execution
3 * of /etc/hotplug.d/ programs, until sysfs
e629ca3f 4 * is fully populated by the kernel. Depending on
a8b5267a
KS
5 * the type of device, we wait for all expected
6 * directories and then just exit.
7 *
8 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation version 2 of the License.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 */
24
25#include <stdio.h>
26#include <stddef.h>
27#include <stdlib.h>
28#include <unistd.h>
29#include <string.h>
30#include <ctype.h>
31#include <errno.h>
32#include <sys/stat.h>
33
34#include "logging.h"
35#include "libsysfs/sysfs/libsysfs.h"
36
37#ifdef LOG
38unsigned char logname[LOGNAME_SIZE];
39void log_message(int level, const char *format, ...)
40{
41 va_list args;
42
43 va_start(args, format);
44 vsyslog(level, format, args);
45 va_end(args);
46}
47#endif
48
49#define WAIT_MAX_SECONDS 5
50#define WAIT_LOOP_PER_SECOND 20
51
e629ca3f 52/* wait for specific file to show up, normally the "dev"-file */
a8b5267a
KS
53static int wait_for_class_device_attributes(struct sysfs_class_device *class_dev)
54{
55 static struct class_file {
56 char *subsystem;
57 char *file;
58 } class_files[] = {
59 { .subsystem = "net", .file = "ifindex" },
e629ca3f
KS
60 { .subsystem = "scsi_host", .file = "unique_id" },
61 { .subsystem = "scsi_device", .file = NULL },
62 { .subsystem = "pcmcia_socket", .file = "card_type" },
a8b5267a 63 { .subsystem = "usb_host", .file = NULL },
a8b5267a
KS
64 { NULL, NULL }
65 };
66 struct class_file *classfile;
67 const char *file = "dev";
68 int loop;
69
70 /* look if we want to look for another file instead of "dev" */
71 for (classfile = class_files; classfile->subsystem != NULL; classfile++) {
72 if (strcmp(class_dev->classname, classfile->subsystem) == 0) {
73 if (classfile->file == NULL) {
74 dbg("class '%s' has no file to wait for", class_dev->classname);
75 return 0;
76 }
77 file = classfile->file;
78 break;
79 }
80 }
81 dbg("looking at class '%s' for specific file '%s'", class_dev->classname, file);
82
83 loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
84 while (--loop) {
85 if (sysfs_get_classdev_attr(class_dev, file) != NULL) {
86 dbg("class '%s' specific file '%s' found", class_dev->classname, file);
87 return 0;
88 }
e629ca3f
KS
89
90 usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
a8b5267a
KS
91 }
92
e629ca3f 93 dbg("error: getting class '%s' specific file '%s'", class_dev->classname, file);
a8b5267a
KS
94 return -1;
95}
96
e629ca3f 97/* skip waiting for physical device */
a8b5267a
KS
98static int class_device_expect_no_device_link(struct sysfs_class_device *class_dev)
99{
a8b5267a
KS
100 static char *devices_without_link[] = {
101 "nb",
102 "ram",
103 "loop",
104 "fd",
105 "md",
106 "dos_cd",
107 "double",
108 "flash",
109 "msd",
110 "rflash",
111 "rom",
112 "rrom",
113 "sbpcd",
114 "pcd",
115 "pf",
116 "scd",
117 "sit",
118 "lp",
119 "ubd",
120 "vcs",
121 "vcsa",
122 "console",
123 "tty",
124 "ttyS",
125 NULL
126 };
e629ca3f 127 char **device;
a8b5267a
KS
128
129 for (device = devices_without_link; *device != NULL; device++) {
130 int len = strlen(*device);
131
132 /* look if name matches */
133 if (strncmp(class_dev->name, *device, len) != 0)
134 continue;
135
136 /* exact match */
137 if (strlen(class_dev->name) == len)
138 return 1;
139
140 /* instance numbers are matching too */
141 if (isdigit(class_dev->name[len]))
142 return 1;
143 }
144
145 return 0;
146}
147
e629ca3f
KS
148/* skip waiting for the bus */
149static int class_device_expect_no_bus(struct sysfs_class_device *class_dev)
150{
151 static char *devices_without_bus[] = {
152 "scsi_host",
153 NULL
154 };
155 char **device;
156
157 for (device = devices_without_bus; *device != NULL; device++) {
158 int len = strlen(*device);
159
160 if (strncmp(class_dev->classname, *device, len) == 0)
161 return 1;
162 }
163
164 return 0;
165}
166
167/* wait for the bus and for a bus specific file to show up */
a8b5267a
KS
168static int wait_for_bus_device(struct sysfs_device *device_dev)
169{
170 static struct bus_file {
171 char *bus;
172 char *file;
173 } bus_files[] = {
174 { .bus = "scsi", .file = "vendor" },
175 { .bus = "usb", .file = "idVendor" },
176 { .bus = "usb", .file = "iInterface" },
177 { .bus = "usb-serial", .file = "detach_state" },
178 { .bus = "ide", .file = "detach_state" },
179 { .bus = "pci", .file = "vendor" },
e629ca3f 180 { .bus = "platform", .file = "detach_state" },
a8b5267a
KS
181 { NULL }
182 };
183 struct bus_file *busfile;
184 int loop;
185
186 /* wait for the /bus-device link to the /device-device */
187 loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
188 while (--loop) {
189 if (sysfs_get_device_bus(device_dev) == 0)
190 break;
191
192 usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
193 }
194 if (loop == 0) {
195 dbg("error: getting /bus-device link");
196 return -1;
197 }
198 dbg("/bus-device link found for bus '%s'", device_dev->bus);
199
200 /* wait for a bus specific file to show up */
201 loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
202 while (--loop) {
e629ca3f
KS
203 int found = 0;
204
a8b5267a
KS
205 for (busfile = bus_files; busfile->bus != NULL; busfile++) {
206 if (strcmp(device_dev->bus, busfile->bus) == 0) {
e629ca3f 207 found = 1;
a8b5267a
KS
208 dbg("looking at bus '%s' for specific file '%s'", device_dev->bus, busfile->file);
209 if (sysfs_get_device_attr(device_dev, busfile->file) != NULL) {
210 dbg("bus '%s' specific file '%s' found", device_dev->bus, busfile->file);
211 return 0;
212 }
a8b5267a
KS
213 }
214 }
e629ca3f
KS
215 if (found == 0) {
216 info("error: unknown bus, please report to "
217 "<linux-hotplug-devel@lists.sourceforge.net> '%s'", device_dev->bus);
218 return -1;
219 }
220 usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
a8b5267a
KS
221 }
222
223 dbg("error: getting bus '%s' specific file '%s'", device_dev->bus, busfile->file);
224 return -1;
225}
226
227int main(int argc, char *argv[], char *envp[])
228{
229 const char *devpath = "";
230 const char *action;
231 const char *subsystem;
232 char sysfs_path[SYSFS_PATH_MAX];
233 char filename[SYSFS_PATH_MAX];
234 struct sysfs_class_device *class_dev;
235 struct sysfs_class_device *class_dev_parent;
236 struct sysfs_device *device_dev = NULL;
237 int loop;
238 int rc = 0;
239
e629ca3f
KS
240 init_logging("wait_for_sysfs");
241
a8b5267a
KS
242 if (argc != 2) {
243 dbg("error: subsystem");
244 return 1;
245 }
246 subsystem = argv[1];
247
248 devpath = getenv ("DEVPATH");
249 if (!devpath) {
250 dbg("error: no DEVPATH");
251 return 1;
252 }
253
254 action = getenv ("ACTION");
255 if (!action) {
256 dbg("error: no ACTION");
257 return 1;
258 }
259
e629ca3f 260 /* we only wait on an add event */
a8b5267a
KS
261 if (strcmp(action, "add") != 0)
262 return 0;
263
264 if (sysfs_get_mnt_path(sysfs_path, SYSFS_PATH_MAX) != 0) {
265 dbg("error: no sysfs path");
266 return 2;
267 }
268
269 if ((strncmp(devpath, "/block/", 7) == 0) || (strncmp(devpath, "/class/", 7) == 0)) {
270 /* open the class device we are called for */
271 snprintf(filename, SYSFS_PATH_MAX-1, "%s%s", sysfs_path, devpath);
272 filename[SYSFS_PATH_MAX-1] = '\0';
273
274 loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
275 while (--loop) {
276 class_dev = sysfs_open_class_device_path(filename);
277 if (class_dev)
278 break;
e629ca3f
KS
279
280 usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
a8b5267a
KS
281 }
282 if (class_dev == NULL) {
283 dbg("error: getting class_device");
e629ca3f 284 rc = 3;
a8b5267a
KS
285 goto exit;
286 }
287 dbg("class_device opened '%s'", filename);
288
e629ca3f
KS
289 if (wait_for_class_device_attributes(class_dev) != 0) {
290 rc = 4;
291 goto exit_class;
292 }
a8b5267a 293
e629ca3f 294 /* skip devices without /device-link */
a8b5267a 295 if (class_device_expect_no_device_link(class_dev)) {
e629ca3f
KS
296 dbg("no device symlink expected for '%s', ", class_dev->name);
297 goto exit_class;
a8b5267a
KS
298 }
299
300 /* the symlink may be on the parent device */
301 class_dev_parent = sysfs_get_classdev_parent(class_dev);
302 if (class_dev_parent)
303 dbg("looking at parent device for device link '%s'", class_dev_parent->path);
304
305 /* wait for the symlink to the /device-device */
306 dbg("waiting for symlink to /device-device");
307 loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
308 while (--loop) {
309 if (class_dev_parent)
310 device_dev = sysfs_get_classdev_device(class_dev_parent);
311 else
312 device_dev = sysfs_get_classdev_device(class_dev);
313
314 if (device_dev)
315 break;
316
317 usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
318 }
319 if (device_dev == NULL) {
320 dbg("error: getting /device-device");
a8b5267a 321 rc = 5;
e629ca3f 322 goto exit_class;
a8b5267a
KS
323 }
324 dbg("device symlink found pointing to '%s'", device_dev->path);
325
326 /* wait for the bus value */
e629ca3f
KS
327 if (class_device_expect_no_bus(class_dev)) {
328 dbg("no bus device expected for '%s', ", class_dev->classname);
329 } else {
330 if (wait_for_bus_device(device_dev) != 0)
331 rc = 6;
332 }
a8b5267a 333
e629ca3f
KS
334exit_class:
335 sysfs_close_class_device(class_dev);
a8b5267a
KS
336
337 } else if ((strncmp(devpath, "/devices/", 9) == 0)) {
338 /* open the path we are called for */
339 snprintf(filename, SYSFS_PATH_MAX-1, "%s%s", sysfs_path, devpath);
340 filename[SYSFS_PATH_MAX-1] = '\0';
341
342 loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
343 while (--loop) {
344 device_dev = sysfs_open_device_path(filename);
345 if (device_dev)
346 break;
e629ca3f
KS
347
348 usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
a8b5267a
KS
349 }
350 if (device_dev == NULL) {
351 dbg("error: getting /device-device");
e629ca3f 352 rc = 7;
a8b5267a
KS
353 goto exit;
354 }
355 dbg("device_device opened '%s'", filename);
356
357 /* wait for the bus value */
358 if (wait_for_bus_device(device_dev) != 0)
e629ca3f 359 rc = 8;
a8b5267a
KS
360
361 sysfs_close_device(device_dev);
362
a8b5267a
KS
363 } else {
364 dbg("unhandled sysfs path, no need to wait");
365 }
366
367exit:
368 if (rc == 0)
e629ca3f 369 dbg("result: waiting for sysfs successful '%s'", devpath);
a8b5267a 370 else
e629ca3f
KS
371 info("error: wait_for_sysfs needs an update to handle the device '%s' "
372 "properly, please report to <linux-hotplug-devel@lists.sourceforge.net>",
373 devpath);
a8b5267a
KS
374
375 return rc;
376}