]> git.ipfire.org Git - thirdparty/mdadm.git/blame - sysfs.c
cleanup an unused call to container2devname
[thirdparty/mdadm.git] / sysfs.c
CommitLineData
e86c9dd6
NB
1/*
2 * sysfs - extract md related information from sysfs. Part of:
3 * mdadm - manage Linux "md" devices aka RAID arrays.
4 *
5 * Copyright (C) 2006 Neil Brown <neilb@suse.de>
6 *
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 * Author: Neil Brown
23 * Email: <neilb@suse.de>
24 */
25
26#include "mdadm.h"
27#include <dirent.h>
1770662b 28#include <ctype.h>
e86c9dd6
NB
29
30int load_sys(char *path, char *buf)
31{
32 int fd = open(path, O_RDONLY);
33 int n;
34 if (fd < 0)
35 return -1;
36 n = read(fd, buf, 1024);
37 close(fd);
2f6079dc 38 if (n <0 || n >= 1024)
e86c9dd6
NB
39 return -1;
40 buf[n] = 0;
8dfb8619 41 if (n && buf[n-1] == '\n')
e86c9dd6
NB
42 buf[n-1] = 0;
43 return 0;
44}
45
7e0f6979 46void sysfs_free(struct mdinfo *sra)
8382f19b 47{
7e0f6979
NB
48 while (sra) {
49 struct mdinfo *sra2 = sra->next;
50 while (sra->devs) {
51 struct mdinfo *d = sra->devs;
52 sra->devs = d->next;
53 free(d);
54 }
55 free(sra);
56 sra = sra2;
8382f19b 57 }
8382f19b
NB
58}
59
549e9569
NB
60int sysfs_open(int devnum, char *devname, char *attr)
61{
62 char fname[50];
549e9569 63 int fd;
1e4bc070 64 char *mdname = devnum2devname(devnum);
549e9569 65
1e4bc070
DW
66 if (!mdname)
67 return -1;
68
69 sprintf(fname, "/sys/block/%s/md/", mdname);
549e9569
NB
70 if (devname) {
71 strcat(fname, devname);
72 strcat(fname, "/");
73 }
74 strcat(fname, attr);
75 fd = open(fname, O_RDWR);
ea6d09b0 76 if (fd < 0 && errno == EACCES)
549e9569 77 fd = open(fname, O_RDONLY);
1e4bc070 78 free(mdname);
549e9569
NB
79 return fd;
80}
81
f35f2525
N
82void sysfs_init(struct mdinfo *mdi, int fd, int devnum)
83{
84 if (fd >= 0) {
85 struct stat stb;
86 mdu_version_t vers;
87 if (fstat(fd, &stb))
88 return;
89 if (ioctl(fd, RAID_VERSION, &vers) != 0)
90 return;
4ebd3237 91 if (major(stb.st_rdev) == MD_MAJOR)
f35f2525 92 sprintf(mdi->sys_name, "md%d", (int)minor(stb.st_rdev));
4ebd3237 93 else if (major(stb.st_rdev) == get_mdp_major())
f35f2525
N
94 sprintf(mdi->sys_name, "md_d%d",
95 (int)minor(stb.st_rdev)>>MdpMinorShift);
4ebd3237
N
96 else {
97 /* must be an extended-minor partition. Look at the
98 * /sys/dev/block/%d:%d link which must look like
99 * ../../block/mdXXX/mdXXXpYY
100 */
101 char path[30];
102 char link[200];
103 char *cp;
104 int n;
105 sprintf(path, "/sys/dev/block/%d:%d", major(stb.st_rdev),
106 minor(stb.st_rdev));
107 n = readlink(path, link, sizeof(link)-1);
108 if (n <= 0)
9c322006 109 return;
4ebd3237
N
110 link[n] = 0;
111 cp = strrchr(link, '/');
112 if (cp) *cp = 0;
113 cp = strchr(link, '/');
114 if (cp && strncmp(cp, "/md", 3) == 0)
9c322006 115 strcpy(mdi->sys_name, cp+1);
4ebd3237 116 else
9c322006 117 return;
4ebd3237 118 }
f35f2525
N
119 } else {
120 if (devnum >= 0)
121 sprintf(mdi->sys_name, "md%d", devnum);
122 else
123 sprintf(mdi->sys_name, "md_d%d",
124 -1-devnum);
125 }
126}
127
7e0f6979 128struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options)
e86c9dd6
NB
129{
130 /* Longest possible name in sysfs, mounted at /sys, is
131 * /sys/block/md_dXXX/md/dev-XXXXX/block/dev
132 * /sys/block/md_dXXX/md/metadata_version
133 * which is about 41 characters. 50 should do for now
134 */
135 char fname[50];
136 char buf[1024];
137 char *base;
138 char *dbase;
7e0f6979 139 struct mdinfo *sra;
06c7f68e 140 struct mdinfo *dev;
355726fa 141 DIR *dir = NULL;
e86c9dd6
NB
142 struct dirent *de;
143
144 sra = malloc(sizeof(*sra));
145 if (sra == NULL)
146 return sra;
f35f2525
N
147 memset(sra, 0, sizeof(*sra));
148 sysfs_init(sra, fd, devnum);
e86c9dd6 149
7e0f6979 150 sprintf(fname, "/sys/block/%s/md/", sra->sys_name);
e86c9dd6
NB
151 base = fname + strlen(fname);
152
153 sra->devs = NULL;
8382f19b
NB
154 if (options & GET_VERSION) {
155 strcpy(base, "metadata_version");
156 if (load_sys(fname, buf))
157 goto abort;
294d6f45 158 if (strncmp(buf, "none", 4) == 0) {
7e0f6979
NB
159 sra->array.major_version =
160 sra->array.minor_version = -1;
294d6f45
NB
161 strcpy(sra->text_version, "");
162 } else if (strncmp(buf, "external:", 9) == 0) {
142cb9e1
NB
163 sra->array.major_version = -1;
164 sra->array.minor_version = -2;
165 strcpy(sra->text_version, buf+9);
b8ac1967 166 } else {
8382f19b 167 sscanf(buf, "%d.%d",
7e0f6979
NB
168 &sra->array.major_version,
169 &sra->array.minor_version);
b8ac1967
NB
170 strcpy(sra->text_version, buf);
171 }
8382f19b 172 }
e86c9dd6
NB
173 if (options & GET_LEVEL) {
174 strcpy(base, "level");
175 if (load_sys(fname, buf))
176 goto abort;
7e0f6979 177 sra->array.level = map_name(pers, buf);
e86c9dd6
NB
178 }
179 if (options & GET_LAYOUT) {
180 strcpy(base, "layout");
181 if (load_sys(fname, buf))
182 goto abort;
7e0f6979 183 sra->array.layout = strtoul(buf, NULL, 0);
e86c9dd6 184 }
549e9569
NB
185 if (options & GET_DISKS) {
186 strcpy(base, "raid_disks");
187 if (load_sys(fname, buf))
188 goto abort;
189 sra->array.raid_disks = strtoul(buf, NULL, 0);
f1d26766
DW
190 }
191 if (options & GET_DEGRADED) {
192 strcpy(base, "degraded");
193 if (load_sys(fname, buf))
194 goto abort;
195 sra->array.failed_disks = strtoul(buf, NULL, 0);
549e9569 196 }
e86c9dd6
NB
197 if (options & GET_COMPONENT) {
198 strcpy(base, "component_size");
199 if (load_sys(fname, buf))
200 goto abort;
201 sra->component_size = strtoull(buf, NULL, 0);
353632d9
NB
202 /* sysfs reports "K", but we want sectors */
203 sra->component_size *= 2;
e86c9dd6
NB
204 }
205 if (options & GET_CHUNK) {
206 strcpy(base, "chunk_size");
207 if (load_sys(fname, buf))
208 goto abort;
7e0f6979 209 sra->array.chunk_size = strtoul(buf, NULL, 0);
e86c9dd6 210 }
758d3a8e
NB
211 if (options & GET_CACHE) {
212 strcpy(base, "stripe_cache_size");
213 if (load_sys(fname, buf))
214 goto abort;
215 sra->cache_size = strtoul(buf, NULL, 0);
216 }
37dfc3d6
NB
217 if (options & GET_MISMATCH) {
218 strcpy(base, "mismatch_cnt");
219 if (load_sys(fname, buf))
220 goto abort;
221 sra->mismatch_cnt = strtoul(buf, NULL, 0);
222 }
1770662b
DW
223 if (options & GET_SAFEMODE) {
224 int scale = 1;
225 int dot = 0;
226 int i;
227 unsigned long msec;
228 size_t len;
229
230 strcpy(base, "safe_mode_delay");
231 if (load_sys(fname, buf))
232 goto abort;
233
234 /* remove a period, and count digits after it */
235 len = strlen(buf);
236 for (i = 0; i < len; i++) {
237 if (dot) {
238 if (isdigit(buf[i])) {
239 buf[i-1] = buf[i];
240 scale *= 10;
241 }
242 buf[i] = 0;
243 } else if (buf[i] == '.') {
244 dot=1;
245 buf[i] = 0;
246 }
247 }
248 msec = strtoul(buf, NULL, 10);
249 msec = (msec * 1000) / scale;
250 sra->safe_mode_delay = msec;
251 }
e86c9dd6
NB
252
253 if (! (options & GET_DEVS))
254 return sra;
255
256 /* Get all the devices as well */
257 *base = 0;
258 dir = opendir(fname);
259 if (!dir)
260 goto abort;
7e0f6979 261 sra->array.spare_disks = 0;
e86c9dd6
NB
262
263 while ((de = readdir(dir)) != NULL) {
264 char *ep;
265 if (de->d_ino == 0 ||
266 strncmp(de->d_name, "dev-", 4) != 0)
267 continue;
268 strcpy(base, de->d_name);
269 dbase = base + strlen(base);
270 *dbase++ = '/';
271
272 dev = malloc(sizeof(*dev));
273 if (!dev)
274 goto abort;
e86c9dd6
NB
275
276 /* Always get slot, major, minor */
277 strcpy(dbase, "slot");
4795982e
DW
278 if (load_sys(fname, buf)) {
279 /* hmm... unable to read 'slot' maybe the device
280 * is going away?
281 */
282 strcpy(dbase, "block");
283 if (readlink(fname, buf, sizeof(buf)) < 0 &&
284 errno != ENAMETOOLONG) {
285 /* ...yup device is gone */
286 free(dev);
287 continue;
288 } else {
289 /* slot is unreadable but 'block' link
290 * still intact... something bad is happening
291 * so abort
292 */
293 free(dev);
294 goto abort;
295 }
296
297 }
298 dev->next = sra->devs;
299 sra->devs = dev;
300
301 strcpy(dev->sys_name, de->d_name);
06c7f68e
NB
302 dev->disk.raid_disk = strtoul(buf, &ep, 10);
303 if (*ep) dev->disk.raid_disk = -1;
e86c9dd6
NB
304
305 strcpy(dbase, "block/dev");
306 if (load_sys(fname, buf))
307 goto abort;
06c7f68e 308 sscanf(buf, "%d:%d", &dev->disk.major, &dev->disk.minor);
e86c9dd6
NB
309
310 if (options & GET_OFFSET) {
311 strcpy(dbase, "offset");
312 if (load_sys(fname, buf))
313 goto abort;
06c7f68e 314 dev->data_offset = strtoull(buf, NULL, 0);
e86c9dd6
NB
315 }
316 if (options & GET_SIZE) {
317 strcpy(dbase, "size");
318 if (load_sys(fname, buf))
319 goto abort;
047d2e49 320 dev->component_size = strtoull(buf, NULL, 0) * 2;
e86c9dd6
NB
321 }
322 if (options & GET_STATE) {
06c7f68e 323 dev->disk.state = 0;
e86c9dd6
NB
324 strcpy(dbase, "state");
325 if (load_sys(fname, buf))
326 goto abort;
327 if (strstr(buf, "in_sync"))
06c7f68e 328 dev->disk.state |= (1<<MD_DISK_SYNC);
e86c9dd6 329 if (strstr(buf, "faulty"))
06c7f68e
NB
330 dev->disk.state |= (1<<MD_DISK_FAULTY);
331 if (dev->disk.state == 0)
7e0f6979 332 sra->array.spare_disks++;
e86c9dd6
NB
333 }
334 if (options & GET_ERROR) {
335 strcpy(buf, "errors");
336 if (load_sys(fname, buf))
337 goto abort;
338 dev->errors = strtoul(buf, NULL, 0);
339 }
340 }
355726fa 341 closedir(dir);
e86c9dd6
NB
342 return sra;
343
344 abort:
355726fa
NB
345 if (dir)
346 closedir(dir);
8382f19b 347 sysfs_free(sra);
e86c9dd6
NB
348 return NULL;
349}
350
1770662b
DW
351int sysfs_attr_match(const char *attr, const char *str)
352{
353 /* See if attr, read from a sysfs file, matches
354 * str. They must either be the same, or attr can
355 * have a trailing newline or comma
356 */
357 while (*attr && *str && *attr == *str) {
358 attr++;
359 str++;
360 }
361
362 if (*str || (*attr && *attr != ',' && *attr != '\n'))
363 return 0;
364 return 1;
365}
366
367int sysfs_match_word(const char *word, char **list)
368{
369 int n;
370 for (n=0; list[n]; n++)
371 if (sysfs_attr_match(word, list[n]))
372 break;
373 return n;
374}
375
e86c9dd6
NB
376unsigned long long get_component_size(int fd)
377{
378 /* Find out the component size of the array.
379 * We cannot trust GET_ARRAY_INFO ioctl as it's
380 * size field is only 32bits.
381 * So look in /sys/block/mdXXX/md/component_size
353632d9 382 *
8686f3ed 383 * This returns in units of sectors.
e86c9dd6
NB
384 */
385 struct stat stb;
386 char fname[50];
387 int n;
388 if (fstat(fd, &stb)) return 0;
4ebd3237 389 if (major(stb.st_rdev) != get_mdp_major())
e86c9dd6 390 sprintf(fname, "/sys/block/md%d/md/component_size",
ea24acd0 391 (int)minor(stb.st_rdev));
e86c9dd6
NB
392 else
393 sprintf(fname, "/sys/block/md_d%d/md/component_size",
ea24acd0 394 (int)minor(stb.st_rdev)>>MdpMinorShift);
e86c9dd6
NB
395 fd = open(fname, O_RDONLY);
396 if (fd < 0)
397 return 0;
398 n = read(fd, fname, sizeof(fname));
399 close(fd);
400 if (n == sizeof(fname))
401 return 0;
402 fname[n] = 0;
8686f3ed 403 return strtoull(fname, NULL, 10) * 2;
e86c9dd6
NB
404}
405
7e0f6979 406int sysfs_set_str(struct mdinfo *sra, struct mdinfo *dev,
e86c9dd6
NB
407 char *name, char *val)
408{
409 char fname[50];
410 int n;
411 int fd;
7e1432fb 412
e86c9dd6 413 sprintf(fname, "/sys/block/%s/md/%s/%s",
7e0f6979 414 sra->sys_name, dev?dev->sys_name:"", name);
e86c9dd6
NB
415 fd = open(fname, O_WRONLY);
416 if (fd < 0)
417 return -1;
418 n = write(fd, val, strlen(val));
419 close(fd);
2a24d7b6
DW
420 if (n != strlen(val)) {
421 dprintf(Name ": failed to write '%s' to '%s' (%s)\n",
422 val, fname, strerror(errno));
e86c9dd6 423 return -1;
2a24d7b6 424 }
e86c9dd6
NB
425 return 0;
426}
427
7e0f6979 428int sysfs_set_num(struct mdinfo *sra, struct mdinfo *dev,
e86c9dd6
NB
429 char *name, unsigned long long val)
430{
431 char valstr[50];
432 sprintf(valstr, "%llu", val);
433 return sysfs_set_str(sra, dev, name, valstr);
434}
435
7e0f6979 436int sysfs_get_ll(struct mdinfo *sra, struct mdinfo *dev,
e86c9dd6
NB
437 char *name, unsigned long long *val)
438{
439 char fname[50];
440 char buf[50];
441 int n;
442 int fd;
443 char *ep;
444 sprintf(fname, "/sys/block/%s/md/%s/%s",
7e0f6979 445 sra->sys_name, dev?dev->sys_name:"", name);
e86c9dd6
NB
446 fd = open(fname, O_RDONLY);
447 if (fd < 0)
448 return -1;
449 n = read(fd, buf, sizeof(buf));
450 close(fd);
451 if (n <= 0)
452 return -1;
453 buf[n] = 0;
454 *val = strtoull(buf, &ep, 0);
455 if (ep == buf || (*ep != 0 && *ep != '\n' && *ep != ' '))
456 return -1;
457 return 0;
458}
2503d23b 459
8ed3e5e1
DW
460int sysfs_set_safemode(struct mdinfo *sra, unsigned long ms)
461{
462 unsigned long sec;
463 unsigned long msec;
464 char delay[30];
465
466 sec = ms / 1000;
0dd3ba30 467 msec = ms % 1000;
8ed3e5e1 468
0dd3ba30
DW
469 sprintf(delay, "%ld.%03ld\n", sec, msec);
470 /* this '\n' ^ needed for kernels older than 2.6.28 */
8ed3e5e1
DW
471 return sysfs_set_str(sra, NULL, "safe_mode_delay", delay);
472}
473
f35f2525 474int sysfs_set_array(struct mdinfo *info, int vers)
2503d23b
NB
475{
476 int rv = 0;
f35f2525
N
477 char ver[100];
478
479 ver[0] = 0;
480 if (info->array.major_version == -1 &&
481 info->array.minor_version == -2) {
482 strcat(strcpy(ver, "external:"), info->text_version);
483
484 if ((vers % 100) < 2 ||
485 sysfs_set_str(info, NULL, "metadata_version",
486 ver) < 0) {
487 fprintf(stderr, Name ": This kernel does not "
488 "support external metadata.\n");
489 return 1;
490 }
491 }
2503d23b
NB
492 if (info->array.level < 0)
493 return 0; /* FIXME */
f35f2525 494 rv |= sysfs_set_str(info, NULL, "level",
2503d23b 495 map_num(pers, info->array.level));
f35f2525
N
496 rv |= sysfs_set_num(info, NULL, "raid_disks", info->array.raid_disks);
497 rv |= sysfs_set_num(info, NULL, "chunk_size", info->array.chunk_size);
498 rv |= sysfs_set_num(info, NULL, "layout", info->array.layout);
499 rv |= sysfs_set_num(info, NULL, "component_size", info->component_size/2);
500 if (info->array.level > 0)
501 rv |= sysfs_set_num(info, NULL, "resync_start", info->resync_start);
2503d23b
NB
502 return rv;
503}
504
2318b9f0 505int sysfs_add_disk(struct mdinfo *sra, struct mdinfo *sd)
2503d23b
NB
506{
507 char dv[100];
508 char nm[100];
2503d23b
NB
509 char *dname;
510 int rv;
511
512 sprintf(dv, "%d:%d", sd->disk.major, sd->disk.minor);
513 rv = sysfs_set_str(sra, NULL, "new_dev", dv);
514 if (rv)
515 return rv;
516
517 memset(nm, 0, sizeof(nm));
518 sprintf(dv, "/sys/dev/block/%d:%d", sd->disk.major, sd->disk.minor);
73649188
N
519 rv = readlink(dv, nm, sizeof(nm));
520 if (rv <= 0)
2503d23b 521 return -1;
73649188 522 nm[rv] = '\0';
2503d23b
NB
523 dname = strrchr(nm, '/');
524 if (dname) dname++;
525 strcpy(sd->sys_name, "dev-");
526 strcpy(sd->sys_name+4, dname);
527
73649188 528 rv = sysfs_set_num(sra, sd, "offset", sd->data_offset);
2503d23b
NB
529 rv |= sysfs_set_num(sra, sd, "size", (sd->component_size+1) / 2);
530 if (sra->array.level != LEVEL_CONTAINER) {
531 rv |= sysfs_set_num(sra, sd, "slot", sd->disk.raid_disk);
532// rv |= sysfs_set_str(sra, sd, "state", "in_sync");
533 }
2503d23b
NB
534 return rv;
535}
90c8b707 536
755c99fa 537#if 0
90c8b707
DW
538int sysfs_disk_to_sg(int fd)
539{
540 /* from an open block device, try find and open its corresponding
541 * scsi_generic interface
542 */
543 struct stat st;
544 char path[256];
545 char sg_path[256];
546 char sg_major_minor[8];
547 char *c;
548 DIR *dir;
549 struct dirent *de;
550 int major, minor, rv;
551
552 if (fstat(fd, &st))
553 return -1;
554
555 snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/device",
556 major(st.st_rdev), minor(st.st_rdev));
557
558 dir = opendir(path);
559 if (!dir)
560 return -1;
561
562 de = readdir(dir);
563 while (de) {
564 if (strncmp("scsi_generic:", de->d_name,
565 strlen("scsi_generic:")) == 0)
566 break;
567 de = readdir(dir);
568 }
569 closedir(dir);
570
571 if (!de)
572 return -1;
573
574 snprintf(sg_path, sizeof(sg_path), "%s/%s/dev", path, de->d_name);
575 fd = open(sg_path, O_RDONLY);
576 if (fd < 0)
577 return fd;
578
579 rv = read(fd, sg_major_minor, sizeof(sg_major_minor));
580 close(fd);
581 if (rv < 0)
582 return -1;
583 else
584 sg_major_minor[rv - 1] = '\0';
585
586 c = strchr(sg_major_minor, ':');
587 *c = '\0';
588 c++;
589 major = strtol(sg_major_minor, NULL, 10);
590 minor = strtol(c, NULL, 10);
591 snprintf(path, sizeof(path), "/dev/.tmp.md.%d:%d:%d",
592 (int) getpid(), major, minor);
593 if (mknod(path, S_IFCHR|0600, makedev(major, minor))==0) {
594 fd = open(path, O_RDONLY);
595 unlink(path);
596 return fd;
597 }
598
599 return -1;
600}
755c99fa 601#endif
90c8b707 602
f1665f72
DW
603int sysfs_disk_to_scsi_id(int fd, __u32 *id)
604{
605 /* from an open block device, try to retrieve it scsi_id */
606 struct stat st;
607 char path[256];
608 char *c1, *c2;
609 DIR *dir;
610 struct dirent *de;
611
612 if (fstat(fd, &st))
613 return 1;
614
615 snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/device",
616 major(st.st_rdev), minor(st.st_rdev));
617
618 dir = opendir(path);
619 if (!dir)
620 return 1;
621
622 de = readdir(dir);
623 while (de) {
624 if (strncmp("scsi_disk:", de->d_name,
625 strlen("scsi_disk:")) == 0)
626 break;
627 de = readdir(dir);
628 }
629 closedir(dir);
630
631 if (!de)
632 return 1;
633
634 c1 = strchr(de->d_name, ':');
635 c1++;
636 c2 = strchr(c1, ':');
637 *c2 = '\0';
638 *id = strtol(c1, NULL, 10) << 24; /* host */
639 c1 = c2 + 1;
640 c2 = strchr(c1, ':');
641 *c2 = '\0';
642 *id |= strtol(c1, NULL, 10) << 16; /* channel */
643 c1 = c2 + 1;
644 c2 = strchr(c1, ':');
645 *c2 = '\0';
646 *id |= strtol(c1, NULL, 10) << 8; /* lun */
647 c1 = c2 + 1;
648 *id |= strtol(c1, NULL, 10); /* id */
649
650 return 0;
651}
f94d52f4
NB
652
653
654int sysfs_unique_holder(int devnum, long rdev)
655{
656 /* Check that devnum is a holder of rdev,
657 * and is the only holder.
658 * we should be locked against races by
659 * an O_EXCL on devnum
660 */
661 DIR *dir;
662 struct dirent *de;
663 char dirname[100];
664 char l;
665 int found = 0;
666 sprintf(dirname, "/sys/dev/block/%d:%d/holders",
667 major(rdev), minor(rdev));
668 dir = opendir(dirname);
669 errno = ENOENT;
670 if (!dir)
671 return 0;
672 l = strlen(dirname);
673 while ((de = readdir(dir)) != NULL) {
674 char buf[10];
675 int n;
676 int mj, mn;
677 char c;
678 int fd;
679
680 if (de->d_ino == 0)
681 continue;
682 if (de->d_name[0] == '.')
683 continue;
684 strcpy(dirname+l, "/");
685 strcat(dirname+l, de->d_name);
686 strcat(dirname+l, "/dev");
687 fd = open(dirname, O_RDONLY);
688 if (fd < 0) {
689 errno = ENOENT;
690 break;
691 }
692 n = read(fd, buf, sizeof(buf)-1);
693 close(fd);
694 buf[n] = 0;
695 if (sscanf(buf, "%d:%d%c", &mj, &mn, &c) != 3 ||
696 c != '\n') {
697 errno = ENOENT;
698 break;
699 }
700 if (mj != MD_MAJOR)
701 mn = -1-(mn>>6);
702
703 if (devnum != mn) {
704 errno = EEXIST;
705 break;
706 }
707 found = 1;
708 }
709 closedir(dir);
710 if (de)
711 return 0;
712 else
713 return found;
714}