6811333 Remove prom_printf() message in emlxs driver
[opensolaris.git] / usr / src / lib / libdevinfo / devinfo_devname.c
blob379c156627d1a1b4bb1c47e9bde887d35a121886
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 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
28 #include <stdio.h>
29 #include <strings.h>
30 #include <unistd.h>
31 #include <stdarg.h>
32 #include <fcntl.h>
33 #include <stdlib.h>
34 #include <libnvpair.h>
35 #include <libdevinfo.h>
36 #include <syslog.h>
37 #include <sys/param.h>
38 #include <errno.h>
39 #include <assert.h>
40 #include <sys/systeminfo.h>
41 #include <sys/modctl.h>
42 #include <sys/fs/sdev_node.h>
45 #define LINEMAX 1024
46 #define SPC " \t\n"
47 #define QUOTES "\'\""
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;
59 typedef enum {
60 DBG_ERR = 1,
61 DBG_INFO,
62 DBG_STEP,
63 DBG_ALL
64 } debug_level_t;
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.
79 int
80 di_devname_get_mapinfo_files(char *mapname, nvlist_t **maplist)
82 FILE *fp;
83 int rval = 0;
84 nvlist_t *nvl = NULL;
86 fp = open_local_map(mapname);
87 if (fp == NULL) {
88 dprintf(DBG_INFO, "di_devname_get_mapinfo_files: file %s does"
89 "not exist\n", mapname);
90 return (ENOENT);
93 rval = parse_mapinfo_file(fp, &nvl);
94 if (rval == 0) {
95 *maplist = nvl;
97 (void) fclose(fp);
99 return (rval);
102 static FILE *
103 open_local_map(char *mapname)
105 char filename[LINEMAX];
107 if (*mapname != '/') {
108 (void) snprintf(filename, sizeof (filename), "/etc/dev/%s",
109 mapname);
110 } else {
111 (void) snprintf(filename, sizeof (filename), "%s", mapname);
114 return (fopen(filename, "r"));
117 static void
118 unquote(char *str, char *qbuf)
120 register int escaped, inquote, quoted;
121 register char *ip, *bp, *qp;
122 char buf[LINEMAX];
124 escaped = inquote = quoted = 0;
126 for (ip = str, bp = buf, qp = qbuf; *ip; ip++) {
127 if (!escaped) {
128 if (*ip == '\\') {
129 escaped = 1;
130 quoted ++;
131 continue;
132 } else if (*ip == '"') {
133 inquote = !inquote;
134 quoted ++;
135 continue;
139 *bp++ = *ip;
140 *qp++ = (inquote || escaped) ? '^' : ' ';
141 escaped = 0;
143 *bp = '\0';
144 *qp = '\0';
145 if (quoted)
146 (void) strcpy(str, buf);
150 * gets the qualified characters in *p into w, which has space allocated
151 * already
153 static int
154 getword(char *w, char *wq, char **p, char **pq, char delim, int wordsz)
156 char *tmp = w;
157 char *tmpq = wq;
158 int count = wordsz;
160 if (wordsz <= 0) {
161 return (-1);
164 while ((delim == ' ' ? isspace(**p) : **p == delim) && **pq == ' ') {
165 (*p)++;
166 (*pq)++;
169 while (**p &&
170 !((delim == ' ' ? isspace(**p) : **p == delim) &&
171 **pq == ' ')) {
172 if (--count <= 0) {
173 *tmp = '\0';
174 *tmpq = '\0';
175 dprintf(DBG_INFO, "maximum word length %d exceeded\n",
176 wordsz);
177 return (-1);
179 *w++ = *(*p)++;
180 *wq++ = *(*pq)++;
182 *w = '\0';
183 *wq = '\0';
184 return (0);
187 static int
188 parse_mapinfo_file(FILE *fp, nvlist_t **ret_nvlp)
190 int error = 0;
191 nvlist_t *nvl = NULL, *attrs = NULL;
192 char line[LINEMAX], lineq[LINEMAX];
193 char word[MAXPATHLEN+1], wordq[MAXPATHLEN+1];
194 char *lp, *lq;
196 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0) {
197 return (EFAULT);
200 while (fgets(line, sizeof (line), fp)) {
201 char *name, *key, *val;
203 lp = (char *)line;
204 lq = (char *)lineq;
205 unquote(lp, lq);
206 if ((getword(word, wordq, &lp, &lq, ' ',
207 sizeof (word)) == -1) || (word[0] == '\0'))
208 continue;
210 if (word[0] == '#')
211 continue;
213 name = strtok(line, SPC);
214 if (name == NULL)
215 continue;
217 (void) dprintf(DBG_INFO, "get a line for %s\n", name);
218 key = strtok(NULL, "=");
219 if (key == NULL) {
220 (void) dprintf(DBG_INFO, "no attributes specified for "
221 "%s\n", name);
222 continue;
225 attrs = NULL;
226 if (nvlist_alloc(&attrs, NV_UNIQUE_NAME, 0) != 0) {
227 error = EFAULT;
228 goto fail1;
231 while (key && *key) {
232 char *rest;
233 rest = strtok(NULL, "\n");
234 if (rest == NULL) {
235 (void) dprintf(DBG_INFO, "no value for key "
236 "%s\n", key);
237 break;
239 if (rest[0] == ';') {
240 val = strdup("devname_null");
241 rest++;
242 } else {
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) {
249 error = EFAULT;
250 goto fail;
253 key = strtok(rest, "=");
255 (void) dprintf(DBG_INFO, "parse_map_info: add entry name=%s\n",
256 name);
257 if (nvlist_add_nvlist(nvl, name, attrs) != 0) {
258 error = EFAULT;
259 goto fail;
263 done:
264 *ret_nvlp = nvl;
265 return (0);
267 fail:
268 nvlist_free(attrs);
269 fail1:
270 nvlist_free(nvl);
271 return (error);
274 void
275 di_devname_print_mapinfo(nvlist_t *nvl)
277 char *name, *key, *val;
278 nvlist_t *attrs;
279 nvpair_t *nvp, *kvp;
281 nvp = nvlist_next_nvpair(nvl, NULL);
282 while (nvp) {
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);
287 while (kvp) {
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);
297 static int
298 action_mklink(char *target, char *source)
300 (void) dprintf(DBG_INFO, "mklink for source %s target %s\n",
301 source, target);
302 return (symlink(source, target));
305 static struct actions {
306 char *key;
307 devname_spec_t spec;
308 int (*action)(char *, char *);
309 } actions[] = {
310 {"devices-path", DEVNAME_NS_PATH, action_mklink},
311 {"dev-path", DEVNAME_NS_DEV, action_mklink},
312 {NULL, DEVNAME_NS_NONE, NULL}
315 static int
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)
319 int i = 0;
320 int error = 0;
321 char *attrname, *attrval;
322 int len = 0;
323 char *path = NULL;
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) {
331 switch (cmd) {
332 case DEVFSADMD_NS_READDIR:
333 len = strlen(dir_name) + strlen(devname) + 2;
334 path = malloc(len);
335 (void) snprintf(path, len, "%s/%s", dir_name,
336 devname);
337 error = actions[i].action(path, attrval);
338 free(path);
339 if (error) {
340 (void) dprintf(DBG_INFO, "action "
341 "failed %d\n", error);
342 return (error);
343 } else {
344 (*nsmapcount)++;
345 (void) dprintf(DBG_INFO,
346 "mapcount %d\n", *nsmapcount);
348 break;
349 case DEVFSADMD_NS_LOOKUP:
350 *devfsadm_link = strdup(attrval);
351 *devfsadm_spec = actions[i].spec;
352 break;
353 default:
354 break;
357 i++;
359 return (0);
363 di_devname_action_on_key(nvlist_t *map, uint8_t cmd, char *dir_name, void *hdl)
365 char *name = NULL;
366 nvpair_t *entry;
367 nvlist_t *attrs;
368 int32_t error = 0;
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);
375 while (entry) {
376 nvpair_t *attr;
377 name = nvpair_name(entry);
378 (void) dprintf(DBG_INFO, "di_devname_action_on_key: name %s\n",
379 name);
380 (void) nvpair_value_nvlist(entry, &attrs);
382 attr = nvlist_next_nvpair(attrs, NULL);
383 while (attr) {
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 */
388 if (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);
399 switch (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);
403 break;
404 case DEVFSADMD_NS_LOOKUP:
405 if (devfsadm_link && devfsadm_spec != DEVNAME_NS_NONE) {
406 (void) dprintf(DBG_INFO, "devfsadm_link is %s\n",
407 devfsadm_link);
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;
411 } else {
412 (void) dprintf(DBG_INFO, "error out\n");
413 return (1);
415 break;
416 default:
417 (void) dprintf(DBG_INFO, "error NOTSUP out\n");
418 return (ENOTSUP);
421 return (0);
425 static nvlist_t *
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];
431 int count = 0;
432 char *lp, *lq;
434 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0) != 0)
435 return (NULL);
437 while (fgets(line, sizeof (line), fp)) {
438 char *name, *key, *val;
440 if (line[0] == '#')
441 continue;
443 dprintf(DBG_INFO, "getent_mapinfo_file: get a line %s\n", line);
444 lp = (char *)line;
445 lq = (char *)lineq;
446 unquote(lp, lq);
447 if ((getword(word, wordq, &lp, &lq, ' ', sizeof (word))
448 == -1) || (word[0] == '\0'))
449 continue;
451 name = strtok(line, SPC);
452 if (name == NULL)
453 continue;
455 dprintf(DBG_INFO, "macthing with the key %s match %s\n",
456 name, match);
457 /* bypass the non-related entries */
458 if (strcmp(name, match) != 0)
459 continue;
461 /* get a matched entry */
462 key = strtok(NULL, "=");
463 if (key == NULL) {
464 (void) dprintf(DBG_INFO, "no attributes specified "
465 "for %s\n", name);
466 goto fail1;
469 attrs = NULL;
470 if (nvlist_alloc(&attrs, NV_UNIQUE_NAME, 0) != 0)
471 goto fail1;
472 while (key && *key) {
473 char *rest;
474 rest = strtok(NULL, "\n");
475 if (rest == NULL) {
476 (void) dprintf(DBG_INFO, "no value for key "
477 "%s\n", key);
478 goto fail;
480 if (rest[0] == ';') {
481 val = strdup("devname_null");
482 rest++;
483 } else {
484 val = strtok(rest, ";");
485 rest = strtok(NULL, "");
487 (void) dprintf(DBG_INFO, "found entry %s %s for %s\n",
488 key, val, name);
489 if (nvlist_add_string(attrs, key, val) != 0)
490 goto fail;
492 key = strtok(rest, "=");
494 (void) dprintf(DBG_INFO, "adding nvlist for %s\n", name);
495 if (nvlist_add_nvlist(nvl, name, attrs) != 0)
496 goto fail;
497 count++;
498 break;
501 if (count == 0)
502 goto fail1;
504 return (nvl);
506 fail:
507 nvlist_free(attrs);
508 fail1:
509 nvlist_free(nvl);
510 errno = EFAULT;
511 return (NULL);
514 static int
515 di_devname_getmapent_files(char *key, char *mapname, nvlist_t **map)
517 FILE *fp;
518 int rval = 0;
519 nvlist_t *nvl = NULL;
521 fp = open_local_map(mapname);
522 if (fp == NULL)
523 return (1);
525 nvl = getent_mapinfo_file(fp, key);
526 if (nvl != NULL) {
527 *map = nvl;
528 } else {
529 rval = errno;
531 (void) fclose(fp);
533 return (rval);
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",
540 key, mapname);
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));
554 static void
555 debug_print(debug_level_t msglevel, const char *fmt, va_list ap)
557 if (devname_debug < msglevel)
558 return;
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);
567 } else {
568 (void) vfprintf(stderr, fmt, ap);
572 /* ARGSUSED */
573 /* PRINTFLIKE2 */
574 static void
575 dprintf(debug_level_t msglevel, const char *fmt, ...)
577 va_list ap;
579 assert(msglevel > 0);
581 if (!devname_debug)
582 return;
584 va_start(ap, fmt);
585 debug_print(msglevel, fmt, ap);
586 va_end(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)
604 nvlist_t *nvl;
606 if (nvlist_alloc(&nvl, 0, 0))
607 return (-1);
609 if (nvlist_add_string(nvl, SDEV_NVNAME_MOUNTPT, mountpt)) {
610 nvlist_free(nvl);
611 return (-1);
614 *profp = (di_prof_t)nvl;
615 return (0);
619 * Free space allocated by di_prof_init().
621 void
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)
633 char *buf = NULL;
634 size_t buflen = 0;
635 int rv;
637 if (nvlist_pack((nvlist_t *)prof, &buf, &buflen, NV_ENCODE_NATIVE, 0))
638 return (-1);
639 rv = modctl(MODDEVNAME, MODDEVNAME_PROFILE, buf, buflen);
640 free(buf);
641 return (rv);
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
649 * is the winner.
652 di_prof_add_dev(di_prof_t prof, const char *dev)
654 if (nvlist_add_string((nvlist_t *)prof, SDEV_NVNAME_INCLUDE, dev))
655 return (-1);
656 return (0);
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))
667 return (-1);
668 return (0);
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;
678 char *syml[2];
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))
683 return (-1);
684 return (0);
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;
694 char *map[2];
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))
699 return (-1);
700 return (0);