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]
23 * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
31 #include <sys/types.h>
39 #include <auth_list.h>
41 #include <bsm/devices.h>
42 #include <bsm/devalloc.h>
43 #include <tsol/label.h>
45 #define DA_DEFS "/etc/security/tsol/devalloc_defaults"
47 extern int _readbufline(char *, int, char *, int, int *);
48 extern char *strtok_r(char *, const char *, char **);
49 extern char *_strtok_escape(char *, char *, char **);
50 extern int getdaon(void);
51 extern int da_matchname(devalloc_t
*, char *);
52 extern int da_match(devalloc_t
*, da_args
*);
53 extern int dmap_matchname(devmap_t
*, char *);
54 extern int dm_match(devmap_t
*, da_args
*);
55 extern int dmap_matchtype(devmap_t
*dmap
, char *type
);
56 extern int dmap_matchdev(devmap_t
*dmap
, char *dev
);
57 extern int dmap_exact_dev(devmap_t
*dmap
, char *dev
, int *num
);
58 extern char *dmap_physname(devmap_t
*dmap
);
61 * The following structure is for recording old entries to be retained.
62 * We read the entries from the database into a linked list in memory,
63 * then turn around and write them out again.
65 typedef struct strentry
{
66 struct strentry
*se_next
;
67 char se_str
[4096 + 1];
71 * da_check_longindevperm -
72 * reads /etc/logindevperm and checks if specified device is in the file.
73 * returns 1 if specified device found in /etc/logindevperm, else returns 0
76 da_check_logindevperm(char *devname
)
80 int nlen
, plen
, slen
, lineno
, fsize
;
82 char *field_delims
= " \t\n";
90 * check if /etc/logindevperm exists and get its size
92 if ((fd
= open(LOGINDEVPERM
, O_RDONLY
)) == -1)
94 if (fstat(fd
, &f_stat
) != 0) {
98 fsize
= f_stat
.st_size
;
99 if ((fbuf
= (char *)malloc(fsize
)) == NULL
) {
103 if ((fp
= fdopen(fd
, "rF")) == NULL
) {
110 * read and parse /etc/logindevperm
112 plen
= nlen
= lineno
= 0;
113 while (fgets(line
, MAX_CANON
, fp
) != NULL
) {
115 if ((ptr
= strchr(line
, '#')) != NULL
)
116 *ptr
= '\0'; /* handle comments */
117 if (strtok_r(line
, field_delims
, &lasts
) == NULL
)
118 continue; /* ignore blank lines */
119 if (strtok_r(NULL
, field_delims
, &lasts
) == NULL
)
122 if ((ptr
= strtok_r(NULL
, field_delims
, &lasts
)) == NULL
)
123 /* empty device list */
125 nlen
= strlen(ptr
) + 1; /* +1 terminator */
128 slen
= snprintf(fbuf
, nlen
, "%s", ptr
);
130 slen
= snprintf(fbuf
+ plen
, nlen
- plen
, ":%s", ptr
);
141 * check if devname exists in /etc/logindevperm
143 device
= strtok_r(fbuf
, ":", &lasts
);
144 while (device
!= NULL
) {
146 * device and devname may be one of these types -
153 if (strcmp(device
, devname
) == 0) {
154 /* /dev/xx, /dev/dir/xx */
158 if ((ptr
= strrchr(device
, KV_WILDCHAR
)) != NULL
) {
159 /* all wildcard types */
161 if (strncmp(device
, devname
, strlen(device
)) == 0) {
166 device
= strtok_r(NULL
, ":", &lasts
);
174 * establishes readers/writer lock on fname; reads in the file if its
175 * contents changed since the last time we read it.
176 * returns size of buffer read, or -1 on failure.
179 _da_read_file(char *fname
, char **fbuf
, time_t *ftime
, rwlock_t
*flock
,
190 /* check the size and the time stamp on the file */
191 if (rw_rdlock(flock
) != 0)
193 if (stat(fname
, &f_stat
) != 0) {
194 (void) rw_unlock(flock
);
197 fsize
= f_stat
.st_size
;
198 newtime
= f_stat
.st_mtime
;
199 (void) rw_unlock(flock
);
201 while (newtime
> *ftime
) {
203 * file has been modified since we last read it; or this
205 * read file into the buffer with rw lock.
207 if (rw_wrlock(flock
) != 0)
209 if ((fd
= open(fname
, O_RDONLY
)) == -1) {
210 (void) rw_unlock(flock
);
217 if ((*fbuf
= malloc(fsize
)) == NULL
) {
218 (void) rw_unlock(flock
);
222 if (read(fd
, *fbuf
, fsize
) < fsize
) {
224 (void) rw_unlock(flock
);
228 (void) rw_unlock(flock
);
230 * verify that the file did not change just after we read it.
232 if (rw_rdlock(flock
) != 0) {
237 if (stat(fname
, &f_stat
) != 0) {
239 (void) rw_unlock(flock
);
243 fsize
= f_stat
.st_size
;
244 newtime
= f_stat
.st_mtime
;
245 (void) rw_unlock(flock
);
255 * add/remove current zone's name to the given devalloc_t.
258 _update_zonename(da_args
*dargs
, devalloc_t
*dap
)
261 int oldsize
, newsize
;
262 int has_zonename
= 0;
264 kva_t
*newkva
, *oldkva
;
265 kv_t
*newdata
, *olddata
;
268 devinfo
= dargs
->devinfo
;
269 oldkva
= dap
->da_devopts
;
270 if (oldkva
== NULL
) {
271 if (dargs
->optflag
& DA_REMOVE_ZONE
)
273 if (dargs
->optflag
& DA_ADD_ZONE
) {
274 newkva
= _str2kva(devinfo
->devopts
, KV_ASSIGN
,
277 dap
->da_devopts
= newkva
;
281 newsize
= oldsize
= oldkva
->length
;
282 if (kva_match(oldkva
, DAOPT_ZONE
))
284 if (dargs
->optflag
& DA_ADD_ZONE
) {
285 if ((zonename
= index(devinfo
->devopts
, '=')) == NULL
)
289 (void) _insert2kva(oldkva
, DAOPT_ZONE
, zonename
);
293 } else if (dargs
->optflag
& DA_REMOVE_ZONE
) {
298 * If zone name was the only key/value pair,
299 * put 'reserved' in the empty slot.
302 dap
->da_devopts
= NULL
;
309 newkva
= _new_kva(newsize
);
311 newdata
= newkva
->data
;
312 olddata
= oldkva
->data
;
313 for (i
= 0, j
= 0; i
< oldsize
; i
++) {
314 if ((dargs
->optflag
& DA_REMOVE_ZONE
) &&
315 (strcmp(olddata
[i
].key
, DAOPT_ZONE
) == 0))
317 newdata
[j
].key
= strdup(olddata
[i
].key
);
318 newdata
[j
].value
= strdup(olddata
[i
].value
);
322 if (dargs
->optflag
& DA_ADD_ZONE
) {
323 newdata
[j
].key
= strdup(DAOPT_ZONE
);
324 newdata
[j
].value
= strdup(zonename
);
328 dap
->da_devopts
= newkva
;
333 * converts a device_map entry into a printable string
334 * returns 0 on success, -1 on error.
338 _dmap2str(devmap_t
*dmp
, char *buf
, int size
, const char *sep
)
342 length
= snprintf(buf
, size
, "%s%s", dmp
->dmap_devname
, sep
);
345 length
+= snprintf(buf
+ length
, size
- length
, "%s%s",
346 dmp
->dmap_devtype
, sep
);
349 length
+= snprintf(buf
+ length
, size
- length
, "%s\n",
358 * calls dmap2str to break given devmap_t into printable entry.
359 * returns pointer to decoded entry, NULL on error.
362 _dmap2strentry(devmap_t
*devmapp
)
366 if ((sep
= (strentry_t
*)malloc(sizeof (strentry_t
))) == NULL
)
368 if (_dmap2str(devmapp
, sep
->se_str
, sizeof (sep
->se_str
),
369 KV_TOKEN_DELIMIT
"\\\n\t") != 0) {
378 * removes trailing ':' from buf.
381 fix_optstr(char *buf
)
385 if (p
= rindex(buf
, ':'))
391 * converts a device_allocate entry into a printable string
392 * returns 0 on success, -1 on error.
395 _da2str(da_args
*dargs
, devalloc_t
*dap
, char *buf
, int size
, const char *sep
,
399 int matching_entry
= 0;
402 if (dargs
->optflag
& DA_UPDATE
&&
403 (dargs
->optflag
& DA_ADD_ZONE
||
404 dargs
->optflag
& DA_REMOVE_ZONE
) &&
406 for (dnames
= dargs
->devnames
; *dnames
!= NULL
; dnames
++) {
407 if (da_matchname(dap
, *dnames
)) {
413 length
= snprintf(buf
, size
, "%s%s", dap
->da_devname
, sep
);
416 length
+= snprintf(buf
+ length
, size
- length
, "%s%s",
417 dap
->da_devtype
, sep
);
421 _update_zonename(dargs
, dap
);
422 if ((dap
->da_devopts
== NULL
) || ((dap
->da_devopts
->length
== 1) &&
423 (strcmp(dap
->da_devopts
->data
->key
, DA_RESERVED
) == 0))) {
424 length
+= snprintf(buf
+ length
, size
- length
, "%s%s",
427 if (_kva2str(dap
->da_devopts
, buf
+ length
, size
- length
,
428 KV_ASSIGN
, (char *)osep
) != 0)
430 length
= strlen(buf
);
436 length
+= snprintf(buf
+ length
, size
- length
, "%s%s",
440 length
+= snprintf(buf
+ length
, size
- length
, "%s%s",
441 dap
->da_devauth
? dap
->da_devauth
: DA_ANYUSER
, sep
);
444 length
+= snprintf(buf
+ length
, size
- length
, "%s\n",
445 dap
->da_devexec
? dap
->da_devexec
: "");
454 * calls da2str to break given devalloc_t into printable entry.
455 * returns pointer to decoded entry, NULL on error.
458 _da2strentry(da_args
*dargs
, devalloc_t
*dap
)
462 if ((sep
= (strentry_t
*)malloc(sizeof (strentry_t
))) == NULL
)
464 if (_da2str(dargs
, dap
, sep
->se_str
, sizeof (sep
->se_str
),
465 KV_DELIMITER
"\\\n\t", KV_TOKEN_DELIMIT
"\\\n\t") != 0) {
474 * converts da_defs_t into a printable string.
475 * returns 0 on success, -1 on error.
478 _def2str(da_defs_t
*da_defs
, char *buf
, int size
, const char *sep
)
482 length
= snprintf(buf
, size
, "%s%s", da_defs
->devtype
, sep
);
485 if (da_defs
->devopts
) {
486 if (_kva2str(da_defs
->devopts
, buf
+ length
, size
- length
,
487 KV_ASSIGN
, KV_DELIMITER
) != 0)
489 length
= strlen(buf
);
499 * calls _def2str to break given da_defs_t into printable entry.
500 * returns pointer decoded entry, NULL on error.
503 _def2strentry(da_defs_t
*da_defs
)
507 if ((sep
= (strentry_t
*)malloc(sizeof (strentry_t
))) == NULL
)
509 if (_def2str(da_defs
, sep
->se_str
, sizeof (sep
->se_str
),
510 KV_TOKEN_DELIMIT
) != 0) {
520 * cycles through all defattr entries, stores them in memory. removes
521 * entries with the given search_key (device type).
522 * returns 0 if given entry not found, 1 if given entry removed, 2 on
526 _build_defattrs(da_args
*dargs
, strentry_t
**head_defent
)
530 strentry_t
*tail_str
, *tmp_str
;
533 while ((da_defs
= getdadefent()) != NULL
) {
534 rc
= !(strcmp(da_defs
->devtype
, dargs
->devinfo
->devtype
));
535 if (rc
&& dargs
->optflag
& DA_ADD
&&
536 !(dargs
->optflag
& DA_FORCE
)) {
538 * During DA_ADD, we keep an existing entry unless
539 * we have DA_FORCE set to override that entry.
541 dargs
->optflag
|= DA_NO_OVERRIDE
;
545 tmp_str
= _def2strentry(da_defs
);
546 if (tmp_str
== NULL
) {
547 freedadefent(da_defs
);
551 /* retaining defattr entry: tmp_str->se_str */
552 tmp_str
->se_next
= NULL
;
553 if (*head_defent
== NULL
) {
554 *head_defent
= tail_str
= tmp_str
;
556 tail_str
->se_next
= tmp_str
;
560 freedadefent(da_defs
);
568 * We have to handle the "standard" types in devlist differently than
569 * other devices, which are not covered by our auto-naming conventions.
571 * buf must be a buffer of size DA_MAX_NAME + 1
574 da_std_type(da_args
*dargs
, char *namebuf
)
576 char *type
= dargs
->devinfo
->devtype
;
579 system_labeled
= is_system_labeled();
581 /* check safely for sizes */
582 if (strcmp(DA_AUDIO_TYPE
, type
) == 0) {
583 (void) strlcpy(namebuf
, DA_AUDIO_NAME
, DA_MAXNAME
);
586 if (strcmp(DA_CD_TYPE
, type
) == 0) {
588 (void) strlcpy(namebuf
, DA_CD_NAME
, DA_MAXNAME
);
590 (void) strlcpy(namebuf
, DA_CD_TYPE
, DA_MAXNAME
);
593 if (strcmp(DA_FLOPPY_TYPE
, type
) == 0) {
595 (void) strlcpy(namebuf
, DA_FLOPPY_NAME
, DA_MAXNAME
);
597 (void) strlcpy(namebuf
, DA_FLOPPY_TYPE
, DA_MAXNAME
);
600 if (strcmp(DA_TAPE_TYPE
, type
) == 0) {
602 (void) strlcpy(namebuf
, DA_TAPE_NAME
, DA_MAXNAME
);
604 (void) strlcpy(namebuf
, DA_TAPE_TYPE
, DA_MAXNAME
);
607 if (strcmp(DA_RMDISK_TYPE
, type
) == 0) {
608 (void) strlcpy(namebuf
, DA_RMDISK_NAME
, DA_MAXNAME
);
616 * allocatable: returns
617 * -1 if no auths field,
618 * 0 if not allocatable (marked '*')
619 * 1 if not marked '*'
622 allocatable(da_args
*dargs
)
625 if (!dargs
->devinfo
->devauths
)
627 if (strcmp("*", dargs
->devinfo
->devauths
) == 0)
635 * If dargs->optflag & DA_EVENT, does not assume the dargs list is
636 * complete or completely believable, since devfsadm caches
637 * ONLY what it has been exposed to via syseventd.
639 * Cycles through all the entries in the /etc files, stores them
640 * in memory, takes note of device->dname numbers (e.g. rmdisk0,
643 * Cycles through again, adds dargs entry
644 * with the name tname%d (lowest unused number for the device type)
645 * to the list of things for the caller to write out to a file,
646 * IFF it is a new entry.
648 * It is an error for it to already be there, if it is allocatable.
651 * Returns 0 if successful and 2 on error.
653 * Returns 0 if not found, 1 if found, 2 on error.
656 _rebuild_lists(da_args
*dargs
, strentry_t
**head_devallocp
,
657 strentry_t
**head_devmapp
)
660 devalloc_t
*devallocp
;
662 strentry_t
*tail_str
;
664 uint64_t tmp_bitmap
= 0;
670 int is_allocatable
= 1;
671 char new_devname
[DA_MAXNAME
+ 1];
672 char defname
[DA_MAXNAME
+ 1]; /* default name for type */
673 char errmsg
[DA_MAXNAME
+ 1 + (PATH_MAX
* 2) + 80];
675 if (dargs
->optflag
& (DA_MAPS_ONLY
| DA_ALLOC_ONLY
))
678 if (dargs
->optflag
& DA_FORCE
)
681 if (dargs
->optflag
& DA_ADD
) {
682 stdtype
= da_std_type(dargs
, defname
);
683 is_allocatable
= allocatable(dargs
);
686 /* read both files, maps first so we can compare actual devices */
688 /* build device_maps */
690 while ((devmapp
= getdmapent()) != NULL
) {
691 suffix
= DA_MAX_DEVNO
+ 1;
692 if ((rc
= dmap_matchtype(devmapp
, dargs
->devinfo
->devtype
))
694 if (dargs
->optflag
& DA_REMOVE
) {
695 if ((devmapp
->dmap_devarray
== NULL
) ||
696 (devmapp
->dmap_devarray
[0] == NULL
)) {
697 freedmapent(devmapp
);
701 realname
= dmap_physname(devmapp
);
702 if (realname
== NULL
) {
703 freedmapent(devmapp
);
707 if (strstr(realname
, dargs
->devinfo
->devlist
)
709 /* if need to free and safe to free */
710 if (dargs
->devinfo
->devname
!= NULL
&&
711 (dargs
->optflag
& DA_EVENT
) != 0)
712 free(dargs
->devinfo
->devname
);
713 dargs
->devinfo
->devname
=
714 strdup(devmapp
->dmap_devname
);
716 freedmapent(devmapp
);
717 continue; /* don't retain */
719 } else if (dargs
->optflag
& DA_ADD
) {
721 * Need to know which suffixes are in use
723 rc
= (dmap_exact_dev(devmapp
,
724 dargs
->devinfo
->devlist
, &suffix
));
728 * Same type, different device. Record
729 * device suffix already in use, if
732 if ((suffix
< DA_MAX_DEVNO
&&
733 suffix
!= -1) && stdtype
)
735 (uint64_t)(1LL << suffix
);
736 } else if ((rc
== 1) && !is_allocatable
) {
740 * Match allocatable on add is an error
741 * or mapping attempt returned error
743 (void) snprintf(errmsg
, sizeof (errmsg
),
744 "Cannot add %s on node %s",
745 dargs
->devinfo
->devtype
,
746 devmapp
->dmap_devname
);
747 syslog(LOG_ERR
, "%s", errmsg
);
748 freedmapent(devmapp
);
753 /* add other transaction types as needed */
755 } else if ((dargs
->optflag
& DA_ADD
) &&
756 (stdtype
|| is_allocatable
) &&
757 dmap_exact_dev(devmapp
, dargs
->devinfo
->devlist
,
760 * no dups w/o DA_FORCE, even if type differs,
761 * if there is a chance this operation is
762 * machine-driven. The 5 "standard types"
763 * can be machine-driven adds, and tend to
766 (void) snprintf(errmsg
, sizeof (errmsg
),
767 "Cannot add %s on node %s type %s",
768 dargs
->devinfo
->devtype
,
769 devmapp
->dmap_devname
,
770 devmapp
->dmap_devtype
);
771 syslog(LOG_ERR
, "%s", errmsg
);
772 freedmapent(devmapp
);
777 tmp_str
= _dmap2strentry(devmapp
);
778 if (tmp_str
== NULL
) {
779 freedmapent(devmapp
);
783 /* retaining devmap entry: tmp_str->se_str */
784 tmp_str
->se_next
= NULL
;
785 if (*head_devmapp
== NULL
) {
786 *head_devmapp
= tail_str
= tmp_str
;
788 tail_str
->se_next
= tmp_str
;
791 freedmapent(devmapp
);
796 * No need to rewrite the files if the item to be removed is not
797 * in the files -- wait for another call on another darg.
799 if ((dargs
->optflag
& DA_REMOVE
) && !found
)
803 if (dargs
->optflag
& DA_ADD
) {
806 * If we got here from an event, or from devfsadm,
807 * we know the stored devname is a useless guess,
808 * since the files had not been read when the name
809 * was chosen, and we don't keep them anywhere else
810 * that is sufficiently definitive.
813 for (tmp
= 0; tmp
<= DA_MAX_DEVNO
; tmp
++)
814 if (!(tmp_bitmap
& (1LL << tmp
)))
816 /* Future: support more than 64 hotplug devices per type? */
817 if (tmp
> DA_MAX_DEVNO
)
821 * Let the caller choose the name unless BOTH the name and
822 * device type one of: cdrom, floppy, audio, rmdisk, or tape.
823 * (or sr, fd for unlabeled)
825 len
= strlen(defname
);
827 (strncmp(dargs
->devinfo
->devname
, defname
, len
) == 0)) {
828 (void) snprintf(new_devname
, DA_MAXNAME
+ 1, "%s%u",
830 /* if need to free and safe to free */
831 if (dargs
->devinfo
->devname
!= NULL
&&
832 (dargs
->optflag
& DA_EVENT
) != 0)
833 free(dargs
->devinfo
->devname
);
834 dargs
->devinfo
->devname
= strdup(new_devname
);
839 * Now adjust devalloc list to match devmaps
840 * Note we now have the correct devname for da_match to use.
843 while ((devallocp
= getdaent()) != NULL
) {
844 rc
= da_match(devallocp
, dargs
);
846 if (dargs
->optflag
& DA_ADD
) {
847 /* logging is on if DA_EVENT is set */
848 if (dargs
->optflag
& DA_EVENT
) {
849 (void) snprintf(errmsg
, sizeof (errmsg
),
850 "%s and %s out of sync,"
853 devallocp
->da_devname
, DEVALLOC
);
854 syslog(LOG_ERR
, "%s", errmsg
);
856 freedaent(devallocp
);
859 } else if (dargs
->optflag
& DA_REMOVE
) {
860 /* make list w/o this entry */
861 freedaent(devallocp
);
865 tmp_str
= _da2strentry(dargs
, devallocp
);
866 if (tmp_str
== NULL
) {
867 freedaent(devallocp
);
871 /* retaining devalloc entry: tmp_str->se_str */
872 tmp_str
->se_next
= NULL
;
873 if (*head_devallocp
== NULL
) {
874 *head_devallocp
= tail_str
= tmp_str
;
876 tail_str
->se_next
= tmp_str
;
879 freedaent(devallocp
);
883 /* the caller needs to know if a remove needs to rewrite files */
884 if (dargs
->optflag
& DA_REMOVE
)
885 return (1); /* 0 and 2 cases returned earlier */
887 return (0); /* Successful DA_ADD */
892 * Cycles through all the entries, stores them in memory. removes entries
893 * with the given search_key (device name or type).
894 * returns 0 if given entry not found, 1 if given entry removed, 2 on
898 _build_lists(da_args
*dargs
, strentry_t
**head_devallocp
,
899 strentry_t
**head_devmapp
)
903 devalloc_t
*devallocp
;
905 strentry_t
*tail_str
;
908 if (dargs
->optflag
& DA_MAPS_ONLY
)
911 /* build device_allocate */
913 while ((devallocp
= getdaent()) != NULL
) {
914 rc
= da_match(devallocp
, dargs
);
915 /* if in _build_lists and DA_ADD is set, so is DA_FORCE */
917 tmp_str
= _da2strentry(dargs
, devallocp
);
918 if (tmp_str
== NULL
) {
919 freedaent(devallocp
);
923 /* retaining devalloc entry: tmp_str->se_str */
924 tmp_str
->se_next
= NULL
;
925 if (*head_devallocp
== NULL
) {
926 *head_devallocp
= tail_str
= tmp_str
;
928 tail_str
->se_next
= tmp_str
;
934 freedaent(devallocp
);
939 if (dargs
->optflag
& DA_ALLOC_ONLY
)
942 /* build device_maps */
945 while ((devmapp
= getdmapent()) != NULL
) {
946 rc
= dm_match(devmapp
, dargs
);
948 tmp_str
= _dmap2strentry(devmapp
);
949 if (tmp_str
== NULL
) {
950 freedmapent(devmapp
);
954 /* retaining devmap entry: tmp_str->se_str */
955 tmp_str
->se_next
= NULL
;
956 if (*head_devmapp
== NULL
) {
957 *head_devmapp
= tail_str
= tmp_str
;
959 tail_str
->se_next
= tmp_str
;
963 freedmapent(devmapp
);
967 /* later code cleanup may cause the use of "found" in other cases */
968 if (dargs
->optflag
& DA_REMOVE
)
975 * writes current entries to devalloc_defaults.
978 _write_defattrs(FILE *fp
, strentry_t
*head_defent
)
982 for (tmp_str
= head_defent
; tmp_str
!= NULL
;
983 tmp_str
= tmp_str
->se_next
) {
984 (void) fputs(tmp_str
->se_str
, fp
);
985 (void) fputs("\n", fp
);
991 * _write_device_allocate -
992 * writes current entries in the list to device_allocate.
996 _write_device_allocate(char *odevalloc
, FILE *dafp
, strentry_t
*head_devallocp
)
999 strentry_t
*tmp_str
, *old_str
;
1002 (void) fseek(dafp
, (off_t
)0, SEEK_SET
);
1005 * if the devalloc on/off string existed before,
1006 * put it back before anything else.
1007 * we need to check for the string only if the file
1010 if (stat(odevalloc
, &dastat
) == 0) {
1013 (void) fputs(DA_OFF_STR
, dafp
);
1014 else if (is_on
== 1)
1015 (void) fputs(DA_ON_STR
, dafp
);
1017 tmp_str
= head_devallocp
;
1019 (void) fputs(tmp_str
->se_str
, dafp
);
1020 (void) fputs("\n", dafp
);
1022 tmp_str
= tmp_str
->se_next
;
1028 * _write_device_maps -
1029 * writes current entries in the list to device_maps.
1030 * and frees the strings
1033 _write_device_maps(FILE *dmfp
, strentry_t
*head_devmapp
)
1035 strentry_t
*tmp_str
, *old_str
;
1037 (void) fseek(dmfp
, (off_t
)0, SEEK_SET
);
1039 tmp_str
= head_devmapp
;
1041 (void) fputs(tmp_str
->se_str
, dmfp
);
1042 (void) fputs("\n", dmfp
);
1044 tmp_str
= tmp_str
->se_next
;
1050 * _write_new_defattrs
1051 * writes the new entry to devalloc_defaults.
1052 * returns 0 on success, -1 on error.
1055 _write_new_defattrs(FILE *fp
, da_args
*dargs
)
1058 char *tok
= NULL
, *tokp
= NULL
;
1060 devinfo_t
*devinfo
= dargs
->devinfo
;
1062 if (fseek(fp
, (off_t
)0, SEEK_END
) == (off_t
)-1)
1064 if (!devinfo
->devopts
)
1066 (void) fprintf(fp
, "%s%s", (devinfo
->devtype
? devinfo
->devtype
: ""),
1068 if ((tokp
= (char *)malloc(strlen(devinfo
->devopts
) +1)) != NULL
) {
1069 (void) strcpy(tokp
, devinfo
->devopts
);
1070 if ((tok
= strtok_r(tokp
, KV_DELIMITER
, &lasts
)) != NULL
) {
1071 (void) fprintf(fp
, "%s", tok
);
1074 while ((tok
= strtok_r(NULL
, KV_DELIMITER
, &lasts
)) != NULL
) {
1076 (void) fprintf(fp
, "%s", KV_DELIMITER
);
1077 (void) fprintf(fp
, "%s", tok
);
1081 (void) fprintf(fp
, "%s", devinfo
->devopts
);
1088 * _write_new_entry -
1089 * writes the new devalloc_t to device_allocate or the new devmap_t to
1091 * returns 0 on success, -1 on error.
1094 _write_new_entry(FILE *fp
, da_args
*dargs
, int flag
)
1097 char *tok
= NULL
, *tokp
= NULL
;
1099 devinfo_t
*devinfo
= dargs
->devinfo
;
1101 if (flag
& DA_MAPS_ONLY
)
1104 if (fseek(fp
, (off_t
)0, SEEK_END
) == (off_t
)-1)
1107 (void) fprintf(fp
, "%s%s\\\n\t",
1108 (devinfo
->devname
? devinfo
->devname
: ""), KV_DELIMITER
);
1109 (void) fprintf(fp
, "%s%s\\\n\t",
1110 (devinfo
->devtype
? devinfo
->devtype
: ""), KV_DELIMITER
);
1111 if (devinfo
->devopts
== NULL
) {
1112 (void) fprintf(fp
, "%s%s\\\n\t", DA_RESERVED
,
1115 if ((tokp
= (char *)malloc(strlen(devinfo
->devopts
) + 1))
1117 (void) strcpy(tokp
, devinfo
->devopts
);
1118 if ((tok
= strtok_r(tokp
, KV_TOKEN_DELIMIT
, &lasts
)) !=
1120 (void) fprintf(fp
, "%s", tok
);
1123 while ((tok
= strtok_r(NULL
, KV_TOKEN_DELIMIT
,
1126 (void) fprintf(fp
, "%s",
1127 KV_TOKEN_DELIMIT
"\\\n\t");
1128 (void) fprintf(fp
, "%s", tok
);
1132 (void) fprintf(fp
, "%s",
1133 KV_DELIMITER
"\\\n\t");
1135 (void) fprintf(fp
, "%s%s", devinfo
->devopts
,
1136 KV_DELIMITER
"\\\n\t");
1139 (void) fprintf(fp
, "%s%s\\\n\t", DA_RESERVED
, KV_DELIMITER
);
1140 (void) fprintf(fp
, "%s%s\\\n\t",
1141 (devinfo
->devauths
? devinfo
->devauths
: DA_ANYUSER
),
1143 (void) fprintf(fp
, "%s\n",
1144 (devinfo
->devexec
? devinfo
->devexec
: KV_DELIMITER
));
1147 if (flag
& DA_ALLOC_ONLY
)
1150 if (fseek(fp
, (off_t
)0, SEEK_END
) == (off_t
)-1)
1153 (void) fprintf(fp
, "%s%s\\\n",
1154 (devinfo
->devname
? devinfo
->devname
: ""), KV_TOKEN_DELIMIT
);
1155 (void) fprintf(fp
, "\t%s%s\\\n",
1156 (devinfo
->devtype
? devinfo
->devtype
: ""), KV_TOKEN_DELIMIT
);
1157 (void) fprintf(fp
, "\t%s\n",
1158 (devinfo
->devlist
? devinfo
->devlist
: KV_TOKEN_DELIMIT
));
1165 * locks the database files; lock can be either broken explicitly by
1166 * closing the fd of the lock file, or it expires automatically at process
1168 * returns fd of the lock file or -1 on error.
1171 _da_lock_devdb(char *rootdir
)
1180 char path
[MAXPATHLEN
];
1181 int size
= sizeof (path
);
1183 if (rootdir
== NULL
) {
1184 lockfile
= DA_DB_LOCK
;
1187 if (snprintf(path
, size
, "%s%s", rootdir
, DA_DB_LOCK
) >= size
)
1192 if ((lockfd
= open(lockfile
, O_RDWR
| O_CREAT
, 0600)) == -1)
1193 /* cannot open lock file */
1196 (void) fchown(lockfd
, DA_UID
, DA_GID
);
1198 if (lseek(lockfd
, (off_t
)0, SEEK_SET
) == -1) {
1199 /* cannot position lock file */
1200 (void) close(lockfd
);
1206 seed
= (uint_t
)gethrtime();
1207 ret
= lockf(lockfd
, F_TLOCK
, 0);
1209 (void) utime(lockfile
, NULL
);
1212 if ((errno
!= EACCES
) && (errno
!= EAGAIN
)) {
1213 /* cannot set lock */
1214 (void) close(lockfd
);
1218 retry_sleep
= rand_r(&seed
)/((RAND_MAX
+ 2)/3) + count
;
1219 (void) sleep(retry_sleep
);
1228 * opens one or both database files - device_allocate, device_maps - in
1229 * the specified mode.
1230 * locks the database files; lock is either broken explicitly by the
1231 * caller by closing the lock file fd, or it expires automatically at
1232 * process termination.
1233 * writes the file pointer of opened file in the input args - dafp, dmfp.
1234 * returns fd of the lock file on success, -2 if database file does not
1235 * exist, -1 on other errors.
1238 da_open_devdb(char *rootdir
, FILE **dafp
, FILE **dmfp
, int flag
)
1246 char path
[MAXPATHLEN
];
1249 if ((dafp
== NULL
) && (dmfp
== NULL
))
1252 if (flag
& DA_RDWR
) {
1255 } else if (flag
& DA_RDONLY
) {
1260 if ((lockfd
= _da_lock_devdb(rootdir
)) == -1)
1263 if ((dafp
== NULL
) || (flag
& DA_MAPS_ONLY
))
1269 * open the device allocation file
1271 if (rootdir
== NULL
) {
1274 if (snprintf(path
, sizeof (path
), "%s%s", rootdir
,
1275 DEVALLOC
) >= sizeof (path
)) {
1277 (void) close(lockfd
);
1282 if ((fda
= open(fname
, oflag
, DA_DBMODE
)) == -1) {
1284 (void) close(lockfd
);
1285 return ((errno
== ENOENT
) ? -2 : -1);
1287 if ((devfile
= fdopen(fda
, fmode
)) == NULL
) {
1290 (void) close(lockfd
);
1294 (void) fchmod(fda
, DA_DBMODE
);
1296 if ((flag
& DA_ALLOC_ONLY
))
1302 * open the device map file
1304 if (rootdir
== NULL
) {
1307 if (snprintf(path
, sizeof (path
), "%s%s", rootdir
,
1308 DEVMAP
) >= sizeof (path
)) {
1311 (void) close(lockfd
);
1317 if ((fdm
= open(fname
, oflag
, DA_DBMODE
)) == -1) {
1319 (void) close(lockfd
);
1320 return ((errno
== ENOENT
) ? -2 : -1);
1323 if ((devfile
= fdopen(fdm
, fmode
)) == NULL
) {
1327 (void) close(lockfd
);
1331 (void) fchmod(fdm
, DA_DBMODE
);
1339 * adds either DA_ON_STR or DA_OFF_STR to device_allocate
1340 * returns 0 on success, -1 on error.
1343 _record_on_off(da_args
*dargs
, FILE *tafp
, FILE *dafp
)
1350 int len
= 0, nlen
= 0, plen
= 0;
1354 char line
[MAX_CANON
];
1357 if (dargs
->optflag
& DA_ON
)
1358 actionstr
= DA_ON_STR
;
1360 actionstr
= DA_OFF_STR
;
1361 actionlen
= strlen(actionstr
);
1362 dafd
= fileno(dafp
);
1363 if (fstat(dafd
, &dastat
) == -1)
1366 /* check the old device_allocate for on/off string */
1367 ptr
= fgets(line
, MAX_CANON
, dafp
);
1369 if ((strcmp(line
, DA_ON_STR
) == 0) ||
1370 (strcmp(line
, DA_OFF_STR
) == 0)) {
1372 nsize
= dastat
.st_size
;
1375 if (!ptr
|| !str_found
) {
1377 * the file never had either the on or the off string;
1381 nsize
= dastat
.st_size
+ actionlen
+ 1;
1383 if ((nbuf
= (char *)malloc(nsize
+ 1)) == NULL
)
1386 /* put the on/off string */
1387 (void) strcpy(nbuf
, actionstr
);
1388 nlen
= strlen(nbuf
);
1390 if (ptr
&& !str_found
) {
1391 /* now put the first line that we read in fgets */
1392 nlen
= plen
+ strlen(line
) + 1;
1393 len
= snprintf(nbuf
+ plen
, nlen
- plen
, "%s", line
);
1401 /* now get the rest of the old file */
1402 while (fgets(line
, MAX_CANON
, dafp
) != NULL
) {
1403 nlen
= plen
+ strlen(line
) + 1;
1404 len
= snprintf(nbuf
+ plen
, nlen
- plen
, "%s", line
);
1411 len
= strlen(nbuf
) + 1;
1415 /* write the on/off str + the old device_allocate to the temp file */
1416 if (fwrite(nbuf
, nsize
, nitems
, tafp
) < nitems
) {
1427 * da_update_defattrs -
1428 * writes default attributes to devalloc_defaults
1429 * returns 0 on success, -1 on error.
1432 da_update_defattrs(da_args
*dargs
)
1434 int rc
= 0, lockfd
= 0, tmpfd
= 0;
1435 char *defpath
= DEFATTRS
;
1436 char *tmpdefpath
= TMPATTRS
;
1439 strentry_t
*head_defent
= NULL
;
1443 if ((lockfd
= _da_lock_devdb(NULL
)) == -1)
1445 if ((tmpfd
= open(tmpdefpath
, O_RDWR
|O_CREAT
, DA_DBMODE
)) == -1) {
1446 (void) close(lockfd
);
1449 (void) fchown(tmpfd
, DA_UID
, DA_GID
);
1450 if ((tmpfp
= fdopen(tmpfd
, "r+")) == NULL
) {
1451 (void) close(tmpfd
);
1452 (void) unlink(tmpdefpath
);
1453 (void) close(lockfd
);
1457 * examine all entries, remove an old one if required, check
1458 * if a new one needs to be added.
1460 if (stat(defpath
, &dstat
) == 0) {
1461 if ((rc
= _build_defattrs(dargs
, &head_defent
)) != 0) {
1463 (void) close(tmpfd
);
1464 (void) unlink(tmpdefpath
);
1465 (void) close(lockfd
);
1471 * write back any existing entries.
1473 _write_defattrs(tmpfp
, head_defent
);
1475 if (dargs
->optflag
& DA_ADD
&& !(dargs
->optflag
& DA_NO_OVERRIDE
)) {
1476 /* add new entries */
1477 rc
= _write_new_defattrs(tmpfp
, dargs
);
1478 (void) fclose(tmpfp
);
1480 (void) fclose(tmpfp
);
1482 if (rename(tmpdefpath
, defpath
) != 0) {
1484 (void) unlink(tmpdefpath
);
1486 (void) close(lockfd
);
1492 * da_update_device -
1493 * Writes existing entries and the SINGLE change requested by da_args,
1494 * to device_allocate and device_maps.
1495 * Returns 0 on success, -1 on error.
1498 da_update_device(da_args
*dargs
)
1501 int tafd
= -1, tmfd
= -1;
1503 char *rootdir
= NULL
;
1504 char *apathp
= NULL
, *mpathp
= NULL
;
1505 char *dapathp
= NULL
, *dmpathp
= NULL
;
1506 char apath
[MAXPATHLEN
], mpath
[MAXPATHLEN
];
1507 char dapath
[MAXPATHLEN
], dmpath
[MAXPATHLEN
];
1508 FILE *tafp
= NULL
, *tmfp
= NULL
, *dafp
= NULL
;
1511 strentry_t
*head_devmapp
= NULL
;
1512 strentry_t
*head_devallocp
= NULL
;
1517 rootdir
= dargs
->rootdir
;
1518 devinfo
= dargs
->devinfo
;
1521 * adding/removing entries should be done in both
1522 * device_allocate and device_maps. updates can be
1523 * done in both or either of the files.
1525 if (dargs
->optflag
& DA_ADD
|| dargs
->optflag
& DA_REMOVE
) {
1526 if (dargs
->optflag
& DA_ALLOC_ONLY
||
1527 dargs
->optflag
& DA_MAPS_ONLY
)
1532 * name, type and list are required fields for adding a new
1535 if ((dargs
->optflag
& DA_ADD
) &&
1536 ((devinfo
->devname
== NULL
) ||
1537 (devinfo
->devtype
== NULL
) ||
1538 (devinfo
->devlist
== NULL
))) {
1542 if (rootdir
!= NULL
) {
1543 if (snprintf(apath
, sizeof (apath
), "%s%s", rootdir
,
1544 TMPALLOC
) >= sizeof (apath
))
1547 if (snprintf(dapath
, sizeof (dapath
), "%s%s", rootdir
,
1548 DEVALLOC
) >= sizeof (dapath
))
1551 if (!(dargs
->optflag
& DA_ALLOC_ONLY
)) {
1552 if (snprintf(mpath
, sizeof (mpath
), "%s%s", rootdir
,
1553 TMPMAP
) >= sizeof (mpath
))
1556 if (snprintf(dmpath
, sizeof (dmpath
), "%s%s", rootdir
,
1557 DEVMAP
) >= sizeof (dmpath
))
1568 if (dargs
->optflag
& DA_MAPS_ONLY
)
1572 * Check if we are here just to record on/off status of
1573 * device_allocation.
1575 if (dargs
->optflag
& DA_ON
|| dargs
->optflag
& DA_OFF
)
1576 lockfd
= da_open_devdb(dargs
->rootdir
, &dafp
, NULL
,
1577 DA_RDONLY
|DA_ALLOC_ONLY
);
1579 lockfd
= _da_lock_devdb(rootdir
);
1583 if ((tafd
= open(apathp
, O_RDWR
|O_CREAT
, DA_DBMODE
)) == -1) {
1584 (void) close(lockfd
);
1585 (void) fclose(dafp
);
1588 (void) fchown(tafd
, DA_UID
, DA_GID
);
1589 if ((tafp
= fdopen(tafd
, "r+")) == NULL
) {
1591 (void) unlink(apathp
);
1592 (void) fclose(dafp
);
1593 (void) close(lockfd
);
1598 * We don't need to parse the file if we are here just to record
1599 * on/off status of device_allocation.
1601 if (dargs
->optflag
& DA_ON
|| dargs
->optflag
& DA_OFF
) {
1602 if (_record_on_off(dargs
, tafp
, dafp
) == -1) {
1604 (void) unlink(apathp
);
1605 (void) fclose(dafp
);
1606 (void) close(lockfd
);
1609 (void) fclose(dafp
);
1614 * If reacting to a hotplug, read the file entries,
1615 * figure out what dname (tname + a new number) goes to the
1616 * device being added/removed, and create a good head_devallocp and
1617 * head_devmapp with everything good still in it (_rebuild_lists)
1619 * Else examine all the entries, remove an old one if it is
1620 * a duplicate with a device being added, returning the
1621 * remaining list (_build_lists.)
1623 * We need to do this only if the file exists already.
1625 * Once we have built these lists, we need to free the strings
1626 * in the head_* arrays before returning.
1628 if (stat(dapathp
, &dastat
) == 0) {
1629 /* for device allocation, the /etc files are the "master" */
1630 if ((dargs
->optflag
& (DA_ADD
| DA_EVENT
)) &&
1631 (!(dargs
->optflag
& DA_FORCE
)))
1632 rc
= _rebuild_lists(dargs
, &head_devallocp
,
1635 rc
= _build_lists(dargs
, &head_devallocp
,
1638 if (rc
!= 0 && rc
!= 1) {
1640 (void) unlink(apathp
);
1641 (void) close(lockfd
);
1647 if ((dargs
->optflag
& DA_REMOVE
) && (rc
== 0)) {
1649 (void) unlink(apathp
);
1650 (void) close(lockfd
);
1654 * TODO: clean up the workings of DA_UPDATE.
1655 * Due to da_match looking at fields that are missing
1656 * in dargs for DA_UPDATE, the da_match call returns no match,
1657 * but due to the way _da2str combines the devalloc_t info with
1658 * the *dargs info, the DA_ADD_ZONE and DA_REMOVE_ZONE work.
1660 * This would not scale if any type of update was ever needed
1665 * Write out devallocp along with the devalloc on/off string.
1667 _write_device_allocate(dapathp
, tafp
, head_devallocp
);
1669 if (dargs
->optflag
& DA_ALLOC_ONLY
)
1673 if ((tmfd
= open(mpathp
, O_RDWR
|O_CREAT
, DA_DBMODE
)) == -1) {
1675 (void) unlink(apathp
);
1676 (void) close(lockfd
);
1679 (void) fchown(tmfd
, DA_UID
, DA_GID
);
1680 if ((tmfp
= fdopen(tmfd
, "r+")) == NULL
) {
1682 (void) unlink(apathp
);
1684 (void) unlink(mpathp
);
1685 (void) close(lockfd
);
1690 * Write back any non-removed pre-existing entries.
1692 if (head_devmapp
!= NULL
)
1693 _write_device_maps(tmfp
, head_devmapp
);
1697 * Add any new entries here.
1699 if (dargs
->optflag
& DA_ADD
&& !(dargs
->optflag
& DA_NO_OVERRIDE
)) {
1700 /* add any new entries */
1701 rc
= _write_new_entry(tafp
, dargs
, DA_ALLOC_ONLY
);
1702 (void) fclose(tafp
);
1705 rc
= _write_new_entry(tmfp
, dargs
, DA_MAPS_ONLY
);
1706 (void) fclose(tmfp
);
1709 (void) fclose(tafp
);
1711 (void) fclose(tmfp
);
1715 if (!(dargs
->optflag
& DA_MAPS_ONLY
)) {
1716 if (rename(apathp
, dapathp
) != 0) {
1718 (void) unlink(apathp
);
1721 if (!(dargs
->optflag
& DA_ALLOC_ONLY
)) {
1722 if (rename(mpathp
, dmpathp
) != 0) {
1724 (void) unlink(mpathp
);
1728 (void) close(lockfd
);
1735 * adds new /dev link name to the linked list of devices.
1736 * returns 0 if link added successfully, -1 on error.
1739 da_add_list(devlist_t
*dlist
, char *link
, int new_instance
, int flag
)
1744 char *dtype
, *dexec
, *tname
, *kval
;
1745 char *minstr
= NULL
, *maxstr
= NULL
;
1746 char dname
[DA_MAXNAME
+ 1];
1748 deventry_t
*dentry
= NULL
, *nentry
= NULL
, *pentry
= NULL
;
1751 if (dlist
== NULL
|| link
== NULL
)
1755 if (flag
& DA_AUDIO
) {
1756 dentry
= dlist
->audio
;
1757 tname
= DA_AUDIO_NAME
;
1758 dtype
= DA_AUDIO_TYPE
;
1759 dexec
= DA_DEFAULT_AUDIO_CLEAN
;
1760 } else if (flag
& DA_CD
) {
1764 dexec
= DA_DEFAULT_DISK_CLEAN
;
1765 } else if (flag
& DA_FLOPPY
) {
1766 dentry
= dlist
->floppy
;
1767 tname
= DA_FLOPPY_NAME
;
1768 dtype
= DA_FLOPPY_TYPE
;
1769 dexec
= DA_DEFAULT_DISK_CLEAN
;
1770 } else if (flag
& DA_TAPE
) {
1771 dentry
= dlist
->tape
;
1772 tname
= DA_TAPE_NAME
;
1773 dtype
= DA_TAPE_TYPE
;
1774 dexec
= DA_DEFAULT_TAPE_CLEAN
;
1775 } else if (flag
& DA_RMDISK
) {
1776 dentry
= dlist
->rmdisk
;
1777 tname
= DA_RMDISK_NAME
;
1778 dtype
= DA_RMDISK_TYPE
;
1779 dexec
= DA_DEFAULT_DISK_CLEAN
;
1784 for (nentry
= dentry
; nentry
!= NULL
; nentry
= nentry
->next
) {
1786 (void) sscanf(nentry
->devinfo
.devname
, "%*[a-z]%d", &instance
);
1787 if (nentry
->devinfo
.instance
== new_instance
)
1789 * Add the new link name to the list of links
1790 * that the device 'dname' has.
1795 if (nentry
== NULL
) {
1797 * Either this is the first entry ever, or no matching entry
1798 * was found. Create a new one and add to the list.
1800 if (dentry
== NULL
) /* first entry ever */
1802 else /* no matching entry */
1804 (void) snprintf(dname
, sizeof (dname
), "%s%d", tname
, instance
);
1805 if ((nentry
= (deventry_t
*)malloc(sizeof (deventry_t
))) ==
1809 pentry
->next
= nentry
;
1811 nentry
->devinfo
.devname
= strdup(dname
);
1812 nentry
->devinfo
.devtype
= dtype
;
1813 nentry
->devinfo
.devauths
= DEFAULT_DEV_ALLOC_AUTH
;
1814 nentry
->devinfo
.devexec
= dexec
;
1815 nentry
->devinfo
.instance
= new_instance
;
1817 * Look for default label range, authorizations and cleaning
1818 * program in devalloc_defaults. If label range is not
1819 * specified in devalloc_defaults, assume it to be admin_low
1822 minstr
= DA_DEFAULT_MIN
;
1823 maxstr
= DA_DEFAULT_MAX
;
1825 if (da_defs
= getdadeftype(nentry
->devinfo
.devtype
)) {
1826 kva
= da_defs
->devopts
;
1827 if ((kval
= kva_match(kva
, DAOPT_MINLABEL
)) != NULL
)
1828 minstr
= strdup(kval
);
1829 if ((kval
= kva_match(kva
, DAOPT_MAXLABEL
)) != NULL
)
1830 maxstr
= strdup(kval
);
1831 if ((kval
= kva_match(kva
, DAOPT_AUTHS
)) != NULL
)
1832 nentry
->devinfo
.devauths
= strdup(kval
);
1833 if ((kval
= kva_match(kva
, DAOPT_CSCRIPT
)) != NULL
)
1834 nentry
->devinfo
.devexec
= strdup(kval
);
1835 freedadefent(da_defs
);
1839 nlen
= strlen(DAOPT_MINLABEL
) + strlen(KV_ASSIGN
) +
1840 strlen(minstr
) + strlen(KV_TOKEN_DELIMIT
) +
1841 strlen(DAOPT_MAXLABEL
) + strlen(KV_ASSIGN
) + strlen(maxstr
)
1842 + 1; /* +1 for terminator */
1843 if (kval
= (char *)malloc(nlen
))
1844 (void) snprintf(kval
, nlen
, "%s%s%s%s%s%s%s",
1845 DAOPT_MINLABEL
, KV_ASSIGN
, minstr
, KV_TOKEN_DELIMIT
,
1846 DAOPT_MAXLABEL
, KV_ASSIGN
, maxstr
);
1847 nentry
->devinfo
.devopts
= kval
;
1849 nentry
->devinfo
.devlist
= NULL
;
1850 nentry
->next
= NULL
;
1853 nlen
= strlen(link
) + 1; /* +1 terminator */
1854 if (nentry
->devinfo
.devlist
) {
1855 plen
= strlen(nentry
->devinfo
.devlist
);
1856 nlen
= nlen
+ plen
+ 1; /* +1 for blank to separate entries */
1861 if ((nentry
->devinfo
.devlist
=
1862 (char *)realloc(nentry
->devinfo
.devlist
, nlen
)) == NULL
) {
1864 free(nentry
->devinfo
.devname
);
1867 pentry
->next
= NULL
;
1873 (void) snprintf(nentry
->devinfo
.devlist
, nlen
, "%s", link
);
1875 (void) snprintf(nentry
->devinfo
.devlist
+ plen
, nlen
- plen
,
1878 if (pentry
== NULL
) {
1880 * This is the first entry of this device type.
1882 if (flag
& DA_AUDIO
)
1883 dlist
->audio
= nentry
;
1884 else if (flag
& DA_CD
)
1886 else if (flag
& DA_FLOPPY
)
1887 dlist
->floppy
= nentry
;
1888 else if (flag
& DA_TAPE
)
1889 dlist
->tape
= nentry
;
1890 else if (flag
& DA_RMDISK
)
1891 dlist
->rmdisk
= nentry
;
1899 * removes a /dev link name from the linked list of devices.
1900 * returns type of device if link for that device removed
1901 * successfully, else returns -1 on error.
1902 * if all links for a device are removed, stores that device
1906 da_remove_list(devlist_t
*dlist
, char *link
, int type
, char *devname
, int size
)
1910 int nlen
, plen
, slen
;
1911 char *lasts
, *lname
, *oldlist
;
1913 deventry_t
*dentry
, *current
, *prev
;
1917 else if (link
== NULL
)
1919 else if (strstr(link
, DA_AUDIO_NAME
) || strstr(link
, DA_SOUND_NAME
))
1921 else if (strstr(link
, "dsk") || strstr(link
, "rdsk") ||
1922 strstr(link
, "sr") || strstr(link
, "rsr"))
1924 else if (strstr(link
, "fd") || strstr(link
, "rfd") ||
1925 strstr(link
, "diskette") || strstr(link
, "rdiskette"))
1927 else if (strstr(link
, DA_TAPE_NAME
))
1934 dentry
= dlist
->audio
;
1940 dentry
= dlist
->floppy
;
1943 dentry
= dlist
->tape
;
1946 dentry
= dlist
->rmdisk
;
1952 if ((type
!= NULL
) && (link
== NULL
)) {
1953 for (current
= dentry
, prev
= dentry
; current
!= NULL
;
1954 current
= current
->next
) {
1955 oldlist
= strdup(current
->devinfo
.devlist
);
1956 for (lname
= strtok_r(oldlist
, " ", &lasts
);
1958 lname
= strtok_r(NULL
, " ", &lasts
)) {
1959 if (stat(lname
, &rmstat
) != 0) {
1969 for (current
= dentry
, prev
= dentry
; current
!= NULL
;
1970 current
= current
->next
) {
1971 plen
= strlen(current
->devinfo
.devlist
);
1972 nlen
= strlen(link
);
1974 if (strcmp(current
->devinfo
.devlist
, link
) == 0) {
1975 /* last name in the list */
1980 if (strstr(current
->devinfo
.devlist
, link
)) {
1981 nlen
= plen
- nlen
+ 1;
1982 oldlist
= strdup(current
->devinfo
.devlist
);
1983 if ((current
->devinfo
.devlist
=
1984 (char *)realloc(current
->devinfo
.devlist
,
1989 current
->devinfo
.devlist
[0] = '\0';
1990 nlen
= plen
= slen
= 0;
1991 for (lname
= strtok_r(oldlist
, " ", &lasts
);
1993 lname
= strtok_r(NULL
, " ", &lasts
)) {
1994 if (strcmp(lname
, link
) == 0)
1996 nlen
= strlen(lname
) + plen
+ 1;
1999 snprintf(current
->devinfo
.devlist
,
2003 snprintf(current
->devinfo
.devlist
+
2004 plen
, nlen
- plen
, " %s", lname
);
2006 plen
= plen
+ slen
+ 1;
2015 if (remove_dev
== 1) {
2016 (void) strlcpy(devname
, current
->devinfo
.devname
, size
);
2017 free(current
->devinfo
.devname
);
2018 free(current
->devinfo
.devlist
);
2019 current
->devinfo
.devname
= current
->devinfo
.devlist
= NULL
;
2020 prev
->next
= current
->next
;
2024 if ((remove_dev
== 1) && (prev
->devinfo
.devname
== NULL
)) {
2027 * what we removed above was the first entry
2028 * in the list. make the next entry to be the
2031 current
= prev
->next
;
2034 * the matching entry was the only entry in the list
2039 if (flag
& DA_AUDIO
)
2040 dlist
->audio
= current
;
2041 else if (flag
& DA_CD
)
2042 dlist
->cd
= current
;
2043 else if (flag
& DA_FLOPPY
)
2044 dlist
->floppy
= current
;
2045 else if (flag
& DA_TAPE
)
2046 dlist
->tape
= current
;
2047 else if (flag
& DA_RMDISK
)
2048 dlist
->rmdisk
= current
;
2055 * da_rm_list_entry -
2057 * The adding of devnames to a devlist and the removal of a
2058 * device are not symmetrical -- hot_cleanup gives a /devices
2059 * name which is used to remove the dentry whose links all point to
2060 * that /devices entry.
2062 * The link argument is present if available to make debugging
2065 * da_rm_list_entry removes an entry from the linked list of devices.
2067 * Returns 1 if the devname was removed successfully,
2068 * 0 if not found, -1 for error.
2072 da_rm_list_entry(devlist_t
*dlist
, char *link
, int type
, char *devname
)
2075 deventry_t
**dentry
, *current
, *prev
;
2079 dentry
= &(dlist
->audio
);
2082 dentry
= &(dlist
->cd
);
2085 dentry
= &(dlist
->floppy
);
2088 dentry
= &(dlist
->tape
);
2091 dentry
= &(dlist
->rmdisk
);
2097 /* Presumably in daemon mode, no need to remove entry, list is empty */
2098 if (*dentry
== (deventry_t
*)NULL
)
2102 for (current
= *dentry
; current
!= NULL
;
2103 prev
= current
, current
= current
->next
) {
2104 if (strcmp(devname
, current
->devinfo
.devname
))
2111 free(current
->devinfo
.devname
);
2112 if (current
->devinfo
.devlist
!= NULL
)
2113 free(current
->devinfo
.devlist
);
2114 if (current
->devinfo
.devopts
!= NULL
)
2115 free(current
->devinfo
.devopts
);
2118 *dentry
= current
->next
;
2120 prev
->next
= current
->next
;
2128 * checks if device allocation feature is turned on.
2129 * returns 1 if on, 0 if off, -1 if status string not
2130 * found in device_allocate.
2140 * debug routine to print device entries.
2143 da_print_device(int flag
, devlist_t
*devlist
)
2145 deventry_t
*entry
, *dentry
;
2148 if (flag
& DA_AUDIO
)
2149 dentry
= devlist
->audio
;
2150 else if (flag
& DA_CD
)
2151 dentry
= devlist
->cd
;
2152 else if (flag
& DA_FLOPPY
)
2153 dentry
= devlist
->floppy
;
2154 else if (flag
& DA_TAPE
)
2155 dentry
= devlist
->tape
;
2156 else if (flag
& DA_RMDISK
)
2157 dentry
= devlist
->rmdisk
;
2161 for (entry
= dentry
; entry
!= NULL
; entry
= entry
->next
) {
2162 devinfo
= &(entry
->devinfo
);
2163 (void) fprintf(stdout
, "name: %s\n", devinfo
->devname
);
2164 (void) fprintf(stdout
, "type: %s\n", devinfo
->devtype
);
2165 (void) fprintf(stdout
, "auth: %s\n", devinfo
->devauths
);
2166 (void) fprintf(stdout
, "exec: %s\n", devinfo
->devexec
);
2167 (void) fprintf(stdout
, "list: %s\n\n", devinfo
->devlist
);