8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libbsm / common / devalloc.c
blobf28f91766adbc5de144cf68c1a3c71cce19342a5
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
23 * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <stdlib.h>
27 #include <ctype.h>
28 #include <unistd.h>
29 #include <limits.h>
30 #include <fcntl.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <utime.h>
34 #include <synch.h>
35 #include <strings.h>
36 #include <string.h>
37 #include <libintl.h>
38 #include <errno.h>
39 #include <auth_list.h>
40 #include <syslog.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];
68 } strentry_t;
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
75 int
76 da_check_logindevperm(char *devname)
78 int ret = 0;
79 int fd = -1;
80 int nlen, plen, slen, lineno, fsize;
81 char line[MAX_CANON];
82 char *field_delims = " \t\n";
83 char *fbuf = NULL;
84 char *ptr, *device;
85 char *lasts = NULL;
86 FILE *fp;
87 struct stat f_stat;
90 * check if /etc/logindevperm exists and get its size
92 if ((fd = open(LOGINDEVPERM, O_RDONLY)) == -1)
93 return (0);
94 if (fstat(fd, &f_stat) != 0) {
95 (void) close(fd);
96 return (0);
98 fsize = f_stat.st_size;
99 if ((fbuf = (char *)malloc(fsize)) == NULL) {
100 (void) close(fd);
101 return (0);
103 if ((fp = fdopen(fd, "rF")) == NULL) {
104 free(fbuf);
105 (void) close(fd);
106 return (0);
110 * read and parse /etc/logindevperm
112 plen = nlen = lineno = 0;
113 while (fgets(line, MAX_CANON, fp) != NULL) {
114 lineno++;
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)
120 /* invalid entry */
121 continue;
122 if ((ptr = strtok_r(NULL, field_delims, &lasts)) == NULL)
123 /* empty device list */
124 continue;
125 nlen = strlen(ptr) + 1; /* +1 terminator */
126 nlen += (plen + 1);
127 if (plen == 0)
128 slen = snprintf(fbuf, nlen, "%s", ptr);
129 else
130 slen = snprintf(fbuf + plen, nlen - plen, ":%s", ptr);
131 if (slen >= fsize) {
132 fbuf[0] = '\0';
133 (void) fclose(fp);
134 return (slen);
136 plen += slen;
138 (void) fclose(fp);
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 -
147 * /dev/xx
148 * /dev/xx*
149 * /dev/dir/xx
150 * /dev/dir/xx*
151 * /dev/dir/"*"
153 if (strcmp(device, devname) == 0) {
154 /* /dev/xx, /dev/dir/xx */
155 free(fbuf);
156 return (1);
158 if ((ptr = strrchr(device, KV_WILDCHAR)) != NULL) {
159 /* all wildcard types */
160 *ptr = '\0';
161 if (strncmp(device, devname, strlen(device)) == 0) {
162 free(fbuf);
163 return (1);
166 device = strtok_r(NULL, ":", &lasts);
169 return (ret);
173 * _da_read_file -
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,
180 int flag)
182 int fd = -1;
183 int fsize = 0;
184 time_t newtime;
185 struct stat f_stat;
187 if (flag & DA_FORCE)
188 *ftime = 0;
190 /* check the size and the time stamp on the file */
191 if (rw_rdlock(flock) != 0)
192 return (-1);
193 if (stat(fname, &f_stat) != 0) {
194 (void) rw_unlock(flock);
195 return (-1);
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
204 * is a forced read.
205 * read file into the buffer with rw lock.
207 if (rw_wrlock(flock) != 0)
208 return (-1);
209 if ((fd = open(fname, O_RDONLY)) == -1) {
210 (void) rw_unlock(flock);
211 return (-1);
213 if (*fbuf != NULL) {
214 free(*fbuf);
215 *fbuf = NULL;
217 if ((*fbuf = malloc(fsize)) == NULL) {
218 (void) rw_unlock(flock);
219 (void) close(fd);
220 return (-1);
222 if (read(fd, *fbuf, fsize) < fsize) {
223 free(*fbuf);
224 (void) rw_unlock(flock);
225 (void) close(fd);
226 return (-1);
228 (void) rw_unlock(flock);
230 * verify that the file did not change just after we read it.
232 if (rw_rdlock(flock) != 0) {
233 free(*fbuf);
234 (void) close(fd);
235 return (-1);
237 if (stat(fname, &f_stat) != 0) {
238 free(*fbuf);
239 (void) rw_unlock(flock);
240 (void) close(fd);
241 return (-1);
243 fsize = f_stat.st_size;
244 newtime = f_stat.st_mtime;
245 (void) rw_unlock(flock);
246 (void) close(fd);
247 *ftime = newtime;
250 return (fsize);
254 * _update_zonename -
255 * add/remove current zone's name to the given devalloc_t.
257 void
258 _update_zonename(da_args *dargs, devalloc_t *dap)
260 int i, j;
261 int oldsize, newsize;
262 int has_zonename = 0;
263 char *zonename;
264 kva_t *newkva, *oldkva;
265 kv_t *newdata, *olddata;
266 devinfo_t *devinfo;
268 devinfo = dargs->devinfo;
269 oldkva = dap->da_devopts;
270 if (oldkva == NULL) {
271 if (dargs->optflag & DA_REMOVE_ZONE)
272 return;
273 if (dargs->optflag & DA_ADD_ZONE) {
274 newkva = _str2kva(devinfo->devopts, KV_ASSIGN,
275 KV_TOKEN_DELIMIT);
276 if (newkva != NULL)
277 dap->da_devopts = newkva;
278 return;
281 newsize = oldsize = oldkva->length;
282 if (kva_match(oldkva, DAOPT_ZONE))
283 has_zonename = 1;
284 if (dargs->optflag & DA_ADD_ZONE) {
285 if ((zonename = index(devinfo->devopts, '=')) == NULL)
286 return;
287 zonename++;
288 if (has_zonename) {
289 (void) _insert2kva(oldkva, DAOPT_ZONE, zonename);
290 return;
292 newsize += 1;
293 } else if (dargs->optflag & DA_REMOVE_ZONE) {
294 if (has_zonename) {
295 newsize -= 1;
296 if (newsize == 0) {
298 * If zone name was the only key/value pair,
299 * put 'reserved' in the empty slot.
301 _kva_free(oldkva);
302 dap->da_devopts = NULL;
303 return;
305 } else {
306 return;
309 newkva = _new_kva(newsize);
310 newkva->length = 0;
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))
316 continue;
317 newdata[j].key = strdup(olddata[i].key);
318 newdata[j].value = strdup(olddata[i].value);
319 newkva->length++;
320 j++;
322 if (dargs->optflag & DA_ADD_ZONE) {
323 newdata[j].key = strdup(DAOPT_ZONE);
324 newdata[j].value = strdup(zonename);
325 newkva->length++;
327 _kva_free(oldkva);
328 dap->da_devopts = newkva;
332 * _dmap2str -
333 * converts a device_map entry into a printable string
334 * returns 0 on success, -1 on error.
336 /*ARGSUSED*/
337 static int
338 _dmap2str(devmap_t *dmp, char *buf, int size, const char *sep)
340 int length;
342 length = snprintf(buf, size, "%s%s", dmp->dmap_devname, sep);
343 if (length >= size)
344 return (-1);
345 length += snprintf(buf + length, size - length, "%s%s",
346 dmp->dmap_devtype, sep);
347 if (length >= size)
348 return (-1);
349 length += snprintf(buf + length, size - length, "%s\n",
350 dmp->dmap_devlist);
351 if (length >= size)
352 return (-1);
353 return (0);
357 * _dmap2strentry -
358 * calls dmap2str to break given devmap_t into printable entry.
359 * returns pointer to decoded entry, NULL on error.
361 static strentry_t *
362 _dmap2strentry(devmap_t *devmapp)
364 strentry_t *sep;
366 if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL)
367 return (NULL);
368 if (_dmap2str(devmapp, sep->se_str, sizeof (sep->se_str),
369 KV_TOKEN_DELIMIT"\\\n\t") != 0) {
370 free(sep);
371 return (NULL);
373 return (sep);
377 * fix_optstr -
378 * removes trailing ':' from buf.
380 void
381 fix_optstr(char *buf)
383 char *p = NULL;
385 if (p = rindex(buf, ':'))
386 *p = ';';
390 * _da2str -
391 * converts a device_allocate entry into a printable string
392 * returns 0 on success, -1 on error.
394 static int
395 _da2str(da_args *dargs, devalloc_t *dap, char *buf, int size, const char *sep,
396 const char *osep)
398 int length;
399 int matching_entry = 0;
400 char **dnames;
402 if (dargs->optflag & DA_UPDATE &&
403 (dargs->optflag & DA_ADD_ZONE ||
404 dargs->optflag & DA_REMOVE_ZONE) &&
405 dargs->devnames) {
406 for (dnames = dargs->devnames; *dnames != NULL; dnames++) {
407 if (da_matchname(dap, *dnames)) {
408 matching_entry = 1;
409 break;
413 length = snprintf(buf, size, "%s%s", dap->da_devname, sep);
414 if (length >= size)
415 return (-1);
416 length += snprintf(buf + length, size - length, "%s%s",
417 dap->da_devtype, sep);
418 if (length >= size)
419 return (-1);
420 if (matching_entry)
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",
425 DA_RESERVED, sep);
426 } else {
427 if (_kva2str(dap->da_devopts, buf + length, size - length,
428 KV_ASSIGN, (char *)osep) != 0)
429 return (-1);
430 length = strlen(buf);
432 if (dap->da_devopts)
433 fix_optstr(buf);
434 if (length >= size)
435 return (-1);
436 length += snprintf(buf + length, size - length, "%s%s",
437 DA_RESERVED, sep);
438 if (length >= size)
439 return (-1);
440 length += snprintf(buf + length, size - length, "%s%s",
441 dap->da_devauth ? dap->da_devauth : DA_ANYUSER, sep);
442 if (length >= size)
443 return (-1);
444 length += snprintf(buf + length, size - length, "%s\n",
445 dap->da_devexec ? dap->da_devexec : "");
446 if (length >= size)
447 return (-1);
449 return (0);
453 * _da2strentry -
454 * calls da2str to break given devalloc_t into printable entry.
455 * returns pointer to decoded entry, NULL on error.
457 static strentry_t *
458 _da2strentry(da_args *dargs, devalloc_t *dap)
460 strentry_t *sep;
462 if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL)
463 return (NULL);
464 if (_da2str(dargs, dap, sep->se_str, sizeof (sep->se_str),
465 KV_DELIMITER "\\\n\t", KV_TOKEN_DELIMIT "\\\n\t") != 0) {
466 free(sep);
467 return (NULL);
469 return (sep);
473 * _def2str
474 * converts da_defs_t into a printable string.
475 * returns 0 on success, -1 on error.
477 static int
478 _def2str(da_defs_t *da_defs, char *buf, int size, const char *sep)
480 int length;
482 length = snprintf(buf, size, "%s%s", da_defs->devtype, sep);
483 if (length >= size)
484 return (-1);
485 if (da_defs->devopts) {
486 if (_kva2str(da_defs->devopts, buf + length, size - length,
487 KV_ASSIGN, KV_DELIMITER) != 0)
488 return (-1);
489 length = strlen(buf);
491 if (length >= size)
492 return (-1);
494 return (0);
498 * _def2strentry
499 * calls _def2str to break given da_defs_t into printable entry.
500 * returns pointer decoded entry, NULL on error.
502 static strentry_t *
503 _def2strentry(da_defs_t *da_defs)
505 strentry_t *sep;
507 if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL)
508 return (NULL);
509 if (_def2str(da_defs, sep->se_str, sizeof (sep->se_str),
510 KV_TOKEN_DELIMIT) != 0) {
511 free(sep);
512 return (NULL);
515 return (sep);
519 * _build_defattrs
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
523 * error.
525 static int
526 _build_defattrs(da_args *dargs, strentry_t **head_defent)
528 int rc = 0;
529 da_defs_t *da_defs;
530 strentry_t *tail_str, *tmp_str;
532 setdadefent();
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;
542 rc = 0;
544 if (rc == 0) {
545 tmp_str = _def2strentry(da_defs);
546 if (tmp_str == NULL) {
547 freedadefent(da_defs);
548 enddadefent();
549 return (2);
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;
555 } else {
556 tail_str->se_next = tmp_str;
557 tail_str = tmp_str;
560 freedadefent(da_defs);
562 enddadefent();
564 return (rc);
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;
577 int system_labeled;
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);
584 return (1);
586 if (strcmp(DA_CD_TYPE, type) == 0) {
587 if (system_labeled)
588 (void) strlcpy(namebuf, DA_CD_NAME, DA_MAXNAME);
589 else
590 (void) strlcpy(namebuf, DA_CD_TYPE, DA_MAXNAME);
591 return (1);
593 if (strcmp(DA_FLOPPY_TYPE, type) == 0) {
594 if (system_labeled)
595 (void) strlcpy(namebuf, DA_FLOPPY_NAME, DA_MAXNAME);
596 else
597 (void) strlcpy(namebuf, DA_FLOPPY_TYPE, DA_MAXNAME);
598 return (1);
600 if (strcmp(DA_TAPE_TYPE, type) == 0) {
601 if (system_labeled)
602 (void) strlcpy(namebuf, DA_TAPE_NAME, DA_MAXNAME);
603 else
604 (void) strlcpy(namebuf, DA_TAPE_TYPE, DA_MAXNAME);
605 return (1);
607 if (strcmp(DA_RMDISK_TYPE, type) == 0) {
608 (void) strlcpy(namebuf, DA_RMDISK_NAME, DA_MAXNAME);
609 return (1);
611 namebuf[0] = '\0';
612 return (0);
616 * allocatable: returns
617 * -1 if no auths field,
618 * 0 if not allocatable (marked '*')
619 * 1 if not marked '*'
621 static int
622 allocatable(da_args *dargs)
625 if (!dargs->devinfo->devauths)
626 return (-1);
627 if (strcmp("*", dargs->devinfo->devauths) == 0)
628 return (0);
629 return (1);
633 * _rebuild_lists -
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,
641 * rmdisk12)
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.
650 * Add:
651 * Returns 0 if successful and 2 on error.
652 * Remove:
653 * Returns 0 if not found, 1 if found, 2 on error.
655 static int
656 _rebuild_lists(da_args *dargs, strentry_t **head_devallocp,
657 strentry_t **head_devmapp)
659 int rc = 0;
660 devalloc_t *devallocp;
661 devmap_t *devmapp;
662 strentry_t *tail_str;
663 strentry_t *tmp_str;
664 uint64_t tmp_bitmap = 0;
665 uint_t tmp = 0;
666 char *realname;
667 int suffix;
668 int found = 0;
669 int stdtype = 1;
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))
676 return (2);
678 if (dargs->optflag & DA_FORCE)
679 return (2);
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 */
689 setdmapent();
690 while ((devmapp = getdmapent()) != NULL) {
691 suffix = DA_MAX_DEVNO + 1;
692 if ((rc = dmap_matchtype(devmapp, dargs->devinfo->devtype))
693 == 1) {
694 if (dargs->optflag & DA_REMOVE) {
695 if ((devmapp->dmap_devarray == NULL) ||
696 (devmapp->dmap_devarray[0] == NULL)) {
697 freedmapent(devmapp);
698 enddmapent();
699 return (2);
701 realname = dmap_physname(devmapp);
702 if (realname == NULL) {
703 freedmapent(devmapp);
704 enddmapent();
705 return (2);
707 if (strstr(realname, dargs->devinfo->devlist)
708 != NULL) {
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);
715 found = 1;
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));
726 if (rc == 0) {
728 * Same type, different device. Record
729 * device suffix already in use, if
730 * applicable.
732 if ((suffix < DA_MAX_DEVNO &&
733 suffix != -1) && stdtype)
734 tmp_bitmap |=
735 (uint64_t)(1LL << suffix);
736 } else if ((rc == 1) && !is_allocatable) {
737 rc = 0;
738 } else {
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);
749 enddmapent();
750 return (2);
752 } else
753 /* add other transaction types as needed */
754 return (2);
755 } else if ((dargs->optflag & DA_ADD) &&
756 (stdtype || is_allocatable) &&
757 dmap_exact_dev(devmapp, dargs->devinfo->devlist,
758 &suffix)) {
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
764 * be allocatable.
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);
773 enddmapent();
774 return (2);
777 tmp_str = _dmap2strentry(devmapp);
778 if (tmp_str == NULL) {
779 freedmapent(devmapp);
780 enddmapent();
781 return (2);
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;
787 } else {
788 tail_str->se_next = tmp_str;
789 tail_str = tmp_str;
791 freedmapent(devmapp);
793 enddmapent();
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)
800 return (0);
803 if (dargs->optflag & DA_ADD) {
804 int len;
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)))
815 break;
816 /* Future: support more than 64 hotplug devices per type? */
817 if (tmp > DA_MAX_DEVNO)
818 return (2);
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);
826 if (stdtype &&
827 (strncmp(dargs->devinfo->devname, defname, len) == 0)) {
828 (void) snprintf(new_devname, DA_MAXNAME + 1, "%s%u",
829 defname, tmp);
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.
842 setdaent();
843 while ((devallocp = getdaent()) != NULL) {
844 rc = da_match(devallocp, dargs);
845 if (rc == 1) {
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,"
851 "%s only in %s.",
852 DEVALLOC, DEVMAP,
853 devallocp->da_devname, DEVALLOC);
854 syslog(LOG_ERR, "%s", errmsg);
856 freedaent(devallocp);
857 enddaent();
858 return (2);
859 } else if (dargs->optflag & DA_REMOVE) {
860 /* make list w/o this entry */
861 freedaent(devallocp);
862 continue;
865 tmp_str = _da2strentry(dargs, devallocp);
866 if (tmp_str == NULL) {
867 freedaent(devallocp);
868 enddaent();
869 return (2);
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;
875 } else {
876 tail_str->se_next = tmp_str;
877 tail_str = tmp_str;
879 freedaent(devallocp);
881 enddaent();
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 */
891 * _build_lists -
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
895 * error.
897 static int
898 _build_lists(da_args *dargs, strentry_t **head_devallocp,
899 strentry_t **head_devmapp)
901 int rc = 0;
902 int found = 0;
903 devalloc_t *devallocp;
904 devmap_t *devmapp;
905 strentry_t *tail_str;
906 strentry_t *tmp_str;
908 if (dargs->optflag & DA_MAPS_ONLY)
909 goto dmap_only;
911 /* build device_allocate */
912 setdaent();
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 */
916 if (rc == 0) {
917 tmp_str = _da2strentry(dargs, devallocp);
918 if (tmp_str == NULL) {
919 freedaent(devallocp);
920 enddaent();
921 return (2);
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;
927 } else {
928 tail_str->se_next = tmp_str;
929 tail_str = tmp_str;
931 } else if (rc == 1)
932 found = 1;
934 freedaent(devallocp);
936 enddaent();
938 dmap_only:
939 if (dargs->optflag & DA_ALLOC_ONLY)
940 return (rc);
942 /* build device_maps */
943 rc = 0;
944 setdmapent();
945 while ((devmapp = getdmapent()) != NULL) {
946 rc = dm_match(devmapp, dargs);
947 if (rc == 0) {
948 tmp_str = _dmap2strentry(devmapp);
949 if (tmp_str == NULL) {
950 freedmapent(devmapp);
951 enddmapent();
952 return (2);
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;
958 } else {
959 tail_str->se_next = tmp_str;
960 tail_str = tmp_str;
963 freedmapent(devmapp);
965 enddmapent();
967 /* later code cleanup may cause the use of "found" in other cases */
968 if (dargs->optflag & DA_REMOVE)
969 return (found);
970 return (rc);
974 * _write_defattrs
975 * writes current entries to devalloc_defaults.
977 static void
978 _write_defattrs(FILE *fp, strentry_t *head_defent)
980 strentry_t *tmp_str;
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.
993 * frees the strings
995 static void
996 _write_device_allocate(char *odevalloc, FILE *dafp, strentry_t *head_devallocp)
998 int is_on = -1;
999 strentry_t *tmp_str, *old_str;
1000 struct stat dastat;
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
1008 * exists.
1010 if (stat(odevalloc, &dastat) == 0) {
1011 is_on = da_is_on();
1012 if (is_on == 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;
1018 while (tmp_str) {
1019 (void) fputs(tmp_str->se_str, dafp);
1020 (void) fputs("\n", dafp);
1021 old_str = tmp_str;
1022 tmp_str = tmp_str->se_next;
1023 free(old_str);
1028 * _write_device_maps -
1029 * writes current entries in the list to device_maps.
1030 * and frees the strings
1032 static void
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;
1040 while (tmp_str) {
1041 (void) fputs(tmp_str->se_str, dmfp);
1042 (void) fputs("\n", dmfp);
1043 old_str = tmp_str;
1044 tmp_str = tmp_str->se_next;
1045 free(old_str);
1050 * _write_new_defattrs
1051 * writes the new entry to devalloc_defaults.
1052 * returns 0 on success, -1 on error.
1054 static int
1055 _write_new_defattrs(FILE *fp, da_args *dargs)
1057 int count;
1058 char *tok = NULL, *tokp = NULL;
1059 char *lasts;
1060 devinfo_t *devinfo = dargs->devinfo;
1062 if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
1063 return (-1);
1064 if (!devinfo->devopts)
1065 return (0);
1066 (void) fprintf(fp, "%s%s", (devinfo->devtype ? devinfo->devtype : ""),
1067 KV_TOKEN_DELIMIT);
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);
1072 count = 1;
1074 while ((tok = strtok_r(NULL, KV_DELIMITER, &lasts)) != NULL) {
1075 if (count)
1076 (void) fprintf(fp, "%s", KV_DELIMITER);
1077 (void) fprintf(fp, "%s", tok);
1078 count++;
1080 } else {
1081 (void) fprintf(fp, "%s", devinfo->devopts);
1084 return (0);
1088 * _write_new_entry -
1089 * writes the new devalloc_t to device_allocate or the new devmap_t to
1090 * device_maps.
1091 * returns 0 on success, -1 on error.
1093 static int
1094 _write_new_entry(FILE *fp, da_args *dargs, int flag)
1096 int count;
1097 char *tok = NULL, *tokp = NULL;
1098 char *lasts;
1099 devinfo_t *devinfo = dargs->devinfo;
1101 if (flag & DA_MAPS_ONLY)
1102 goto dmap_only;
1104 if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
1105 return (-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,
1113 KV_DELIMITER);
1114 } else {
1115 if ((tokp = (char *)malloc(strlen(devinfo->devopts) + 1))
1116 != NULL) {
1117 (void) strcpy(tokp, devinfo->devopts);
1118 if ((tok = strtok_r(tokp, KV_TOKEN_DELIMIT, &lasts)) !=
1119 NULL) {
1120 (void) fprintf(fp, "%s", tok);
1121 count = 1;
1123 while ((tok = strtok_r(NULL, KV_TOKEN_DELIMIT,
1124 &lasts)) != NULL) {
1125 if (count)
1126 (void) fprintf(fp, "%s",
1127 KV_TOKEN_DELIMIT "\\\n\t");
1128 (void) fprintf(fp, "%s", tok);
1129 count++;
1131 if (count)
1132 (void) fprintf(fp, "%s",
1133 KV_DELIMITER "\\\n\t");
1134 } else {
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),
1142 KV_DELIMITER);
1143 (void) fprintf(fp, "%s\n",
1144 (devinfo->devexec ? devinfo->devexec : KV_DELIMITER));
1146 dmap_only:
1147 if (flag & DA_ALLOC_ONLY)
1148 return (0);
1150 if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
1151 return (-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));
1160 return (0);
1164 * _da_lock_devdb -
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
1167 * termination.
1168 * returns fd of the lock file or -1 on error.
1171 _da_lock_devdb(char *rootdir)
1173 int lockfd = -1;
1174 int ret;
1175 int count = 0;
1176 int retry = 10;
1177 int retry_sleep;
1178 uint_t seed;
1179 char *lockfile;
1180 char path[MAXPATHLEN];
1181 int size = sizeof (path);
1183 if (rootdir == NULL) {
1184 lockfile = DA_DB_LOCK;
1185 } else {
1186 path[0] = '\0';
1187 if (snprintf(path, size, "%s%s", rootdir, DA_DB_LOCK) >= size)
1188 return (-1);
1189 lockfile = path;
1192 if ((lockfd = open(lockfile, O_RDWR | O_CREAT, 0600)) == -1)
1193 /* cannot open lock file */
1194 return (-1);
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);
1201 return (-1);
1203 errno = 0;
1204 while (retry > 0) {
1205 count++;
1206 seed = (uint_t)gethrtime();
1207 ret = lockf(lockfd, F_TLOCK, 0);
1208 if (ret == 0) {
1209 (void) utime(lockfile, NULL);
1210 return (lockfd);
1212 if ((errno != EACCES) && (errno != EAGAIN)) {
1213 /* cannot set lock */
1214 (void) close(lockfd);
1215 return (-1);
1217 retry--;
1218 retry_sleep = rand_r(&seed)/((RAND_MAX + 2)/3) + count;
1219 (void) sleep(retry_sleep);
1220 errno = 0;
1223 return (-1);
1227 * da_open_devdb -
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)
1240 int oflag = 0;
1241 int fda = -1;
1242 int fdm = -1;
1243 int lockfd = -1;
1244 char *fname;
1245 char *fmode;
1246 char path[MAXPATHLEN];
1247 FILE *devfile;
1249 if ((dafp == NULL) && (dmfp == NULL))
1250 return (-1);
1252 if (flag & DA_RDWR) {
1253 oflag = DA_RDWR;
1254 fmode = "r+F";
1255 } else if (flag & DA_RDONLY) {
1256 oflag = DA_RDONLY;
1257 fmode = "rF";
1260 if ((lockfd = _da_lock_devdb(rootdir)) == -1)
1261 return (-1);
1263 if ((dafp == NULL) || (flag & DA_MAPS_ONLY))
1264 goto dmap_only;
1266 path[0] = '\0';
1269 * open the device allocation file
1271 if (rootdir == NULL) {
1272 fname = DEVALLOC;
1273 } else {
1274 if (snprintf(path, sizeof (path), "%s%s", rootdir,
1275 DEVALLOC) >= sizeof (path)) {
1276 if (lockfd != -1)
1277 (void) close(lockfd);
1278 return (-1);
1280 fname = path;
1282 if ((fda = open(fname, oflag, DA_DBMODE)) == -1) {
1283 if (lockfd != -1)
1284 (void) close(lockfd);
1285 return ((errno == ENOENT) ? -2 : -1);
1287 if ((devfile = fdopen(fda, fmode)) == NULL) {
1288 (void) close(fda);
1289 if (lockfd != -1)
1290 (void) close(lockfd);
1291 return (-1);
1293 *dafp = devfile;
1294 (void) fchmod(fda, DA_DBMODE);
1296 if ((flag & DA_ALLOC_ONLY))
1297 goto out;
1299 dmap_only:
1300 path[0] = '\0';
1302 * open the device map file
1304 if (rootdir == NULL) {
1305 fname = DEVMAP;
1306 } else {
1307 if (snprintf(path, sizeof (path), "%s%s", rootdir,
1308 DEVMAP) >= sizeof (path)) {
1309 (void) close(fda);
1310 if (lockfd != -1)
1311 (void) close(lockfd);
1312 return (-1);
1314 fname = path;
1317 if ((fdm = open(fname, oflag, DA_DBMODE)) == -1) {
1318 if (lockfd != -1)
1319 (void) close(lockfd);
1320 return ((errno == ENOENT) ? -2 : -1);
1323 if ((devfile = fdopen(fdm, fmode)) == NULL) {
1324 (void) close(fdm);
1325 (void) close(fda);
1326 if (lockfd != -1)
1327 (void) close(lockfd);
1328 return (-1);
1330 *dmfp = devfile;
1331 (void) fchmod(fdm, DA_DBMODE);
1333 out:
1334 return (lockfd);
1338 * _record_on_off -
1339 * adds either DA_ON_STR or DA_OFF_STR to device_allocate
1340 * returns 0 on success, -1 on error.
1342 static int
1343 _record_on_off(da_args *dargs, FILE *tafp, FILE *dafp)
1345 int dafd;
1346 int nsize;
1347 int nitems = 1;
1348 int actionlen;
1349 int str_found = 0;
1350 int len = 0, nlen = 0, plen = 0;
1351 char *ptr = NULL;
1352 char *actionstr;
1353 char *nbuf = NULL;
1354 char line[MAX_CANON];
1355 struct stat dastat;
1357 if (dargs->optflag & DA_ON)
1358 actionstr = DA_ON_STR;
1359 else
1360 actionstr = DA_OFF_STR;
1361 actionlen = strlen(actionstr);
1362 dafd = fileno(dafp);
1363 if (fstat(dafd, &dastat) == -1)
1364 return (-1);
1366 /* check the old device_allocate for on/off string */
1367 ptr = fgets(line, MAX_CANON, dafp);
1368 if (ptr != NULL) {
1369 if ((strcmp(line, DA_ON_STR) == 0) ||
1370 (strcmp(line, DA_OFF_STR) == 0)) {
1371 str_found = 1;
1372 nsize = dastat.st_size;
1375 if (!ptr || !str_found) {
1377 * the file never had either the on or the off string;
1378 * make room for it.
1380 str_found = 0;
1381 nsize = dastat.st_size + actionlen + 1;
1383 if ((nbuf = (char *)malloc(nsize + 1)) == NULL)
1384 return (-1);
1385 nbuf[0] = '\0';
1386 /* put the on/off string */
1387 (void) strcpy(nbuf, actionstr);
1388 nlen = strlen(nbuf);
1389 plen = nlen;
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);
1394 if (len >= nsize) {
1395 free(nbuf);
1396 return (-1);
1398 plen += len;
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);
1405 if (len >= nsize) {
1406 free(nbuf);
1407 return (-1);
1409 plen += len;
1411 len = strlen(nbuf) + 1;
1412 if (len < nsize)
1413 nbuf[len] = '\n';
1415 /* write the on/off str + the old device_allocate to the temp file */
1416 if (fwrite(nbuf, nsize, nitems, tafp) < nitems) {
1417 free(nbuf);
1418 return (-1);
1421 free(nbuf);
1423 return (0);
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;
1437 FILE *tmpfp = NULL;
1438 struct stat dstat;
1439 strentry_t *head_defent = NULL;
1441 if (dargs == NULL)
1442 return (0);
1443 if ((lockfd = _da_lock_devdb(NULL)) == -1)
1444 return (-1);
1445 if ((tmpfd = open(tmpdefpath, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
1446 (void) close(lockfd);
1447 return (-1);
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);
1454 return (-1);
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) {
1462 if (rc == 1) {
1463 (void) close(tmpfd);
1464 (void) unlink(tmpdefpath);
1465 (void) close(lockfd);
1466 return (rc);
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);
1479 } else {
1480 (void) fclose(tmpfp);
1482 if (rename(tmpdefpath, defpath) != 0) {
1483 rc = -1;
1484 (void) unlink(tmpdefpath);
1486 (void) close(lockfd);
1488 return (rc);
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)
1500 int rc;
1501 int tafd = -1, tmfd = -1;
1502 int lockfd = -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;
1509 struct stat dastat;
1510 devinfo_t *devinfo;
1511 strentry_t *head_devmapp = NULL;
1512 strentry_t *head_devallocp = NULL;
1514 if (dargs == NULL)
1515 return (0);
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)
1528 return (0);
1532 * name, type and list are required fields for adding a new
1533 * device.
1535 if ((dargs->optflag & DA_ADD) &&
1536 ((devinfo->devname == NULL) ||
1537 (devinfo->devtype == NULL) ||
1538 (devinfo->devlist == NULL))) {
1539 return (-1);
1542 if (rootdir != NULL) {
1543 if (snprintf(apath, sizeof (apath), "%s%s", rootdir,
1544 TMPALLOC) >= sizeof (apath))
1545 return (-1);
1546 apathp = apath;
1547 if (snprintf(dapath, sizeof (dapath), "%s%s", rootdir,
1548 DEVALLOC) >= sizeof (dapath))
1549 return (-1);
1550 dapathp = dapath;
1551 if (!(dargs->optflag & DA_ALLOC_ONLY)) {
1552 if (snprintf(mpath, sizeof (mpath), "%s%s", rootdir,
1553 TMPMAP) >= sizeof (mpath))
1554 return (-1);
1555 mpathp = mpath;
1556 if (snprintf(dmpath, sizeof (dmpath), "%s%s", rootdir,
1557 DEVMAP) >= sizeof (dmpath))
1558 return (-1);
1559 dmpathp = dmpath;
1561 } else {
1562 apathp = TMPALLOC;
1563 dapathp = DEVALLOC;
1564 mpathp = TMPMAP;
1565 dmpathp = DEVMAP;
1568 if (dargs->optflag & DA_MAPS_ONLY)
1569 goto dmap_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);
1578 else
1579 lockfd = _da_lock_devdb(rootdir);
1580 if (lockfd == -1)
1581 return (-1);
1583 if ((tafd = open(apathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
1584 (void) close(lockfd);
1585 (void) fclose(dafp);
1586 return (-1);
1588 (void) fchown(tafd, DA_UID, DA_GID);
1589 if ((tafp = fdopen(tafd, "r+")) == NULL) {
1590 (void) close(tafd);
1591 (void) unlink(apathp);
1592 (void) fclose(dafp);
1593 (void) close(lockfd);
1594 return (-1);
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) {
1603 (void) close(tafd);
1604 (void) unlink(apathp);
1605 (void) fclose(dafp);
1606 (void) close(lockfd);
1607 return (-1);
1609 (void) fclose(dafp);
1610 goto out;
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,
1633 &head_devmapp);
1634 else
1635 rc = _build_lists(dargs, &head_devallocp,
1636 &head_devmapp);
1638 if (rc != 0 && rc != 1) {
1639 (void) close(tafd);
1640 (void) unlink(apathp);
1641 (void) close(lockfd);
1642 return (-1);
1644 } else
1645 rc = 0;
1647 if ((dargs->optflag & DA_REMOVE) && (rc == 0)) {
1648 (void) close(tafd);
1649 (void) unlink(apathp);
1650 (void) close(lockfd);
1651 return (0);
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
1661 * from the daemon.
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)
1670 goto out;
1672 dmap_only:
1673 if ((tmfd = open(mpathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
1674 (void) close(tafd);
1675 (void) unlink(apathp);
1676 (void) close(lockfd);
1677 return (-1);
1679 (void) fchown(tmfd, DA_UID, DA_GID);
1680 if ((tmfp = fdopen(tmfd, "r+")) == NULL) {
1681 (void) close(tafd);
1682 (void) unlink(apathp);
1683 (void) close(tmfd);
1684 (void) unlink(mpathp);
1685 (void) close(lockfd);
1686 return (-1);
1690 * Write back any non-removed pre-existing entries.
1692 if (head_devmapp != NULL)
1693 _write_device_maps(tmfp, head_devmapp);
1695 out:
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);
1704 if (rc == 0)
1705 rc = _write_new_entry(tmfp, dargs, DA_MAPS_ONLY);
1706 (void) fclose(tmfp);
1707 } else {
1708 if (tafp)
1709 (void) fclose(tafp);
1710 if (tmfp)
1711 (void) fclose(tmfp);
1714 rc = 0;
1715 if (!(dargs->optflag & DA_MAPS_ONLY)) {
1716 if (rename(apathp, dapathp) != 0) {
1717 rc = -1;
1718 (void) unlink(apathp);
1721 if (!(dargs->optflag & DA_ALLOC_ONLY)) {
1722 if (rename(mpathp, dmpathp) != 0) {
1723 rc = -1;
1724 (void) unlink(mpathp);
1728 (void) close(lockfd);
1730 return (rc);
1734 * da_add_list -
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)
1741 int instance;
1742 int nlen, plen;
1743 int new_entry = 0;
1744 char *dtype, *dexec, *tname, *kval;
1745 char *minstr = NULL, *maxstr = NULL;
1746 char dname[DA_MAXNAME + 1];
1747 kva_t *kva;
1748 deventry_t *dentry = NULL, *nentry = NULL, *pentry = NULL;
1749 da_defs_t *da_defs;
1751 if (dlist == NULL || link == NULL)
1752 return (-1);
1754 dname[0] = '\0';
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) {
1761 dentry = dlist->cd;
1762 tname = DA_CD_NAME;
1763 dtype = DA_CD_TYPE;
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;
1780 } else {
1781 return (-1);
1784 for (nentry = dentry; nentry != NULL; nentry = nentry->next) {
1785 pentry = nentry;
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.
1792 break;
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 */
1801 instance = 0;
1802 else /* no matching entry */
1803 instance++;
1804 (void) snprintf(dname, sizeof (dname), "%s%d", tname, instance);
1805 if ((nentry = (deventry_t *)malloc(sizeof (deventry_t))) ==
1806 NULL)
1807 return (-1);
1808 if (pentry != NULL)
1809 pentry->next = nentry;
1810 new_entry = 1;
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
1820 * to admin_high.
1822 minstr = DA_DEFAULT_MIN;
1823 maxstr = DA_DEFAULT_MAX;
1824 setdadefent();
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);
1837 enddadefent();
1838 kval = NULL;
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 */
1857 } else {
1858 plen = 0;
1861 if ((nentry->devinfo.devlist =
1862 (char *)realloc(nentry->devinfo.devlist, nlen)) == NULL) {
1863 if (new_entry) {
1864 free(nentry->devinfo.devname);
1865 free(nentry);
1866 if (pentry != NULL)
1867 pentry->next = NULL;
1869 return (-1);
1872 if (plen == 0)
1873 (void) snprintf(nentry->devinfo.devlist, nlen, "%s", link);
1874 else
1875 (void) snprintf(nentry->devinfo.devlist + plen, nlen - plen,
1876 " %s", link);
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)
1885 dlist->cd = nentry;
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;
1894 return (0);
1898 * da_remove_list -
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
1903 * name in devname.
1906 da_remove_list(devlist_t *dlist, char *link, int type, char *devname, int size)
1908 int flag;
1909 int remove_dev = 0;
1910 int nlen, plen, slen;
1911 char *lasts, *lname, *oldlist;
1912 struct stat rmstat;
1913 deventry_t *dentry, *current, *prev;
1915 if (type != NULL)
1916 flag = type;
1917 else if (link == NULL)
1918 return (-1);
1919 else if (strstr(link, DA_AUDIO_NAME) || strstr(link, DA_SOUND_NAME))
1920 flag = DA_AUDIO;
1921 else if (strstr(link, "dsk") || strstr(link, "rdsk") ||
1922 strstr(link, "sr") || strstr(link, "rsr"))
1923 flag = DA_CD;
1924 else if (strstr(link, "fd") || strstr(link, "rfd") ||
1925 strstr(link, "diskette") || strstr(link, "rdiskette"))
1926 flag = DA_FLOPPY;
1927 else if (strstr(link, DA_TAPE_NAME))
1928 flag = DA_TAPE;
1929 else
1930 flag = DA_RMDISK;
1932 switch (type) {
1933 case DA_AUDIO:
1934 dentry = dlist->audio;
1935 break;
1936 case DA_CD:
1937 dentry = dlist->cd;
1938 break;
1939 case DA_FLOPPY:
1940 dentry = dlist->floppy;
1941 break;
1942 case DA_TAPE:
1943 dentry = dlist->tape;
1944 break;
1945 case DA_RMDISK:
1946 dentry = dlist->rmdisk;
1947 break;
1948 default:
1949 return (-1);
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);
1957 lname != NULL;
1958 lname = strtok_r(NULL, " ", &lasts)) {
1959 if (stat(lname, &rmstat) != 0) {
1960 remove_dev = 1;
1961 goto remove_dev;
1964 prev = current;
1966 return (-1);
1969 for (current = dentry, prev = dentry; current != NULL;
1970 current = current->next) {
1971 plen = strlen(current->devinfo.devlist);
1972 nlen = strlen(link);
1973 if (plen == nlen) {
1974 if (strcmp(current->devinfo.devlist, link) == 0) {
1975 /* last name in the list */
1976 remove_dev = 1;
1977 break;
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,
1985 nlen)) == NULL) {
1986 free(oldlist);
1987 return (-1);
1989 current->devinfo.devlist[0] = '\0';
1990 nlen = plen = slen = 0;
1991 for (lname = strtok_r(oldlist, " ", &lasts);
1992 lname != NULL;
1993 lname = strtok_r(NULL, " ", &lasts)) {
1994 if (strcmp(lname, link) == 0)
1995 continue;
1996 nlen = strlen(lname) + plen + 1;
1997 if (plen == 0) {
1998 slen =
1999 snprintf(current->devinfo.devlist,
2000 nlen, "%s", lname);
2001 } else {
2002 slen =
2003 snprintf(current->devinfo.devlist +
2004 plen, nlen - plen, " %s", lname);
2006 plen = plen + slen + 1;
2008 free(oldlist);
2009 break;
2011 prev = current;
2014 remove_dev:
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;
2021 free(current);
2022 current = NULL;
2024 if ((remove_dev == 1) && (prev->devinfo.devname == NULL)) {
2025 if (prev->next) {
2027 * what we removed above was the first entry
2028 * in the list. make the next entry to be the
2029 * first.
2031 current = prev->next;
2032 } else {
2034 * the matching entry was the only entry in the list
2035 * for this type.
2037 current = NULL;
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;
2051 return (flag);
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
2063 * easier.
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.
2070 /*ARGSUSED*/
2072 da_rm_list_entry(devlist_t *dlist, char *link, int type, char *devname)
2074 int retval = 0;
2075 deventry_t **dentry, *current, *prev;
2077 switch (type) {
2078 case DA_AUDIO:
2079 dentry = &(dlist->audio);
2080 break;
2081 case DA_CD:
2082 dentry = &(dlist->cd);
2083 break;
2084 case DA_FLOPPY:
2085 dentry = &(dlist->floppy);
2086 break;
2087 case DA_TAPE:
2088 dentry = &(dlist->tape);
2089 break;
2090 case DA_RMDISK:
2091 dentry = &(dlist->rmdisk);
2092 break;
2093 default:
2094 return (-1);
2097 /* Presumably in daemon mode, no need to remove entry, list is empty */
2098 if (*dentry == (deventry_t *)NULL)
2099 return (0);
2101 prev = NULL;
2102 for (current = *dentry; current != NULL;
2103 prev = current, current = current->next) {
2104 if (strcmp(devname, current->devinfo.devname))
2105 continue;
2106 retval = 1;
2107 break;
2109 if (retval == 0)
2110 return (0);
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);
2117 if (prev == NULL)
2118 *dentry = current->next;
2119 else
2120 prev->next = current->next;
2122 free(current);
2123 return (retval);
2127 * da_is_on -
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.
2133 da_is_on()
2135 return (getdaon());
2139 * da_print_device -
2140 * debug routine to print device entries.
2142 void
2143 da_print_device(int flag, devlist_t *devlist)
2145 deventry_t *entry, *dentry;
2146 devinfo_t *devinfo;
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;
2158 else
2159 return;
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);