8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libbsm / common / getdment.c
blob3f1953d956df26c31b9877ee960014255109796d
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) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <string.h>
27 #include <strings.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <limits.h>
31 #include <bsm/devices.h>
32 #include <bsm/devalloc.h>
34 char *strtok_r(char *, const char *, char **);
36 /* externs from getdaent.c */
37 extern char *trim_white(char *);
38 extern int pack_white(char *);
39 extern char *getdadmfield(char *, char *);
40 extern int getdadmline(char *, int, FILE *);
42 static struct _dmapbuff {
43 FILE *_dmapf; /* for /etc/security/device_maps */
44 devmap_t _interpdevmap;
45 char _interpdmline[DA_BUFSIZE + 1];
46 char *_DEVMAP;
47 } *__dmapbuff;
49 #define dmapf (_dmap->_dmapf)
50 #define interpdevmap (_dmap->_interpdevmap)
51 #define interpdmline (_dmap->_interpdmline)
52 #define DEVMAPS_FILE (_dmap->_DEVMAP)
54 devmap_t *dmap_interpret(char *, devmap_t *);
55 static devmap_t *dmap_interpretf(char *, devmap_t *);
56 static devmap_t *dmap_dlexpand(devmap_t *);
57 static int dmap_resolve_link(char *devpath, char **devfs_path);
59 int dmap_matchdev(devmap_t *, char *);
60 int dmap_matchname(devmap_t *, char *);
64 * _dmapalloc -
65 * allocates common buffers and structures.
66 * returns pointer to the new structure, else returns NULL on error.
68 static struct _dmapbuff *
69 _dmapalloc(void)
71 struct _dmapbuff *_dmap = __dmapbuff;
73 if (_dmap == NULL) {
74 _dmap = (struct _dmapbuff *)calloc((unsigned)1,
75 (unsigned)sizeof (*__dmapbuff));
76 if (_dmap == NULL)
77 return (NULL);
78 DEVMAPS_FILE = "/etc/security/device_maps";
79 dmapf = NULL;
80 __dmapbuff = _dmap;
83 return (_dmap);
87 * setdmapent -
88 * rewinds the device_maps file to the beginning.
90 void
91 setdmapent(void)
93 struct _dmapbuff *_dmap = _dmapalloc();
95 if (_dmap == NULL)
96 return;
97 if (dmapf == NULL)
98 dmapf = fopen(DEVMAPS_FILE, "rF");
99 else
100 rewind(dmapf);
104 * enddmapent -
105 * closes device_maps file.
107 void
108 enddmapent(void)
110 struct _dmapbuff *_dmap = _dmapalloc();
112 if (_dmap == NULL)
113 return;
114 if (dmapf != NULL) {
115 (void) fclose(dmapf);
116 dmapf = NULL;
120 void
121 freedmapent(devmap_t *dmap)
123 char **darp;
125 if ((darp = dmap->dmap_devarray) != NULL) {
126 while (*darp != NULL)
127 free(*darp++);
128 free(dmap->dmap_devarray);
129 dmap->dmap_devarray = NULL;
134 * setdmapfile -
135 * changes the default device_maps file to the one specified.
136 * It does not close the previous file. If this is desired, enddmapent
137 * should be called prior to setdampfile.
139 void
140 setdmapfile(char *file)
142 struct _dmapbuff *_dmap = _dmapalloc();
144 if (_dmap == NULL)
145 return;
146 if (dmapf != NULL) {
147 (void) fclose(dmapf);
148 dmapf = NULL;
150 DEVMAPS_FILE = file;
154 * getdmapent -
155 * When first called, returns a pointer to the first devmap_t structure
156 * in device_maps; thereafter, it returns a pointer to the next devmap_t
157 * structure in the file. Thus successive calls can be used to read the
158 * entire file.
159 * call to getdmapent should be bracketed by setdmapent and enddmapent.
160 * returns pointer to devmap_t found, else returns NULL if no entry found
161 * or on error.
163 devmap_t *
164 getdmapent(void)
166 devmap_t *dmap;
167 struct _dmapbuff *_dmap = _dmapalloc();
169 if ((_dmap == 0) || (dmapf == NULL))
170 return (NULL);
172 while (getdadmline(interpdmline, (int)sizeof (interpdmline),
173 dmapf) != 0) {
174 if ((dmap = dmap_interpret(interpdmline,
175 &interpdevmap)) == NULL)
176 continue;
177 return (dmap);
180 return (NULL);
184 * getdmapnam -
185 * searches from the beginning of device_maps for the device specified by
186 * its name.
187 * call to getdmapnam should be bracketed by setdmapent and enddmapent.
188 * returns pointer to devmapt_t for the device if it is found, else
189 * returns NULL if device not found or in case of error.
191 devmap_t *
192 getdmapnam(char *name)
194 devmap_t *dmap;
195 struct _dmapbuff *_dmap = _dmapalloc();
197 if ((name == NULL) || (_dmap == 0) || (dmapf == NULL))
198 return (NULL);
200 while (getdadmline(interpdmline, (int)sizeof (interpdmline),
201 dmapf) != 0) {
202 if (strstr(interpdmline, name) == NULL)
203 continue;
204 if ((dmap = dmap_interpretf(interpdmline,
205 &interpdevmap)) == NULL)
206 continue;
207 if (dmap_matchname(dmap, name)) {
208 if ((dmap = dmap_dlexpand(dmap)) == NULL)
209 continue;
210 enddmapent();
211 return (dmap);
213 freedmapent(dmap);
216 return (NULL);
220 * getdmapdev -
221 * searches from the beginning of device_maps for the device specified by
222 * its logical name.
223 * call to getdmapdev should be bracketed by setdmapent and enddmapent.
224 * returns pointer to the devmap_t for the device if device is found,
225 * else returns NULL if device not found or on error.
227 devmap_t *
228 getdmapdev(char *dev)
230 devmap_t *dmap;
231 struct _dmapbuff *_dmap = _dmapalloc();
233 if ((dev == NULL) || (_dmap == 0) || (dmapf == NULL))
234 return (NULL);
236 while (getdadmline(interpdmline, (int)sizeof (interpdmline),
237 dmapf) != 0) {
238 if ((dmap = dmap_interpret(interpdmline,
239 &interpdevmap)) == NULL)
240 continue;
241 if (dmap_matchdev(dmap, dev)) {
242 enddmapent();
243 return (dmap);
245 freedmapent(dmap);
248 return (NULL);
252 * getdmaptype -
253 * searches from the beginning of device_maps for the device specified by
254 * its type.
255 * call to getdmaptype should be bracketed by setdmapent and enddmapent.
256 * returns pointer to devmap_t found, else returns NULL if no entry found
257 * or on error.
259 devmap_t *
260 getdmaptype(char *type)
262 devmap_t *dmap;
263 struct _dmapbuff *_dmap = _dmapalloc();
265 if ((type == NULL) || (_dmap == 0) || (dmapf == NULL))
266 return (NULL);
268 while (getdadmline(interpdmline, (int)sizeof (interpdmline),
269 dmapf) != 0) {
270 if ((dmap = dmap_interpretf(interpdmline,
271 &interpdevmap)) == NULL)
272 continue;
273 if (dmap->dmap_devtype != NULL &&
274 strcmp(type, dmap->dmap_devtype) == 0) {
275 if ((dmap = dmap_dlexpand(dmap)) == NULL)
276 continue;
277 return (dmap);
279 freedmapent(dmap);
282 return (NULL);
286 * dmap_match_one_dev -
287 * Checks if the specified devmap_t contains strings
288 * for the same link as the device specified.
290 * Returns 1 for a match, else returns 0.
292 static int
293 dmap_match_one_dev(devmap_t *dmap, char *dev)
295 char **dva;
296 char *dv;
297 char *dmap_link;
298 char *dev_link;
299 char stage_link[PATH_MAX + 1];
301 if (dmap->dmap_devarray == NULL)
302 return (0);
304 for (dva = dmap->dmap_devarray; (dv = *dva) != NULL; dva++) {
305 if (strstr(dev, dv) != NULL)
306 return (1);
308 /* check if both refer to same physical device */
309 (void) strncpy(stage_link, dmap->dmap_devarray[0], sizeof (stage_link));
310 if (dmap_resolve_link(stage_link, &dmap_link) != 0)
311 return (0);
312 (void) strncpy(stage_link, dev, sizeof (stage_link));
313 if (dmap_resolve_link(stage_link, &dev_link) != 0) {
314 free(dmap_link);
315 return (0);
317 if (strcmp(dev_link, dmap_link) == 0) {
318 free(dmap_link);
319 free(dev_link);
320 return (1);
322 free(dmap_link);
323 free(dev_link);
324 return (0);
328 * dmap_matchdev -
329 * checks if the specified devmap_t is for the device specified.
330 * returns 1 if it is, else returns 0.
333 dmap_matchdev(devmap_t *dmap, char *dev)
335 char **dva;
336 char *dv;
338 if (dmap->dmap_devarray == NULL)
339 return (0);
340 for (dva = dmap->dmap_devarray; (dv = *dva) != NULL; dva ++) {
341 if (strcmp(dv, dev) == 0)
342 return (1);
345 return (0);
349 * Requires a match of the /dev/? links, not just the logical devname
350 * Returns 1 for match found, 0 for match not found, 2 for invalid arguments.
352 * Also looks for an instance number at the end of the logical name, and
353 * puts instance or -1 into *num.
356 dmap_exact_dev(devmap_t *dmap, char *dev, int *num)
358 char *dv;
360 if ((dev == NULL) || (dmap->dmap_devname == NULL))
361 return (2);
362 dv = dmap->dmap_devname;
363 dv += strcspn(dmap->dmap_devname, "0123456789");
364 if (sscanf(dv, "%d", num) != 1)
365 *num = -1;
366 /* during some add processes, dev can be shorter than dmap */
367 return (dmap_match_one_dev(dmap, dev));
371 * dmap_matchtype -
372 * checks if the specified devmap_t is for the device specified.
373 * returns 1 if it is, else returns 0.
376 dmap_matchtype(devmap_t *dmap, char *type)
378 if ((dmap->dmap_devtype == NULL) || (type == NULL))
379 return (0);
381 return ((strcmp(dmap->dmap_devtype, type) == 0));
385 * dmap_matchname -
386 * checks if the specified devmap_t is for the device specified.
387 * returns 1 if it is, else returns 0.
390 dmap_matchname(devmap_t *dmap, char *name)
392 if (dmap->dmap_devname == NULL)
393 return (0);
395 return ((strcmp(dmap->dmap_devname, name) == 0));
399 * Temporarily duplicated directly from libdevinfo's is_minor_node(),
400 * and renamed, because we cannot link this from libdevinfo.
402 * To be resolved in a couple of builds.
404 * The real fix is to move device allocation out of libbsm.
406 * returns 1 if contents is a minor node in /devices.
407 * If mn_root is not NULL, mn_root is set to:
408 * if contents is a /dev node, mn_root = contents
409 * OR
410 * if contents is a /devices node, mn_root set to the '/'
411 * following /devices.
413 static int
414 dmap_minor_root(const char *contents, const char **mn_root)
416 char *ptr, *prefix;
418 prefix = "../devices/";
420 if ((ptr = strstr(contents, prefix)) != NULL) {
422 /* mn_root should point to the / following /devices */
423 if (mn_root != NULL) {
424 *mn_root = ptr += strlen(prefix) - 1;
426 return (1);
429 prefix = "/devices/";
431 if (strncmp(contents, prefix, strlen(prefix)) == 0) {
433 /* mn_root should point to the / following /devices/ */
434 if (mn_root != NULL) {
435 *mn_root = contents + strlen(prefix) - 1;
437 return (1);
440 if (mn_root != NULL) {
441 *mn_root = contents;
443 return (0);
447 * Temporarily duplicated directly from libdevinfo's devfs_resolve_link(),
448 * and renamed, because we cannot link this from libdevinfo now, and will
449 * create a sensible solution in the near future.
451 * returns 0 if resolved, -1 otherwise.
452 * devpath: Absolute path to /dev link
453 * devfs_path: Returns malloced string: /devices path w/out "/devices"
455 static int
456 dmap_resolve_link(char *devpath, char **devfs_path)
458 char contents[PATH_MAX + 1];
459 char stage_link[PATH_MAX + 1];
460 char *ptr;
461 int linksize;
462 char *slashdev = "/dev/";
464 if (devfs_path) {
465 *devfs_path = NULL;
468 linksize = readlink(devpath, contents, PATH_MAX);
470 if (linksize <= 0) {
471 return (-1);
472 } else {
473 contents[linksize] = '\0';
477 * if the link contents is not a minor node assume
478 * that link contents is really a pointer to another
479 * link, and if so recurse and read its link contents.
481 if (dmap_minor_root((const char *)contents, (const char **)&ptr) !=
482 1) {
483 if (strncmp(contents, slashdev, strlen(slashdev)) == 0) {
484 /* absolute path, starting with /dev */
485 (void) strcpy(stage_link, contents);
486 } else {
487 /* relative path, prefix devpath */
488 if ((ptr = strrchr(devpath, '/')) == NULL) {
489 /* invalid link */
490 return (-1);
492 *ptr = '\0';
493 (void) strcpy(stage_link, devpath);
494 *ptr = '/';
495 (void) strcat(stage_link, "/");
496 (void) strcat(stage_link, contents);
499 return (dmap_resolve_link(stage_link, devfs_path));
502 if (devfs_path) {
503 *devfs_path = strdup(ptr);
504 if (*devfs_path == NULL) {
505 return (-1);
509 return (0);
513 * dmap_physname: path to /devices device
514 * Returns:
515 * strdup'd (i.e. malloc'd) real device file if successful
516 * NULL on error
518 char *
519 dmap_physname(devmap_t *dmap)
521 char *oldlink;
522 char stage_link[PATH_MAX + 1];
524 if ((dmap == NULL) || (dmap->dmap_devarray == NULL) ||
525 (dmap->dmap_devarray[0] == NULL))
526 return (NULL);
528 (void) strncpy(stage_link, dmap->dmap_devarray[0], sizeof (stage_link));
530 if (dmap_resolve_link(stage_link, &oldlink) == 0)
531 return (oldlink);
532 return (NULL);
536 * dm_match -
537 * calls dmap_matchname or dmap_matchtype as appropriate.
540 dm_match(devmap_t *dmap, da_args *dargs)
542 if (dargs->devinfo->devname)
543 return (dmap_matchname(dmap, dargs->devinfo->devname));
544 else if (dargs->devinfo->devtype)
545 return (dmap_matchtype(dmap, dargs->devinfo->devtype));
547 return (0);
551 * dmap_interpret -
552 * calls dmap_interpretf and dmap_dlexpand to parse devmap_t line.
553 * returns pointer to parsed devmapt_t entry, else returns NULL on error.
555 devmap_t *
556 dmap_interpret(char *val, devmap_t *dm)
558 if (dmap_interpretf(val, dm) == NULL)
559 return (NULL);
561 return (dmap_dlexpand(dm));
565 * dmap_interpretf -
566 * parses string "val" and initializes pointers in the given devmap_t to
567 * fields in "val".
568 * returns pointer to updated devmap_t.
570 static devmap_t *
571 dmap_interpretf(char *val, devmap_t *dm)
573 dm->dmap_devname = getdadmfield(val, KV_TOKEN_DELIMIT);
574 dm->dmap_devtype = getdadmfield(NULL, KV_TOKEN_DELIMIT);
575 dm->dmap_devlist = getdadmfield(NULL, KV_TOKEN_DELIMIT);
576 dm->dmap_devarray = NULL;
577 if (dm->dmap_devname == NULL ||
578 dm->dmap_devtype == NULL ||
579 dm->dmap_devlist == NULL)
580 return (NULL);
582 return (dm);
586 * dmap_dlexpand -
587 * expands dmap_devlist of the form `devlist_generate`
588 * returns unexpanded form if there is no '\`' or in case of error.
590 static devmap_t *
591 dmap_dlexpand(devmap_t *dmp)
593 char tmplist[DA_BUFSIZE + 1];
594 char *cp, *cpl, **darp;
595 int count;
596 FILE *expansion;
598 dmp->dmap_devarray = NULL;
599 if (dmp->dmap_devlist == NULL)
600 return (NULL);
601 if (*(dmp->dmap_devlist) != '`') {
602 (void) strcpy(tmplist, dmp->dmap_devlist);
603 } else {
604 (void) strcpy(tmplist, dmp->dmap_devlist + 1);
605 if ((cp = strchr(tmplist, '`')) != NULL)
606 *cp = '\0';
607 if ((expansion = popen(tmplist, "rF")) == NULL)
608 return (NULL);
609 count = fread(tmplist, 1, sizeof (tmplist) - 1, expansion);
610 (void) pclose(expansion);
611 tmplist[count] = '\0';
614 /* cleanup the list */
615 count = pack_white(tmplist);
616 dmp->dmap_devarray = darp =
617 (char **)malloc((count + 2) * sizeof (char *));
618 if (darp == NULL)
619 return (NULL);
620 cp = tmplist;
621 while ((cp = strtok_r(cp, " ", &cpl)) != NULL) {
622 *darp = strdup(cp);
623 if (*darp == NULL) {
624 freedmapent(dmp);
625 return (NULL);
627 darp++;
628 cp = NULL;
630 *darp = NULL;
632 return (dmp);
636 * dmapskip -
637 * scans input string to find next colon or end of line.
638 * returns pointer to next char.
640 static char *
641 dmapskip(char *p)
643 while (*p && *p != ':' && *p != '\n')
644 ++p;
645 if (*p == '\n')
646 *p = '\0';
647 else if (*p != '\0')
648 *p++ = '\0';
650 return (p);
654 * dmapdskip -
655 * scans input string to find next space or end of line.
656 * returns pointer to next char.
658 static char *
659 dmapdskip(p)
660 register char *p;
662 while (*p && *p != ' ' && *p != '\n')
663 ++p;
664 if (*p != '\0')
665 *p++ = '\0';
667 return (p);
670 char *
671 getdmapfield(char *ptr)
673 static char *tptr;
675 if (ptr == NULL)
676 ptr = tptr;
677 if (ptr == NULL)
678 return (NULL);
679 tptr = dmapskip(ptr);
680 ptr = trim_white(ptr);
681 if (ptr == NULL)
682 return (NULL);
683 if (*ptr == NULL)
684 return (NULL);
686 return (ptr);
689 char *
690 getdmapdfield(char *ptr)
692 static char *tptr;
693 if (ptr != NULL) {
694 ptr = trim_white(ptr);
695 } else {
696 ptr = tptr;
698 if (ptr == NULL)
699 return (NULL);
700 tptr = dmapdskip(ptr);
701 if (ptr == NULL)
702 return (NULL);
703 if (*ptr == NULL)
704 return (NULL);
706 return (ptr);