feature_tests.h: always use largefile interfaces
[unleashed.git] / usr / src / lib / libdevinfo / devfsmap.c
blob375027a3f559d0f6c551cb09f57fe17632c89be1
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
25 #include <stdio.h>
26 #include <ctype.h>
27 #include <stdlib.h>
28 #include <sys/types.h>
29 #include <strings.h>
30 #include <stdarg.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 #include <errno.h>
34 #include <unistd.h>
35 #include <stropts.h>
36 #include <time.h>
37 #include <sys/param.h>
38 #include <sys/vfstab.h>
39 #include <dirent.h>
40 #include "libdevinfo.h"
41 #include "device_info.h"
42 #include <regex.h>
44 #define isnewline(ch) ((ch) == '\n' || (ch) == '\r' || (ch) == '\f')
45 #define isnamechar(ch) (isalpha(ch) || isdigit(ch) || (ch) == '_' ||\
46 (ch) == '-')
47 #define MAX_TOKEN_SIZE 1024
48 #define BUFSIZE 1024
49 #define STRVAL(s) ((s) ? (s) : "NULL")
51 #define SCSI_VHCI_CONF "/kernel/drv/scsi_vhci.conf"
52 #define QLC_CONF "/kernel/drv/qlc.conf"
53 #define FP_CONF "/kernel/drv/fp.conf"
54 #define DRIVER_CLASSES "/etc/driver_classes"
55 #define FP_AT "fp@"
56 #define VHCI_CTL_NODE "/devices/scsi_vhci:devctl"
57 #define SLASH_DEVICES "/devices"
58 #define SLASH_DEVICES_SLASH "/devices/"
59 #define SLASH_FP_AT "/fp@"
60 #define SLASH_SCSI_VHCI "/scsi_vhci"
61 #define META_DEV "/dev/md/dsk/"
62 #define SLASH_DEV_SLASH "/dev/"
65 * Macros to produce a quoted string containing the value of a
66 * preprocessor macro. For example, if SIZE is defined to be 256,
67 * VAL2STR(SIZE) is "256". This is used to construct format
68 * strings for scanf-family functions below.
70 #define QUOTE(x) #x
71 #define VAL2STR(x) QUOTE(x)
73 typedef enum {
74 CLIENT_TYPE_UNKNOWN,
75 CLIENT_TYPE_PHCI,
76 CLIENT_TYPE_VHCI
77 } client_type_t;
79 typedef enum {
80 T_EQUALS,
81 T_AMPERSAND,
82 T_BIT_OR,
83 T_STAR,
84 T_POUND,
85 T_COLON,
86 T_SEMICOLON,
87 T_COMMA,
88 T_SLASH,
89 T_WHITE_SPACE,
90 T_NEWLINE,
91 T_EOF,
92 T_STRING,
93 T_HEXVAL,
94 T_DECVAL,
95 T_NAME
96 } token_t;
98 typedef enum {
99 begin, parent, drvname, drvclass, prop,
100 parent_equals, name_equals, drvclass_equals,
101 parent_equals_string, name_equals_string,
102 drvclass_equals_string,
103 prop_equals, prop_equals_string, prop_equals_integer,
104 prop_equals_string_comma, prop_equals_integer_comma
105 } conf_state_t;
107 /* structure to hold entries with mpxio-disable property in driver.conf file */
108 struct conf_entry {
109 char *name;
110 char *parent;
111 char *class;
112 char *unit_address;
113 int port;
114 int mpxio_disable;
115 struct conf_entry *next;
118 struct conf_file {
119 char *filename;
120 FILE *fp;
121 int linenum;
124 static char *tok_err = "Unexpected token '%s'\n";
127 /* #define DEBUG */
129 #ifdef DEBUG
131 int devfsmap_debug = 0;
132 /* /var/run is not mounted at install time. Therefore use /tmp */
133 char *devfsmap_logfile = "/tmp/devfsmap.log";
134 static FILE *logfp;
135 #define logdmsg(args) log_debug_msg args
136 static void vlog_debug_msg(char *, va_list);
137 static void log_debug_msg(char *, ...);
138 #ifdef __sparc
139 static void log_confent_list(char *, struct conf_entry *, int);
140 static void log_pathlist(char **);
141 #endif /* __sparc */
143 #else /* DEBUG */
144 #define logdmsg(args) /* nothing */
145 #endif /* DEBUG */
149 * Leave NEWLINE as the next character.
151 static void
152 find_eol(FILE *fp)
154 int ch;
156 while ((ch = getc(fp)) != EOF) {
157 if (isnewline(ch)) {
158 (void) ungetc(ch, fp);
159 break;
164 /* ignore parsing errors */
165 /*ARGSUSED*/
166 static void
167 file_err(struct conf_file *filep, char *fmt, ...)
169 #ifdef DEBUG
170 va_list ap;
172 va_start(ap, fmt);
173 log_debug_msg("WARNING: %s line # %d: ",
174 filep->filename, filep->linenum);
175 vlog_debug_msg(fmt, ap);
176 va_end(ap);
177 #endif /* DEBUG */
180 /* return the next token from the given driver.conf file, or -1 on error */
181 static token_t
182 lex(struct conf_file *filep, char *val, size_t size)
184 char *cp;
185 int ch, oval, badquote;
186 size_t remain;
187 token_t token;
188 FILE *fp = filep->fp;
190 if (size < 2)
191 return (-1);
193 cp = val;
194 while ((ch = getc(fp)) == ' ' || ch == '\t')
197 remain = size - 1;
198 *cp++ = (char)ch;
199 switch (ch) {
200 case '=':
201 token = T_EQUALS;
202 break;
203 case '&':
204 token = T_AMPERSAND;
205 break;
206 case '|':
207 token = T_BIT_OR;
208 break;
209 case '*':
210 token = T_STAR;
211 break;
212 case '#':
213 token = T_POUND;
214 break;
215 case ':':
216 token = T_COLON;
217 break;
218 case ';':
219 token = T_SEMICOLON;
220 break;
221 case ',':
222 token = T_COMMA;
223 break;
224 case '/':
225 token = T_SLASH;
226 break;
227 case ' ':
228 case '\t':
229 case '\f':
230 while ((ch = getc(fp)) == ' ' ||
231 ch == '\t' || ch == '\f') {
232 if (--remain == 0) {
233 *cp = '\0';
234 return (-1);
236 *cp++ = (char)ch;
238 (void) ungetc(ch, fp);
239 token = T_WHITE_SPACE;
240 break;
241 case '\n':
242 case '\r':
243 token = T_NEWLINE;
244 break;
245 case '"':
246 remain++;
247 cp--;
248 badquote = 0;
249 while (!badquote && (ch = getc(fp)) != '"') {
250 switch (ch) {
251 case '\n':
252 case EOF:
253 file_err(filep, "Missing \"\n");
254 remain = size - 1;
255 cp = val;
256 *cp++ = '\n';
257 badquote = 1;
258 /* since we consumed the newline/EOF */
259 (void) ungetc(ch, fp);
260 break;
262 case '\\':
263 if (--remain == 0) {
264 *cp = '\0';
265 return (-1);
267 ch = (char)getc(fp);
268 if (!isdigit(ch)) {
269 /* escape the character */
270 *cp++ = (char)ch;
271 break;
273 oval = 0;
274 while (ch >= '0' && ch <= '7') {
275 ch -= '0';
276 oval = (oval << 3) + ch;
277 ch = (char)getc(fp);
279 (void) ungetc(ch, fp);
280 /* check for character overflow? */
281 if (oval > 127) {
282 file_err(filep,
283 "Character "
284 "overflow detected.\n");
286 *cp++ = (char)oval;
287 break;
288 default:
289 if (--remain == 0) {
290 *cp = '\0';
291 return (-1);
293 *cp++ = (char)ch;
294 break;
297 token = T_STRING;
298 break;
300 case EOF:
301 token = T_EOF;
302 break;
304 default:
306 * detect a lone '-' (including at the end of a line), and
307 * identify it as a 'name'
309 if (ch == '-') {
310 if (--remain == 0) {
311 *cp = '\0';
312 return (-1);
314 *cp++ = (char)(ch = getc(fp));
315 if (ch == ' ' || ch == '\t' || ch == '\n') {
316 (void) ungetc(ch, fp);
317 remain++;
318 cp--;
319 token = T_NAME;
320 break;
322 } else if (ch == '~' || ch == '-') {
323 if (--remain == 0) {
324 *cp = '\0';
325 return (-1);
327 *cp++ = (char)(ch = getc(fp));
331 if (isdigit(ch)) {
332 if (ch == '0') {
333 if ((ch = getc(fp)) == 'x') {
334 if (--remain == 0) {
335 *cp = '\0';
336 return (-1);
338 *cp++ = (char)ch;
339 ch = getc(fp);
340 while (isxdigit(ch)) {
341 if (--remain == 0) {
342 *cp = '\0';
343 return (-1);
345 *cp++ = (char)ch;
346 ch = getc(fp);
348 (void) ungetc(ch, fp);
349 token = T_HEXVAL;
350 } else {
351 goto digit;
353 } else {
354 ch = getc(fp);
355 digit:
356 while (isdigit(ch)) {
357 if (--remain == 0) {
358 *cp = '\0';
359 return (-1);
361 *cp++ = (char)ch;
362 ch = getc(fp);
364 (void) ungetc(ch, fp);
365 token = T_DECVAL;
367 } else if (isalpha(ch) || ch == '\\') {
368 if (ch != '\\') {
369 ch = getc(fp);
370 } else {
372 * if the character was a backslash,
373 * back up so we can overwrite it with
374 * the next (i.e. escaped) character.
376 remain++;
377 cp--;
379 while (isnamechar(ch) || ch == '\\') {
380 if (ch == '\\')
381 ch = getc(fp);
382 if (--remain == 0) {
383 *cp = '\0';
384 return (-1);
386 *cp++ = (char)ch;
387 ch = getc(fp);
389 (void) ungetc(ch, fp);
390 token = T_NAME;
391 } else {
392 return (-1);
394 break;
397 *cp = '\0';
399 return (token);
403 static int
404 devlink_callback(di_devlink_t devlink, void *argp)
406 const char *link;
408 if ((link = di_devlink_path(devlink)) != NULL)
409 (void) strlcpy((char *)argp, link, MAXPATHLEN);
411 return (DI_WALK_CONTINUE);
415 * Get the /dev name in the install environment corresponding to physpath.
417 * physpath /devices path in the install environment without the /devices
418 * prefix.
419 * buf caller supplied buffer where the /dev name is placed on return
420 * bufsz length of the buffer
422 * Returns strlen of the /dev name on success, -1 on failure.
424 static int
425 get_install_devlink(char *physpath, char *buf, size_t bufsz)
427 di_devlink_handle_t devlink_hdl;
428 char devname[MAXPATHLEN];
429 int tries = 0;
430 int sleeptime = 2; /* number of seconds to sleep between retries */
431 int maxtries = 10; /* maximum number of tries */
433 logdmsg(("get_install_devlink: physpath = %s\n", physpath));
436 * devlink_db sync happens after MINOR_FINI_TIMEOUT_DEFAULT secs
437 * after dev link creation. So wait for minimum that amout of time.
440 retry:
441 (void) sleep(sleeptime);
443 if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
444 logdmsg(("get_install_devlink: di_devlink_init() failed: %s\n",
445 strerror(errno)));
446 return (-1);
449 devname[0] = '\0';
450 if (di_devlink_walk(devlink_hdl, NULL, physpath, DI_PRIMARY_LINK,
451 devname, devlink_callback) == 0) {
452 if (devname[0] == '\0' && tries < maxtries) {
453 tries++;
454 (void) di_devlink_fini(&devlink_hdl);
455 goto retry;
456 } else if (devname[0] == '\0') {
457 logdmsg(("get_install_devlink: di_devlink_walk"
458 " failed: %s\n", strerror(errno)));
459 (void) di_devlink_fini(&devlink_hdl);
460 return (-1);
462 } else {
463 logdmsg(("get_install_devlink: di_devlink_walk failed: %s\n",
464 strerror(errno)));
465 (void) di_devlink_fini(&devlink_hdl);
466 return (-1);
469 (void) di_devlink_fini(&devlink_hdl);
471 logdmsg(("get_install_devlink: devlink = %s\n", devname));
472 return (strlcpy(buf, devname, bufsz));
476 * Get the /dev name in the target environment corresponding to physpath.
478 * rootdir root directory of the target environment
479 * physpath /devices path in the target environment without the /devices
480 * prefix.
481 * buf caller supplied buffer where the /dev name is placed on return
482 * bufsz length of the buffer
484 * Returns strlen of the /dev name on success, -1 on failure.
486 static int
487 get_target_devlink(char *rootdir, char *physpath, char *buf, size_t bufsz)
489 char *p;
490 int linksize;
491 DIR *dirp;
492 struct dirent *direntry;
493 char dirpath[MAXPATHLEN];
494 char devname[MAXPATHLEN];
495 char physdev[MAXPATHLEN];
497 logdmsg(("get_target_devlink: rootdir = %s, physpath = %s\n",
498 rootdir, physpath));
500 if ((p = strrchr(physpath, '/')) == NULL)
501 return (-1);
503 if (strstr(p, ",raw") != NULL) {
504 (void) snprintf(dirpath, MAXPATHLEN, "%s/dev/rdsk", rootdir);
505 } else {
506 (void) snprintf(dirpath, MAXPATHLEN, "%s/dev/dsk", rootdir);
509 if ((dirp = opendir(dirpath)) == NULL)
510 return (-1);
512 while ((direntry = readdir(dirp)) != NULL) {
513 if (strcmp(direntry->d_name, ".") == 0 ||
514 strcmp(direntry->d_name, "..") == 0)
515 continue;
517 (void) snprintf(devname, MAXPATHLEN, "%s/%s",
518 dirpath, direntry->d_name);
520 if ((linksize = readlink(devname, physdev, MAXPATHLEN)) > 0 &&
521 linksize < (MAXPATHLEN - 1)) {
522 physdev[linksize] = '\0';
523 if ((p = strstr(physdev, SLASH_DEVICES_SLASH)) !=
524 NULL && strcmp(p + sizeof (SLASH_DEVICES) - 1,
525 physpath) == 0) {
526 (void) closedir(dirp);
527 logdmsg(("get_target_devlink: devlink = %s\n",
528 devname + strlen(rootdir)));
529 return (strlcpy(buf, devname + strlen(rootdir),
530 bufsz));
535 (void) closedir(dirp);
536 return (-1);
540 * Convert device name to physpath.
542 * rootdir root directory
543 * devname a /dev name or /devices name under rootdir
544 * physpath caller supplied buffer where the /devices path will be placed
545 * on return (without the /devices prefix).
546 * physpathlen length of the physpath buffer
548 * Returns 0 on success, -1 on failure.
550 static int
551 devname2physpath(char *rootdir, char *devname, char *physpath, int physpathlen)
553 int linksize;
554 char *p;
555 char devlink[MAXPATHLEN];
556 char tmpphyspath[MAXPATHLEN];
558 logdmsg(("devname2physpath: rootdir = %s, devname = %s\n",
559 rootdir, devname));
561 if (strncmp(devname, SLASH_DEVICES_SLASH,
562 sizeof (SLASH_DEVICES_SLASH) - 1) != 0) {
563 if (*rootdir == '\0')
564 linksize = readlink(devname, tmpphyspath, MAXPATHLEN);
565 else {
566 (void) snprintf(devlink, MAXPATHLEN, "%s%s",
567 rootdir, devname);
568 linksize = readlink(devlink, tmpphyspath, MAXPATHLEN);
570 if (linksize > 0 && linksize < (MAXPATHLEN - 1)) {
571 tmpphyspath[linksize] = '\0';
572 if ((p = strstr(tmpphyspath, SLASH_DEVICES_SLASH))
573 == NULL)
574 return (-1);
575 } else
576 return (-1);
577 } else
578 p = devname;
580 (void) strlcpy(physpath, p + sizeof (SLASH_DEVICES) - 1, physpathlen);
581 logdmsg(("devname2physpath: physpath = %s\n", physpath));
582 return (0);
586 * Map a device name (devname) from the target environment to the
587 * install environment.
589 * rootdir root directory of the target environment
590 * devname /dev or /devices name under the target environment
591 * buf caller supplied buffer where the mapped /dev name is placed
592 * on return
593 * bufsz length of the buffer
595 * Returns strlen of the mapped /dev name on success, -1 on failure.
598 devfs_target2install(const char *rootdir, const char *devname, char *buf,
599 size_t bufsz)
601 char physpath[MAXPATHLEN];
603 logdmsg(("devfs_target2install: rootdir = %s, devname = %s\n",
604 STRVAL(rootdir), STRVAL(devname)));
606 if (rootdir == NULL || devname == NULL || buf == NULL || bufsz == 0)
607 return (-1);
609 if (strcmp(rootdir, "/") == 0)
610 rootdir = "";
612 if (devname2physpath((char *)rootdir, (char *)devname, physpath,
613 MAXPATHLEN) != 0)
614 return (-1);
617 return (get_install_devlink(physpath, buf, bufsz));
621 * Map a device name (devname) from the install environment to the target
622 * environment.
624 * rootdir root directory of the target environment
625 * devname /dev or /devices name under the install environment
626 * buf caller supplied buffer where the mapped /dev name is placed
627 * on return
628 * bufsz length of the buffer
630 * Returns strlen of the mapped /dev name on success, -1 on failure.
633 devfs_install2target(const char *rootdir, const char *devname, char *buf,
634 size_t bufsz)
636 char physpath[MAXPATHLEN];
638 logdmsg(("devfs_install2target: rootdir = %s, devname = %s\n",
639 STRVAL(rootdir), STRVAL(devname)));
641 if (rootdir == NULL || devname == NULL || buf == NULL || bufsz == 0)
642 return (-1);
644 if (strcmp(rootdir, "/") == 0)
645 rootdir = "";
647 if (devname2physpath("", (char *)devname, physpath, MAXPATHLEN) != 0)
648 return (-1);
651 return (get_target_devlink((char *)rootdir, physpath, buf, bufsz));
655 * A parser for /etc/path_to_inst.
656 * The user-supplied callback is called once for each entry in the file.
657 * Returns 0 on success, ENOMEM/ENOENT/EINVAL on error.
658 * Callback may return DI_WALK_TERMINATE to terminate the walk,
659 * otherwise DI_WALK_CONTINUE.
662 devfs_parse_binding_file(const char *binding_file,
663 int (*callback)(void *, const char *, int,
664 const char *), void *cb_arg)
666 token_t token;
667 struct conf_file file;
668 char tokval[MAX_TOKEN_SIZE];
669 enum { STATE_RESET, STATE_DEVPATH, STATE_INSTVAL } state;
670 char *devpath;
671 char *bindname;
672 int instval = 0;
673 int rv;
675 if ((devpath = calloc(1, MAXPATHLEN)) == NULL)
676 return (ENOMEM);
677 if ((bindname = calloc(1, MAX_TOKEN_SIZE)) == NULL) {
678 free(devpath);
679 return (ENOMEM);
682 if ((file.fp = fopen(binding_file, "r")) == NULL) {
683 free(devpath);
684 free(bindname);
685 return (errno);
688 file.filename = (char *)binding_file;
689 file.linenum = 1;
691 state = STATE_RESET;
692 while ((token = lex(&file, tokval, MAX_TOKEN_SIZE)) != T_EOF) {
693 switch (token) {
694 case T_POUND:
696 * Skip comments.
698 find_eol(file.fp);
699 break;
700 case T_NAME:
701 case T_STRING:
702 switch (state) {
703 case STATE_RESET:
704 if (strlcpy(devpath, tokval,
705 MAXPATHLEN) >= MAXPATHLEN)
706 goto err;
707 state = STATE_DEVPATH;
708 break;
709 case STATE_INSTVAL:
710 if (strlcpy(bindname, tokval,
711 MAX_TOKEN_SIZE) >= MAX_TOKEN_SIZE)
712 goto err;
713 rv = callback(cb_arg,
714 devpath, instval, bindname);
715 if (rv == DI_WALK_TERMINATE)
716 goto done;
717 if (rv != DI_WALK_CONTINUE)
718 goto err;
719 state = STATE_RESET;
720 break;
721 default:
722 file_err(&file, tok_err, tokval);
723 state = STATE_RESET;
724 break;
726 break;
727 case T_DECVAL:
728 case T_HEXVAL:
729 switch (state) {
730 case STATE_DEVPATH:
731 instval = (int)strtol(tokval, NULL, 0);
732 state = STATE_INSTVAL;
733 break;
734 default:
735 file_err(&file, tok_err, tokval);
736 state = STATE_RESET;
737 break;
739 break;
740 case T_NEWLINE:
741 file.linenum++;
742 state = STATE_RESET;
743 break;
744 default:
745 file_err(&file, tok_err, tokval);
746 state = STATE_RESET;
747 break;
751 done:
752 (void) fclose(file.fp);
753 free(devpath);
754 free(bindname);
755 return (0);
757 err:
758 (void) fclose(file.fp);
759 free(devpath);
760 free(bindname);
761 return (EINVAL);
765 * Walk the minor nodes of all children below the specified device
766 * by calling the provided callback with the path to each minor.
768 static int
769 devfs_walk_children_minors(const char *device_path, struct stat *st,
770 int (*callback)(void *, const char *), void *cb_arg, int *terminate)
772 DIR *dir;
773 struct dirent *dp;
774 char *minor_path = NULL;
775 int need_close = 0;
776 int rv;
778 if ((minor_path = calloc(1, MAXPATHLEN)) == NULL)
779 return (ENOMEM);
781 if ((dir = opendir(device_path)) == NULL) {
782 rv = ENOENT;
783 goto err;
785 need_close = 1;
787 while ((dp = readdir(dir)) != NULL) {
788 if ((strcmp(dp->d_name, ".") == 0) ||
789 (strcmp(dp->d_name, "..") == 0))
790 continue;
791 (void) snprintf(minor_path, MAXPATHLEN,
792 "%s/%s", device_path, dp->d_name);
793 if (stat(minor_path, st) == -1)
794 continue;
795 if (S_ISDIR(st->st_mode)) {
796 rv = devfs_walk_children_minors(
797 (const char *)minor_path, st,
798 callback, cb_arg, terminate);
799 if (rv != 0)
800 goto err;
801 if (*terminate)
802 break;
803 } else {
804 rv = callback(cb_arg, minor_path);
805 if (rv == DI_WALK_TERMINATE) {
806 *terminate = 1;
807 break;
809 if (rv != DI_WALK_CONTINUE) {
810 rv = EINVAL;
811 goto err;
816 rv = 0;
817 err:
818 if (need_close)
819 (void) closedir(dir);
820 free(minor_path);
821 return (rv);
825 * Return the path to each minor node for a device by
826 * calling the provided callback.
828 static int
829 devfs_walk_device_minors(const char *device_path, struct stat *st,
830 int (*callback)(void *, const char *), void *cb_arg, int *terminate)
832 char *minor_path;
833 char *devpath;
834 char *expr;
835 regex_t regex;
836 int need_regfree = 0;
837 int need_close = 0;
838 DIR *dir;
839 struct dirent *dp;
840 int rv;
841 char *p;
843 minor_path = calloc(1, MAXPATHLEN);
844 devpath = calloc(1, MAXPATHLEN);
845 expr = calloc(1, MAXNAMELEN);
846 if (devpath == NULL || expr == NULL || minor_path == NULL) {
847 rv = ENOMEM;
848 goto err;
851 rv = EINVAL;
852 if (strlcpy(devpath, device_path, MAXPATHLEN) >= MAXPATHLEN)
853 goto err;
854 if ((p = strrchr(devpath, '/')) == NULL)
855 goto err;
856 *p++ = 0;
857 if (strlen(p) == 0)
858 goto err;
859 if (snprintf(expr, MAXNAMELEN, "%s:.*", p) >= MAXNAMELEN)
860 goto err;
861 if (regcomp(&regex, expr, REG_EXTENDED) != 0)
862 goto err;
863 need_regfree = 1;
865 if ((dir = opendir(devpath)) == NULL) {
866 rv = ENOENT;
867 goto err;
869 need_close = 1;
871 while ((dp = readdir(dir)) != NULL) {
872 if ((strcmp(dp->d_name, ".") == 0) ||
873 (strcmp(dp->d_name, "..") == 0))
874 continue;
875 (void) snprintf(minor_path, MAXPATHLEN,
876 "%s/%s", devpath, dp->d_name);
877 if (stat(minor_path, st) == -1)
878 continue;
879 if ((S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode)) &&
880 regexec(&regex, dp->d_name, 0, NULL, 0) == 0) {
881 rv = callback(cb_arg, minor_path);
882 if (rv == DI_WALK_TERMINATE) {
883 *terminate = 1;
884 break;
886 if (rv != DI_WALK_CONTINUE) {
887 rv = EINVAL;
888 goto err;
893 rv = 0;
894 err:
895 if (need_close)
896 (void) closedir(dir);
897 if (need_regfree)
898 regfree(&regex);
899 free(devpath);
900 free(minor_path);
901 free(expr);
902 return (rv);
906 * Perform a walk of all minor nodes for the specified device,
907 * and minor nodes below the device.
910 devfs_walk_minor_nodes(const char *device_path,
911 int (*callback)(void *, const char *), void *cb_arg)
913 struct stat stbuf;
914 int rv;
915 int terminate = 0;
917 rv = devfs_walk_device_minors(device_path,
918 &stbuf, callback, cb_arg, &terminate);
919 if (rv == 0 && terminate == 0) {
920 rv = devfs_walk_children_minors(device_path,
921 &stbuf, callback, cb_arg, &terminate);
923 return (rv);
926 #ifdef DEBUG
928 static void
929 vlog_debug_msg(char *fmt, va_list ap)
931 time_t clock;
932 struct tm t;
934 if (!devfsmap_debug)
935 return;
937 if (logfp == NULL) {
938 if (*devfsmap_logfile != '\0') {
939 logfp = fopen(devfsmap_logfile, "a");
940 if (logfp)
941 (void) fprintf(logfp, "\nNew Log:\n");
944 if (logfp == NULL)
945 logfp = stdout;
948 clock = time(NULL);
949 (void) localtime_r(&clock, &t);
950 (void) fprintf(logfp, "%02d:%02d:%02d ", t.tm_hour, t.tm_min,
951 t.tm_sec);
952 (void) vfprintf(logfp, fmt, ap);
953 (void) fflush(logfp);
956 static void
957 log_debug_msg(char *fmt, ...)
959 va_list ap;
961 va_start(ap, fmt);
962 vlog_debug_msg(fmt, ap);
963 va_end(ap);
966 #ifdef __sparc
968 static char *
969 mpxio_disable_string(int mpxio_disable)
971 if (mpxio_disable == 0)
972 return ("no");
973 else if (mpxio_disable == 1)
974 return ("yes");
975 else
976 return ("not specified");
979 static void
980 log_confent_list(char *filename, struct conf_entry *confent_list,
981 int global_mpxio_disable)
983 struct conf_entry *confent;
985 log_debug_msg("log_confent_list: filename = %s:\n", filename);
986 if (global_mpxio_disable != -1)
987 log_debug_msg("\tdriver global mpxio_disable = \"%s\"\n\n",
988 mpxio_disable_string(global_mpxio_disable));
990 for (confent = confent_list; confent != NULL; confent = confent->next) {
991 if (confent->name)
992 log_debug_msg("\tname = %s\n", confent->name);
993 if (confent->parent)
994 log_debug_msg("\tparent = %s\n", confent->parent);
995 if (confent->class)
996 log_debug_msg("\tclass = %s\n", confent->class);
997 if (confent->unit_address)
998 log_debug_msg("\tunit_address = %s\n",
999 confent->unit_address);
1000 if (confent->port != -1)
1001 log_debug_msg("\tport = %d\n", confent->port);
1002 log_debug_msg("\tmpxio_disable = \"%s\"\n\n",
1003 mpxio_disable_string(confent->mpxio_disable));
1007 static void
1008 log_pathlist(char **pathlist)
1010 char **p;
1012 for (p = pathlist; *p != NULL; p++)
1013 log_debug_msg("\t%s\n", *p);
1016 #endif /* __sparc */
1018 #endif /* DEBUG */