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 (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
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];
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 *);
65 * allocates common buffers and structures.
66 * returns pointer to the new structure, else returns NULL on error.
68 static struct _dmapbuff
*
71 struct _dmapbuff
*_dmap
= __dmapbuff
;
74 _dmap
= (struct _dmapbuff
*)calloc((unsigned)1,
75 (unsigned)sizeof (*__dmapbuff
));
78 DEVMAPS_FILE
= "/etc/security/device_maps";
88 * rewinds the device_maps file to the beginning.
93 struct _dmapbuff
*_dmap
= _dmapalloc();
98 dmapf
= fopen(DEVMAPS_FILE
, "rF");
105 * closes device_maps file.
110 struct _dmapbuff
*_dmap
= _dmapalloc();
115 (void) fclose(dmapf
);
121 freedmapent(devmap_t
*dmap
)
125 if ((darp
= dmap
->dmap_devarray
) != NULL
) {
126 while (*darp
!= NULL
)
128 free(dmap
->dmap_devarray
);
129 dmap
->dmap_devarray
= NULL
;
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.
140 setdmapfile(char *file
)
142 struct _dmapbuff
*_dmap
= _dmapalloc();
147 (void) fclose(dmapf
);
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
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
167 struct _dmapbuff
*_dmap
= _dmapalloc();
169 if ((_dmap
== 0) || (dmapf
== NULL
))
172 while (getdadmline(interpdmline
, (int)sizeof (interpdmline
),
174 if ((dmap
= dmap_interpret(interpdmline
,
175 &interpdevmap
)) == NULL
)
185 * searches from the beginning of device_maps for the device specified by
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.
192 getdmapnam(char *name
)
195 struct _dmapbuff
*_dmap
= _dmapalloc();
197 if ((name
== NULL
) || (_dmap
== 0) || (dmapf
== NULL
))
200 while (getdadmline(interpdmline
, (int)sizeof (interpdmline
),
202 if (strstr(interpdmline
, name
) == NULL
)
204 if ((dmap
= dmap_interpretf(interpdmline
,
205 &interpdevmap
)) == NULL
)
207 if (dmap_matchname(dmap
, name
)) {
208 if ((dmap
= dmap_dlexpand(dmap
)) == NULL
)
221 * searches from the beginning of device_maps for the device specified by
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.
228 getdmapdev(char *dev
)
231 struct _dmapbuff
*_dmap
= _dmapalloc();
233 if ((dev
== NULL
) || (_dmap
== 0) || (dmapf
== NULL
))
236 while (getdadmline(interpdmline
, (int)sizeof (interpdmline
),
238 if ((dmap
= dmap_interpret(interpdmline
,
239 &interpdevmap
)) == NULL
)
241 if (dmap_matchdev(dmap
, dev
)) {
253 * searches from the beginning of device_maps for the device specified by
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
260 getdmaptype(char *type
)
263 struct _dmapbuff
*_dmap
= _dmapalloc();
265 if ((type
== NULL
) || (_dmap
== 0) || (dmapf
== NULL
))
268 while (getdadmline(interpdmline
, (int)sizeof (interpdmline
),
270 if ((dmap
= dmap_interpretf(interpdmline
,
271 &interpdevmap
)) == NULL
)
273 if (dmap
->dmap_devtype
!= NULL
&&
274 strcmp(type
, dmap
->dmap_devtype
) == 0) {
275 if ((dmap
= dmap_dlexpand(dmap
)) == 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.
293 dmap_match_one_dev(devmap_t
*dmap
, char *dev
)
299 char stage_link
[PATH_MAX
+ 1];
301 if (dmap
->dmap_devarray
== NULL
)
304 for (dva
= dmap
->dmap_devarray
; (dv
= *dva
) != NULL
; dva
++) {
305 if (strstr(dev
, dv
) != NULL
)
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)
312 (void) strncpy(stage_link
, dev
, sizeof (stage_link
));
313 if (dmap_resolve_link(stage_link
, &dev_link
) != 0) {
317 if (strcmp(dev_link
, dmap_link
) == 0) {
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
)
338 if (dmap
->dmap_devarray
== NULL
)
340 for (dva
= dmap
->dmap_devarray
; (dv
= *dva
) != NULL
; dva
++) {
341 if (strcmp(dv
, dev
) == 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
)
360 if ((dev
== NULL
) || (dmap
->dmap_devname
== NULL
))
362 dv
= dmap
->dmap_devname
;
363 dv
+= strcspn(dmap
->dmap_devname
, "0123456789");
364 if (sscanf(dv
, "%d", num
) != 1)
366 /* during some add processes, dev can be shorter than dmap */
367 return (dmap_match_one_dev(dmap
, dev
));
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
))
381 return ((strcmp(dmap
->dmap_devtype
, type
) == 0));
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
)
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
410 * if contents is a /devices node, mn_root set to the '/'
411 * following /devices.
414 dmap_minor_root(const char *contents
, const char **mn_root
)
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;
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;
440 if (mn_root
!= NULL
) {
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"
456 dmap_resolve_link(char *devpath
, char **devfs_path
)
458 char contents
[PATH_MAX
+ 1];
459 char stage_link
[PATH_MAX
+ 1];
462 char *slashdev
= "/dev/";
468 linksize
= readlink(devpath
, contents
, PATH_MAX
);
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
) !=
483 if (strncmp(contents
, slashdev
, strlen(slashdev
)) == 0) {
484 /* absolute path, starting with /dev */
485 (void) strcpy(stage_link
, contents
);
487 /* relative path, prefix devpath */
488 if ((ptr
= strrchr(devpath
, '/')) == NULL
) {
493 (void) strcpy(stage_link
, devpath
);
495 (void) strcat(stage_link
, "/");
496 (void) strcat(stage_link
, contents
);
499 return (dmap_resolve_link(stage_link
, devfs_path
));
503 *devfs_path
= strdup(ptr
);
504 if (*devfs_path
== NULL
) {
513 * dmap_physname: path to /devices device
515 * strdup'd (i.e. malloc'd) real device file if successful
519 dmap_physname(devmap_t
*dmap
)
522 char stage_link
[PATH_MAX
+ 1];
524 if ((dmap
== NULL
) || (dmap
->dmap_devarray
== NULL
) ||
525 (dmap
->dmap_devarray
[0] == NULL
))
528 (void) strncpy(stage_link
, dmap
->dmap_devarray
[0], sizeof (stage_link
));
530 if (dmap_resolve_link(stage_link
, &oldlink
) == 0)
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
));
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.
556 dmap_interpret(char *val
, devmap_t
*dm
)
558 if (dmap_interpretf(val
, dm
) == NULL
)
561 return (dmap_dlexpand(dm
));
566 * parses string "val" and initializes pointers in the given devmap_t to
568 * returns pointer to updated 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
)
587 * expands dmap_devlist of the form `devlist_generate`
588 * returns unexpanded form if there is no '\`' or in case of error.
591 dmap_dlexpand(devmap_t
*dmp
)
593 char tmplist
[DA_BUFSIZE
+ 1];
594 char *cp
, *cpl
, **darp
;
598 dmp
->dmap_devarray
= NULL
;
599 if (dmp
->dmap_devlist
== NULL
)
601 if (*(dmp
->dmap_devlist
) != '`') {
602 (void) strcpy(tmplist
, dmp
->dmap_devlist
);
604 (void) strcpy(tmplist
, dmp
->dmap_devlist
+ 1);
605 if ((cp
= strchr(tmplist
, '`')) != NULL
)
607 if ((expansion
= popen(tmplist
, "rF")) == 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 *));
621 while ((cp
= strtok_r(cp
, " ", &cpl
)) != NULL
) {
637 * scans input string to find next colon or end of line.
638 * returns pointer to next char.
643 while (*p
&& *p
!= ':' && *p
!= '\n')
655 * scans input string to find next space or end of line.
656 * returns pointer to next char.
662 while (*p
&& *p
!= ' ' && *p
!= '\n')
671 getdmapfield(char *ptr
)
679 tptr
= dmapskip(ptr
);
680 ptr
= trim_white(ptr
);
690 getdmapdfield(char *ptr
)
694 ptr
= trim_white(ptr
);
700 tptr
= dmapdskip(ptr
);