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]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
34 #include <libnvpair.h>
35 #include <libdevinfo.h>
37 #include <sys/param.h>
40 #include <sys/systeminfo.h>
41 #include <sys/modctl.h>
42 #include <sys/fs/sdev_node.h>
50 * This is for local file supports of DBNR configurations.
52 static int di_devname_getmapent_files(char *, char *, nvlist_t
**);
53 static int di_devname_get_mapinfo_files(char *, nvlist_t
**);
54 static int parse_mapinfo_file(FILE *, nvlist_t
**);
55 static FILE *open_local_map(char *);
56 static void unquote(char *, char *);
58 static int msglog
= 1;
65 static int devname_debug
= 1;
66 static void dprintf(debug_level_t
, const char *, ...);
68 extern int isspace(int);
70 /* exported interfaces */
71 void di_devname_print_mapinfo(nvlist_t
*);
72 int di_devname_get_mapinfo(char *, nvlist_t
**);
73 int di_devname_get_mapent(char *, char *, nvlist_t
**);
74 int di_devname_action_on_key(nvlist_t
*, uint8_t, char *, void *);
77 * Returns 0 and the valid maplist, otherwise errno.
80 di_devname_get_mapinfo_files(char *mapname
, nvlist_t
**maplist
)
86 fp
= open_local_map(mapname
);
88 dprintf(DBG_INFO
, "di_devname_get_mapinfo_files: file %s does"
89 "not exist\n", mapname
);
93 rval
= parse_mapinfo_file(fp
, &nvl
);
103 open_local_map(char *mapname
)
105 char filename
[LINEMAX
];
107 if (*mapname
!= '/') {
108 (void) snprintf(filename
, sizeof (filename
), "/etc/dev/%s",
111 (void) snprintf(filename
, sizeof (filename
), "%s", mapname
);
114 return (fopen(filename
, "r"));
118 unquote(char *str
, char *qbuf
)
120 register int escaped
, inquote
, quoted
;
121 register char *ip
, *bp
, *qp
;
124 escaped
= inquote
= quoted
= 0;
126 for (ip
= str
, bp
= buf
, qp
= qbuf
; *ip
; ip
++) {
132 } else if (*ip
== '"') {
140 *qp
++ = (inquote
|| escaped
) ? '^' : ' ';
146 (void) strcpy(str
, buf
);
150 * gets the qualified characters in *p into w, which has space allocated
154 getword(char *w
, char *wq
, char **p
, char **pq
, char delim
, int wordsz
)
164 while ((delim
== ' ' ? isspace(**p
) : **p
== delim
) && **pq
== ' ') {
170 !((delim
== ' ' ? isspace(**p
) : **p
== delim
) &&
175 dprintf(DBG_INFO
, "maximum word length %d exceeded\n",
188 parse_mapinfo_file(FILE *fp
, nvlist_t
**ret_nvlp
)
191 nvlist_t
*nvl
= NULL
, *attrs
= NULL
;
192 char line
[LINEMAX
], lineq
[LINEMAX
];
193 char word
[MAXPATHLEN
+1], wordq
[MAXPATHLEN
+1];
196 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0) != 0) {
200 while (fgets(line
, sizeof (line
), fp
)) {
201 char *name
, *key
, *val
;
206 if ((getword(word
, wordq
, &lp
, &lq
, ' ',
207 sizeof (word
)) == -1) || (word
[0] == '\0'))
213 name
= strtok(line
, SPC
);
217 (void) dprintf(DBG_INFO
, "get a line for %s\n", name
);
218 key
= strtok(NULL
, "=");
220 (void) dprintf(DBG_INFO
, "no attributes specified for "
226 if (nvlist_alloc(&attrs
, NV_UNIQUE_NAME
, 0) != 0) {
231 while (key
&& *key
) {
233 rest
= strtok(NULL
, "\n");
235 (void) dprintf(DBG_INFO
, "no value for key "
239 if (rest
[0] == ';') {
240 val
= strdup("devname_null");
243 val
= strtok(rest
, ";");
244 rest
= strtok(NULL
, "");
246 (void) dprintf(DBG_INFO
, "parse_map_info: one entry "
247 "key=%s val=%s\n", key
, val
);
248 if (nvlist_add_string(attrs
, key
, val
) != 0) {
253 key
= strtok(rest
, "=");
255 (void) dprintf(DBG_INFO
, "parse_map_info: add entry name=%s\n",
257 if (nvlist_add_nvlist(nvl
, name
, attrs
) != 0) {
275 di_devname_print_mapinfo(nvlist_t
*nvl
)
277 char *name
, *key
, *val
;
281 nvp
= nvlist_next_nvpair(nvl
, NULL
);
283 name
= nvpair_name(nvp
);
284 (void) nvpair_value_nvlist(nvp
, &attrs
);
285 (void) printf("name = %s, binding attributes:\n", name
);
286 kvp
= nvlist_next_nvpair(attrs
, NULL
);
288 key
= nvpair_name(kvp
);
289 (void) nvpair_value_string(kvp
, &val
);
290 (void) printf("\t%s = %s\n", key
, val
);
291 kvp
= nvlist_next_nvpair(attrs
, kvp
);
293 nvp
= nvlist_next_nvpair(nvl
, nvp
);
298 action_mklink(char *target
, char *source
)
300 (void) dprintf(DBG_INFO
, "mklink for source %s target %s\n",
302 return (symlink(source
, target
));
305 static struct actions
{
308 int (*action
)(char *, char *);
310 {"devices-path", DEVNAME_NS_PATH
, action_mklink
},
311 {"dev-path", DEVNAME_NS_DEV
, action_mklink
},
312 {NULL
, DEVNAME_NS_NONE
, NULL
}
316 action_on_key(uint_t cmd
, char *dir_name
, char *devname
, nvpair_t
*attr
,
317 uint32_t *nsmapcount
, char **devfsadm_link
, devname_spec_t
*devfsadm_spec
)
321 char *attrname
, *attrval
;
325 attrname
= nvpair_name(attr
);
326 (void) nvpair_value_string(attr
, &attrval
);
327 (void) dprintf(DBG_INFO
, "key = %s; value = %s\n", attrname
, attrval
);
329 while (actions
[i
].key
) {
330 if (strcmp(actions
[i
].key
, attrname
) == 0) {
332 case DEVFSADMD_NS_READDIR
:
333 len
= strlen(dir_name
) + strlen(devname
) + 2;
335 (void) snprintf(path
, len
, "%s/%s", dir_name
,
337 error
= actions
[i
].action(path
, attrval
);
340 (void) dprintf(DBG_INFO
, "action "
341 "failed %d\n", error
);
345 (void) dprintf(DBG_INFO
,
346 "mapcount %d\n", *nsmapcount
);
349 case DEVFSADMD_NS_LOOKUP
:
350 *devfsadm_link
= strdup(attrval
);
351 *devfsadm_spec
= actions
[i
].spec
;
363 di_devname_action_on_key(nvlist_t
*map
, uint8_t cmd
, char *dir_name
, void *hdl
)
369 uint32_t ns_mapcount
= 0;
370 char *devfsadm_link
= NULL
;
371 devname_spec_t devfsadm_spec
= DEVNAME_NS_NONE
;
372 sdev_door_res_t
*resp
;
374 entry
= nvlist_next_nvpair(map
, NULL
);
377 name
= nvpair_name(entry
);
378 (void) dprintf(DBG_INFO
, "di_devname_action_on_key: name %s\n",
380 (void) nvpair_value_nvlist(entry
, &attrs
);
382 attr
= nvlist_next_nvpair(attrs
, NULL
);
384 error
= action_on_key(cmd
, dir_name
, name
, attr
,
385 &ns_mapcount
, &devfsadm_link
, &devfsadm_spec
);
387 /* do not continue if encountered the first error */
389 (void) dprintf(DBG_INFO
, "error %d\n", error
);
390 return ((int32_t)error
);
392 attr
= nvlist_next_nvpair(attrs
, attr
);
394 entry
= nvlist_next_nvpair(map
, entry
);
397 resp
= (sdev_door_res_t
*)hdl
;
398 (void) dprintf(DBG_INFO
, "cmd is %d\n", cmd
);
400 case DEVFSADMD_NS_READDIR
:
401 resp
->ns_rdr_hdl
.ns_mapcount
= (uint32_t)ns_mapcount
;
402 (void) dprintf(DBG_INFO
, "mapcount is %d\n", ns_mapcount
);
404 case DEVFSADMD_NS_LOOKUP
:
405 if (devfsadm_link
&& devfsadm_spec
!= DEVNAME_NS_NONE
) {
406 (void) dprintf(DBG_INFO
, "devfsadm_link is %s\n",
408 (void) snprintf(resp
->ns_lkp_hdl
.devfsadm_link
,
409 strlen(devfsadm_link
) + 1, "%s", devfsadm_link
);
410 resp
->ns_lkp_hdl
.devfsadm_spec
= devfsadm_spec
;
412 (void) dprintf(DBG_INFO
, "error out\n");
417 (void) dprintf(DBG_INFO
, "error NOTSUP out\n");
426 getent_mapinfo_file(FILE *fp
, char *match
)
428 nvlist_t
*nvl
, *attrs
;
429 char line
[LINEMAX
], lineq
[LINEMAX
];
430 char word
[MAXPATHLEN
+1], wordq
[MAXPATHLEN
+1];
434 if (nvlist_alloc(&nvl
, NV_UNIQUE_NAME
, 0) != 0)
437 while (fgets(line
, sizeof (line
), fp
)) {
438 char *name
, *key
, *val
;
443 dprintf(DBG_INFO
, "getent_mapinfo_file: get a line %s\n", line
);
447 if ((getword(word
, wordq
, &lp
, &lq
, ' ', sizeof (word
))
448 == -1) || (word
[0] == '\0'))
451 name
= strtok(line
, SPC
);
455 dprintf(DBG_INFO
, "macthing with the key %s match %s\n",
457 /* bypass the non-related entries */
458 if (strcmp(name
, match
) != 0)
461 /* get a matched entry */
462 key
= strtok(NULL
, "=");
464 (void) dprintf(DBG_INFO
, "no attributes specified "
470 if (nvlist_alloc(&attrs
, NV_UNIQUE_NAME
, 0) != 0)
472 while (key
&& *key
) {
474 rest
= strtok(NULL
, "\n");
476 (void) dprintf(DBG_INFO
, "no value for key "
480 if (rest
[0] == ';') {
481 val
= strdup("devname_null");
484 val
= strtok(rest
, ";");
485 rest
= strtok(NULL
, "");
487 (void) dprintf(DBG_INFO
, "found entry %s %s for %s\n",
489 if (nvlist_add_string(attrs
, key
, val
) != 0)
492 key
= strtok(rest
, "=");
494 (void) dprintf(DBG_INFO
, "adding nvlist for %s\n", name
);
495 if (nvlist_add_nvlist(nvl
, name
, attrs
) != 0)
515 di_devname_getmapent_files(char *key
, char *mapname
, nvlist_t
**map
)
519 nvlist_t
*nvl
= NULL
;
521 fp
= open_local_map(mapname
);
525 nvl
= getent_mapinfo_file(fp
, key
);
537 di_devname_get_mapent(char *key
, char *mapname
, nvlist_t
**map
)
539 dprintf(DBG_INFO
, "di_devname_get_mapent: called for %s in %s\n",
542 return (di_devname_getmapent_files(key
, mapname
, map
));
547 di_devname_get_mapinfo(char *mapname
, nvlist_t
**maps
)
549 dprintf(DBG_INFO
, "di_devname_get_mapinfo: called for %s\n", mapname
);
551 return (di_devname_get_mapinfo_files(mapname
, maps
));
555 debug_print(debug_level_t msglevel
, const char *fmt
, va_list ap
)
557 if (devname_debug
< msglevel
)
560 /* Print a distinctive label for error msgs */
561 if (msglevel
== DBG_ERR
) {
562 (void) fprintf(stderr
, "[ERROR]: ");
565 if (msglog
== TRUE
) {
566 (void) vsyslog(LOG_NOTICE
, fmt
, ap
);
568 (void) vfprintf(stderr
, fmt
, ap
);
575 dprintf(debug_level_t msglevel
, const char *fmt
, ...)
579 assert(msglevel
> 0);
585 debug_print(msglevel
, fmt
, ap
);
591 * Private interfaces for non-global /dev profile
595 * Allocate opaque data structure for passing profile to the kernel for
596 * the given mount point.
598 * Note that this interface returns an empty, initialized, profile.
599 * It does not return what may have been previously committed.
602 di_prof_init(const char *mountpt
, di_prof_t
*profp
)
606 if (nvlist_alloc(&nvl
, 0, 0))
609 if (nvlist_add_string(nvl
, SDEV_NVNAME_MOUNTPT
, mountpt
)) {
614 *profp
= (di_prof_t
)nvl
;
619 * Free space allocated by di_prof_init().
622 di_prof_fini(di_prof_t prof
)
624 nvlist_free((nvlist_t
*)prof
);
628 * Sends profile to the kernel.
631 di_prof_commit(di_prof_t prof
)
637 if (nvlist_pack((nvlist_t
*)prof
, &buf
, &buflen
, NV_ENCODE_NATIVE
, 0))
639 rv
= modctl(MODDEVNAME
, MODDEVNAME_PROFILE
, buf
, buflen
);
645 * Add a device or directory to profile's include list.
647 * Note that there is no arbitration between conflicting
648 * include and exclude profile entries, most recent
652 di_prof_add_dev(di_prof_t prof
, const char *dev
)
654 if (nvlist_add_string((nvlist_t
*)prof
, SDEV_NVNAME_INCLUDE
, dev
))
660 * Add a device or directory to profile's exclude list.
661 * This can effectively remove a previously committed device.
664 di_prof_add_exclude(di_prof_t prof
, const char *dev
)
666 if (nvlist_add_string((nvlist_t
*)prof
, SDEV_NVNAME_EXCLUDE
, dev
))
672 * Add a symlink to profile.
675 di_prof_add_symlink(di_prof_t prof
, const char *linkname
, const char *target
)
677 nvlist_t
*nvl
= (nvlist_t
*)prof
;
680 syml
[0] = (char *)linkname
; /* 1st entry must be the symlink */
681 syml
[1] = (char *)target
; /* 2nd entry must be the target */
682 if (nvlist_add_string_array(nvl
, SDEV_NVNAME_SYMLINK
, syml
, 2))
688 * Add a name mapping to profile.
691 di_prof_add_map(di_prof_t prof
, const char *source
, const char *target
)
693 nvlist_t
*nvl
= (nvlist_t
*)prof
;
696 map
[0] = (char *)source
; /* 1st entry must be the source */
697 map
[1] = (char *)target
; /* 2nd entry must be the target */
698 if (nvlist_add_string_array(nvl
, SDEV_NVNAME_MAP
, map
, 2))