dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / libbsm / common / devalloc.c
blob5c02514d5dd52b6669dc103b2721818e33be8d1d
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>
44 extern int _readbufline(char *, int, char *, int, int *);
45 extern char *strtok_r(char *, const char *, char **);
46 extern char *_strtok_escape(char *, char *, char **);
47 extern int getdaon(void);
48 extern int da_matchname(devalloc_t *, char *);
49 extern int da_match(devalloc_t *, da_args *);
50 extern int dmap_matchname(devmap_t *, char *);
51 extern int dm_match(devmap_t *, da_args *);
52 extern int dmap_matchtype(devmap_t *dmap, char *type);
53 extern int dmap_matchdev(devmap_t *dmap, char *dev);
54 extern int dmap_exact_dev(devmap_t *dmap, char *dev, int *num);
55 extern char *dmap_physname(devmap_t *dmap);
58 * The following structure is for recording old entries to be retained.
59 * We read the entries from the database into a linked list in memory,
60 * then turn around and write them out again.
62 typedef struct strentry {
63 struct strentry *se_next;
64 char se_str[4096 + 1];
65 } strentry_t;
68 * da_check_longindevperm -
69 * reads /etc/logindevperm and checks if specified device is in the file.
70 * returns 1 if specified device found in /etc/logindevperm, else returns 0
72 int
73 da_check_logindevperm(char *devname)
75 int ret = 0;
76 int fd = -1;
77 int nlen, plen, slen, lineno, fsize;
78 char line[MAX_CANON];
79 char *field_delims = " \t\n";
80 char *fbuf = NULL;
81 char *ptr, *device;
82 char *lasts = NULL;
83 FILE *fp;
84 struct stat f_stat;
87 * check if /etc/logindevperm exists and get its size
89 if ((fd = open(LOGINDEVPERM, O_RDONLY)) == -1)
90 return (0);
91 if (fstat(fd, &f_stat) != 0) {
92 (void) close(fd);
93 return (0);
95 fsize = f_stat.st_size;
96 if ((fbuf = (char *)malloc(fsize)) == NULL) {
97 (void) close(fd);
98 return (0);
100 if ((fp = fdopen(fd, "rF")) == NULL) {
101 free(fbuf);
102 (void) close(fd);
103 return (0);
107 * read and parse /etc/logindevperm
109 plen = nlen = lineno = 0;
110 while (fgets(line, MAX_CANON, fp) != NULL) {
111 lineno++;
112 if ((ptr = strchr(line, '#')) != NULL)
113 *ptr = '\0'; /* handle comments */
114 if (strtok_r(line, field_delims, &lasts) == NULL)
115 continue; /* ignore blank lines */
116 if (strtok_r(NULL, field_delims, &lasts) == NULL)
117 /* invalid entry */
118 continue;
119 if ((ptr = strtok_r(NULL, field_delims, &lasts)) == NULL)
120 /* empty device list */
121 continue;
122 nlen = strlen(ptr) + 1; /* +1 terminator */
123 nlen += (plen + 1);
124 if (plen == 0)
125 slen = snprintf(fbuf, nlen, "%s", ptr);
126 else
127 slen = snprintf(fbuf + plen, nlen - plen, ":%s", ptr);
128 if (slen >= fsize) {
129 fbuf[0] = '\0';
130 (void) fclose(fp);
131 return (slen);
133 plen += slen;
135 (void) fclose(fp);
138 * check if devname exists in /etc/logindevperm
140 device = strtok_r(fbuf, ":", &lasts);
141 while (device != NULL) {
143 * device and devname may be one of these types -
144 * /dev/xx
145 * /dev/xx*
146 * /dev/dir/xx
147 * /dev/dir/xx*
148 * /dev/dir/"*"
150 if (strcmp(device, devname) == 0) {
151 /* /dev/xx, /dev/dir/xx */
152 free(fbuf);
153 return (1);
155 if ((ptr = strrchr(device, KV_WILDCHAR)) != NULL) {
156 /* all wildcard types */
157 *ptr = '\0';
158 if (strncmp(device, devname, strlen(device)) == 0) {
159 free(fbuf);
160 return (1);
163 device = strtok_r(NULL, ":", &lasts);
166 return (ret);
170 * _da_read_file -
171 * establishes readers/writer lock on fname; reads in the file if its
172 * contents changed since the last time we read it.
173 * returns size of buffer read, or -1 on failure.
176 _da_read_file(char *fname, char **fbuf, time_t *ftime, rwlock_t *flock,
177 int flag)
179 int fd = -1;
180 int fsize = 0;
181 time_t newtime;
182 struct stat f_stat;
184 if (flag & DA_FORCE)
185 *ftime = 0;
187 /* check the size and the time stamp on the file */
188 if (rw_rdlock(flock) != 0)
189 return (-1);
190 if (stat(fname, &f_stat) != 0) {
191 (void) rw_unlock(flock);
192 return (-1);
194 fsize = f_stat.st_size;
195 newtime = f_stat.st_mtime;
196 (void) rw_unlock(flock);
198 while (newtime > *ftime) {
200 * file has been modified since we last read it; or this
201 * is a forced read.
202 * read file into the buffer with rw lock.
204 if (rw_wrlock(flock) != 0)
205 return (-1);
206 if ((fd = open(fname, O_RDONLY)) == -1) {
207 (void) rw_unlock(flock);
208 return (-1);
210 if (*fbuf != NULL) {
211 free(*fbuf);
212 *fbuf = NULL;
214 if ((*fbuf = malloc(fsize)) == NULL) {
215 (void) rw_unlock(flock);
216 (void) close(fd);
217 return (-1);
219 if (read(fd, *fbuf, fsize) < fsize) {
220 free(*fbuf);
221 (void) rw_unlock(flock);
222 (void) close(fd);
223 return (-1);
225 (void) rw_unlock(flock);
227 * verify that the file did not change just after we read it.
229 if (rw_rdlock(flock) != 0) {
230 free(*fbuf);
231 (void) close(fd);
232 return (-1);
234 if (stat(fname, &f_stat) != 0) {
235 free(*fbuf);
236 (void) rw_unlock(flock);
237 (void) close(fd);
238 return (-1);
240 fsize = f_stat.st_size;
241 newtime = f_stat.st_mtime;
242 (void) rw_unlock(flock);
243 (void) close(fd);
244 *ftime = newtime;
247 return (fsize);
251 * _update_zonename -
252 * add/remove current zone's name to the given devalloc_t.
254 void
255 _update_zonename(da_args *dargs, devalloc_t *dap)
257 int i, j;
258 int oldsize, newsize;
259 int has_zonename = 0;
260 char *zonename;
261 kva_t *newkva, *oldkva;
262 kv_t *newdata, *olddata;
263 devinfo_t *devinfo;
265 devinfo = dargs->devinfo;
266 oldkva = dap->da_devopts;
267 if (oldkva == NULL) {
268 if (dargs->optflag & DA_REMOVE_ZONE)
269 return;
270 if (dargs->optflag & DA_ADD_ZONE) {
271 newkva = _str2kva(devinfo->devopts, KV_ASSIGN,
272 KV_TOKEN_DELIMIT);
273 if (newkva != NULL)
274 dap->da_devopts = newkva;
275 return;
278 newsize = oldsize = oldkva->length;
279 if (kva_match(oldkva, DAOPT_ZONE))
280 has_zonename = 1;
281 if (dargs->optflag & DA_ADD_ZONE) {
282 if ((zonename = index(devinfo->devopts, '=')) == NULL)
283 return;
284 zonename++;
285 if (has_zonename) {
286 (void) _insert2kva(oldkva, DAOPT_ZONE, zonename);
287 return;
289 newsize += 1;
290 } else if (dargs->optflag & DA_REMOVE_ZONE) {
291 if (has_zonename) {
292 newsize -= 1;
293 if (newsize == 0) {
295 * If zone name was the only key/value pair,
296 * put 'reserved' in the empty slot.
298 _kva_free(oldkva);
299 dap->da_devopts = NULL;
300 return;
302 } else {
303 return;
306 newkva = _new_kva(newsize);
307 newkva->length = 0;
308 newdata = newkva->data;
309 olddata = oldkva->data;
310 for (i = 0, j = 0; i < oldsize; i++) {
311 if ((dargs->optflag & DA_REMOVE_ZONE) &&
312 (strcmp(olddata[i].key, DAOPT_ZONE) == 0))
313 continue;
314 newdata[j].key = strdup(olddata[i].key);
315 newdata[j].value = strdup(olddata[i].value);
316 newkva->length++;
317 j++;
319 if (dargs->optflag & DA_ADD_ZONE) {
320 newdata[j].key = strdup(DAOPT_ZONE);
321 newdata[j].value = strdup(zonename);
322 newkva->length++;
324 _kva_free(oldkva);
325 dap->da_devopts = newkva;
329 * _dmap2str -
330 * converts a device_map entry into a printable string
331 * returns 0 on success, -1 on error.
333 /*ARGSUSED*/
334 static int
335 _dmap2str(devmap_t *dmp, char *buf, int size, const char *sep)
337 int length;
339 length = snprintf(buf, size, "%s%s", dmp->dmap_devname, sep);
340 if (length >= size)
341 return (-1);
342 length += snprintf(buf + length, size - length, "%s%s",
343 dmp->dmap_devtype, sep);
344 if (length >= size)
345 return (-1);
346 length += snprintf(buf + length, size - length, "%s\n",
347 dmp->dmap_devlist);
348 if (length >= size)
349 return (-1);
350 return (0);
354 * _dmap2strentry -
355 * calls dmap2str to break given devmap_t into printable entry.
356 * returns pointer to decoded entry, NULL on error.
358 static strentry_t *
359 _dmap2strentry(devmap_t *devmapp)
361 strentry_t *sep;
363 if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL)
364 return (NULL);
365 if (_dmap2str(devmapp, sep->se_str, sizeof (sep->se_str),
366 KV_TOKEN_DELIMIT"\\\n\t") != 0) {
367 free(sep);
368 return (NULL);
370 return (sep);
374 * fix_optstr -
375 * removes trailing ':' from buf.
377 void
378 fix_optstr(char *buf)
380 char *p = NULL;
382 if (p = rindex(buf, ':'))
383 *p = ';';
387 * _da2str -
388 * converts a device_allocate entry into a printable string
389 * returns 0 on success, -1 on error.
391 static int
392 _da2str(da_args *dargs, devalloc_t *dap, char *buf, int size, const char *sep,
393 const char *osep)
395 int length;
396 int matching_entry = 0;
397 char **dnames;
399 if (dargs->optflag & DA_UPDATE &&
400 (dargs->optflag & DA_ADD_ZONE ||
401 dargs->optflag & DA_REMOVE_ZONE) &&
402 dargs->devnames) {
403 for (dnames = dargs->devnames; *dnames != NULL; dnames++) {
404 if (da_matchname(dap, *dnames)) {
405 matching_entry = 1;
406 break;
410 length = snprintf(buf, size, "%s%s", dap->da_devname, sep);
411 if (length >= size)
412 return (-1);
413 length += snprintf(buf + length, size - length, "%s%s",
414 dap->da_devtype, sep);
415 if (length >= size)
416 return (-1);
417 if (matching_entry)
418 _update_zonename(dargs, dap);
419 if ((dap->da_devopts == NULL) || ((dap->da_devopts->length == 1) &&
420 (strcmp(dap->da_devopts->data->key, DA_RESERVED) == 0))) {
421 length += snprintf(buf + length, size - length, "%s%s",
422 DA_RESERVED, sep);
423 } else {
424 if (_kva2str(dap->da_devopts, buf + length, size - length,
425 KV_ASSIGN, (char *)osep) != 0)
426 return (-1);
427 length = strlen(buf);
429 if (dap->da_devopts)
430 fix_optstr(buf);
431 if (length >= size)
432 return (-1);
433 length += snprintf(buf + length, size - length, "%s%s",
434 DA_RESERVED, sep);
435 if (length >= size)
436 return (-1);
437 length += snprintf(buf + length, size - length, "%s%s",
438 dap->da_devauth ? dap->da_devauth : DA_ANYUSER, sep);
439 if (length >= size)
440 return (-1);
441 length += snprintf(buf + length, size - length, "%s\n",
442 dap->da_devexec ? dap->da_devexec : "");
443 if (length >= size)
444 return (-1);
446 return (0);
450 * _da2strentry -
451 * calls da2str to break given devalloc_t into printable entry.
452 * returns pointer to decoded entry, NULL on error.
454 static strentry_t *
455 _da2strentry(da_args *dargs, devalloc_t *dap)
457 strentry_t *sep;
459 if ((sep = (strentry_t *)malloc(sizeof (strentry_t))) == NULL)
460 return (NULL);
461 if (_da2str(dargs, dap, sep->se_str, sizeof (sep->se_str),
462 KV_DELIMITER "\\\n\t", KV_TOKEN_DELIMIT "\\\n\t") != 0) {
463 free(sep);
464 return (NULL);
466 return (sep);
470 * We have to handle the "standard" types in devlist differently than
471 * other devices, which are not covered by our auto-naming conventions.
473 * buf must be a buffer of size DA_MAX_NAME + 1
476 da_std_type(da_args *dargs, char *namebuf)
478 char *type = dargs->devinfo->devtype;
479 /* check safely for sizes */
480 if (strcmp(DA_AUDIO_TYPE, type) == 0) {
481 (void) strlcpy(namebuf, DA_AUDIO_NAME, DA_MAXNAME);
482 return (1);
484 if (strcmp(DA_CD_TYPE, type) == 0) {
485 (void) strlcpy(namebuf, DA_CD_TYPE, DA_MAXNAME);
486 return (1);
488 if (strcmp(DA_FLOPPY_TYPE, type) == 0) {
489 (void) strlcpy(namebuf, DA_FLOPPY_TYPE, DA_MAXNAME);
490 return (1);
492 if (strcmp(DA_TAPE_TYPE, type) == 0) {
493 (void) strlcpy(namebuf, DA_TAPE_TYPE, DA_MAXNAME);
494 return (1);
496 if (strcmp(DA_RMDISK_TYPE, type) == 0) {
497 (void) strlcpy(namebuf, DA_RMDISK_NAME, DA_MAXNAME);
498 return (1);
500 namebuf[0] = '\0';
501 return (0);
505 * allocatable: returns
506 * -1 if no auths field,
507 * 0 if not allocatable (marked '*')
508 * 1 if not marked '*'
510 static int
511 allocatable(da_args *dargs)
514 if (!dargs->devinfo->devauths)
515 return (-1);
516 if (strcmp("*", dargs->devinfo->devauths) == 0)
517 return (0);
518 return (1);
522 * _rebuild_lists -
524 * If dargs->optflag & DA_EVENT, does not assume the dargs list is
525 * complete or completely believable, since devfsadm caches
526 * ONLY what it has been exposed to via syseventd.
528 * Cycles through all the entries in the /etc files, stores them
529 * in memory, takes note of device->dname numbers (e.g. rmdisk0,
530 * rmdisk12)
532 * Cycles through again, adds dargs entry
533 * with the name tname%d (lowest unused number for the device type)
534 * to the list of things for the caller to write out to a file,
535 * IFF it is a new entry.
537 * It is an error for it to already be there, if it is allocatable.
539 * Add:
540 * Returns 0 if successful and 2 on error.
541 * Remove:
542 * Returns 0 if not found, 1 if found, 2 on error.
544 static int
545 _rebuild_lists(da_args *dargs, strentry_t **head_devallocp,
546 strentry_t **head_devmapp)
548 int rc = 0;
549 devalloc_t *devallocp;
550 devmap_t *devmapp;
551 strentry_t *tail_str;
552 strentry_t *tmp_str;
553 uint64_t tmp_bitmap = 0;
554 uint_t tmp = 0;
555 char *realname;
556 int suffix;
557 int found = 0;
558 int stdtype = 1;
559 int is_allocatable = 1;
560 char new_devname[DA_MAXNAME + 1];
561 char defname[DA_MAXNAME + 1]; /* default name for type */
562 char errmsg[DA_MAXNAME + 1 + (PATH_MAX * 2) + 80];
564 if (dargs->optflag & (DA_MAPS_ONLY | DA_ALLOC_ONLY))
565 return (2);
567 if (dargs->optflag & DA_FORCE)
568 return (2);
570 if (dargs->optflag & DA_ADD) {
571 stdtype = da_std_type(dargs, defname);
572 is_allocatable = allocatable(dargs);
575 /* read both files, maps first so we can compare actual devices */
577 /* build device_maps */
578 setdmapent();
579 while ((devmapp = getdmapent()) != NULL) {
580 suffix = DA_MAX_DEVNO + 1;
581 if ((rc = dmap_matchtype(devmapp, dargs->devinfo->devtype))
582 == 1) {
583 if (dargs->optflag & DA_REMOVE) {
584 if ((devmapp->dmap_devarray == NULL) ||
585 (devmapp->dmap_devarray[0] == NULL)) {
586 freedmapent(devmapp);
587 enddmapent();
588 return (2);
590 realname = dmap_physname(devmapp);
591 if (realname == NULL) {
592 freedmapent(devmapp);
593 enddmapent();
594 return (2);
596 if (strstr(realname, dargs->devinfo->devlist)
597 != NULL) {
598 /* if need to free and safe to free */
599 if (dargs->devinfo->devname != NULL &&
600 (dargs->optflag & DA_EVENT) != 0)
601 free(dargs->devinfo->devname);
602 dargs->devinfo->devname =
603 strdup(devmapp->dmap_devname);
604 found = 1;
605 freedmapent(devmapp);
606 continue; /* don't retain */
608 } else if (dargs->optflag & DA_ADD) {
610 * Need to know which suffixes are in use
612 rc = (dmap_exact_dev(devmapp,
613 dargs->devinfo->devlist, &suffix));
615 if (rc == 0) {
617 * Same type, different device. Record
618 * device suffix already in use, if
619 * applicable.
621 if ((suffix < DA_MAX_DEVNO &&
622 suffix != -1) && stdtype)
623 tmp_bitmap |=
624 (uint64_t)(1LL << suffix);
625 } else if ((rc == 1) && !is_allocatable) {
626 rc = 0;
627 } else {
629 * Match allocatable on add is an error
630 * or mapping attempt returned error
632 (void) snprintf(errmsg, sizeof (errmsg),
633 "Cannot add %s on node %s",
634 dargs->devinfo->devtype,
635 devmapp->dmap_devname);
636 syslog(LOG_ERR, "%s", errmsg);
637 freedmapent(devmapp);
638 enddmapent();
639 return (2);
641 } else
642 /* add other transaction types as needed */
643 return (2);
644 } else if ((dargs->optflag & DA_ADD) &&
645 (stdtype || is_allocatable) &&
646 dmap_exact_dev(devmapp, dargs->devinfo->devlist,
647 &suffix)) {
649 * no dups w/o DA_FORCE, even if type differs,
650 * if there is a chance this operation is
651 * machine-driven. The 5 "standard types"
652 * can be machine-driven adds, and tend to
653 * be allocatable.
655 (void) snprintf(errmsg, sizeof (errmsg),
656 "Cannot add %s on node %s type %s",
657 dargs->devinfo->devtype,
658 devmapp->dmap_devname,
659 devmapp->dmap_devtype);
660 syslog(LOG_ERR, "%s", errmsg);
661 freedmapent(devmapp);
662 enddmapent();
663 return (2);
666 tmp_str = _dmap2strentry(devmapp);
667 if (tmp_str == NULL) {
668 freedmapent(devmapp);
669 enddmapent();
670 return (2);
672 /* retaining devmap entry: tmp_str->se_str */
673 tmp_str->se_next = NULL;
674 if (*head_devmapp == NULL) {
675 *head_devmapp = tail_str = tmp_str;
676 } else {
677 tail_str->se_next = tmp_str;
678 tail_str = tmp_str;
680 freedmapent(devmapp);
682 enddmapent();
685 * No need to rewrite the files if the item to be removed is not
686 * in the files -- wait for another call on another darg.
688 if ((dargs->optflag & DA_REMOVE) && !found)
689 return (0);
692 if (dargs->optflag & DA_ADD) {
693 int len;
695 * If we got here from an event, or from devfsadm,
696 * we know the stored devname is a useless guess,
697 * since the files had not been read when the name
698 * was chosen, and we don't keep them anywhere else
699 * that is sufficiently definitive.
702 for (tmp = 0; tmp <= DA_MAX_DEVNO; tmp++)
703 if (!(tmp_bitmap & (1LL << tmp)))
704 break;
705 /* Future: support more than 64 hotplug devices per type? */
706 if (tmp > DA_MAX_DEVNO)
707 return (2);
710 * Let the caller choose the name unless BOTH the name and
711 * device type one of: cdrom, floppy, audio, rmdisk, tape,
712 * sr, or fd.
714 len = strlen(defname);
715 if (stdtype &&
716 (strncmp(dargs->devinfo->devname, defname, len) == 0)) {
717 (void) snprintf(new_devname, DA_MAXNAME + 1, "%s%u",
718 defname, tmp);
719 /* if need to free and safe to free */
720 if (dargs->devinfo->devname != NULL &&
721 (dargs->optflag & DA_EVENT) != 0)
722 free(dargs->devinfo->devname);
723 dargs->devinfo->devname = strdup(new_devname);
728 * Now adjust devalloc list to match devmaps
729 * Note we now have the correct devname for da_match to use.
731 setdaent();
732 while ((devallocp = getdaent()) != NULL) {
733 rc = da_match(devallocp, dargs);
734 if (rc == 1) {
735 if (dargs->optflag & DA_ADD) {
736 /* logging is on if DA_EVENT is set */
737 if (dargs->optflag & DA_EVENT) {
738 (void) snprintf(errmsg, sizeof (errmsg),
739 "%s and %s out of sync,"
740 "%s only in %s.",
741 DEVALLOC, DEVMAP,
742 devallocp->da_devname, DEVALLOC);
743 syslog(LOG_ERR, "%s", errmsg);
745 freedaent(devallocp);
746 enddaent();
747 return (2);
748 } else if (dargs->optflag & DA_REMOVE) {
749 /* make list w/o this entry */
750 freedaent(devallocp);
751 continue;
754 tmp_str = _da2strentry(dargs, devallocp);
755 if (tmp_str == NULL) {
756 freedaent(devallocp);
757 enddaent();
758 return (2);
760 /* retaining devalloc entry: tmp_str->se_str */
761 tmp_str->se_next = NULL;
762 if (*head_devallocp == NULL) {
763 *head_devallocp = tail_str = tmp_str;
764 } else {
765 tail_str->se_next = tmp_str;
766 tail_str = tmp_str;
768 freedaent(devallocp);
770 enddaent();
772 /* the caller needs to know if a remove needs to rewrite files */
773 if (dargs->optflag & DA_REMOVE)
774 return (1); /* 0 and 2 cases returned earlier */
776 return (0); /* Successful DA_ADD */
780 * _build_lists -
781 * Cycles through all the entries, stores them in memory. removes entries
782 * with the given search_key (device name or type).
783 * returns 0 if given entry not found, 1 if given entry removed, 2 on
784 * error.
786 static int
787 _build_lists(da_args *dargs, strentry_t **head_devallocp,
788 strentry_t **head_devmapp)
790 int rc = 0;
791 int found = 0;
792 devalloc_t *devallocp;
793 devmap_t *devmapp;
794 strentry_t *tail_str;
795 strentry_t *tmp_str;
797 if (dargs->optflag & DA_MAPS_ONLY)
798 goto dmap_only;
800 /* build device_allocate */
801 setdaent();
802 while ((devallocp = getdaent()) != NULL) {
803 rc = da_match(devallocp, dargs);
804 /* if in _build_lists and DA_ADD is set, so is DA_FORCE */
805 if (rc == 0) {
806 tmp_str = _da2strentry(dargs, devallocp);
807 if (tmp_str == NULL) {
808 freedaent(devallocp);
809 enddaent();
810 return (2);
812 /* retaining devalloc entry: tmp_str->se_str */
813 tmp_str->se_next = NULL;
814 if (*head_devallocp == NULL) {
815 *head_devallocp = tail_str = tmp_str;
816 } else {
817 tail_str->se_next = tmp_str;
818 tail_str = tmp_str;
820 } else if (rc == 1)
821 found = 1;
823 freedaent(devallocp);
825 enddaent();
827 dmap_only:
828 if (dargs->optflag & DA_ALLOC_ONLY)
829 return (rc);
831 /* build device_maps */
832 rc = 0;
833 setdmapent();
834 while ((devmapp = getdmapent()) != NULL) {
835 rc = dm_match(devmapp, dargs);
836 if (rc == 0) {
837 tmp_str = _dmap2strentry(devmapp);
838 if (tmp_str == NULL) {
839 freedmapent(devmapp);
840 enddmapent();
841 return (2);
843 /* retaining devmap entry: tmp_str->se_str */
844 tmp_str->se_next = NULL;
845 if (*head_devmapp == NULL) {
846 *head_devmapp = tail_str = tmp_str;
847 } else {
848 tail_str->se_next = tmp_str;
849 tail_str = tmp_str;
852 freedmapent(devmapp);
854 enddmapent();
856 /* later code cleanup may cause the use of "found" in other cases */
857 if (dargs->optflag & DA_REMOVE)
858 return (found);
859 return (rc);
863 * _write_device_allocate -
864 * writes current entries in the list to device_allocate.
865 * frees the strings
867 static void
868 _write_device_allocate(char *odevalloc, FILE *dafp, strentry_t *head_devallocp)
870 int is_on = -1;
871 strentry_t *tmp_str, *old_str;
872 struct stat dastat;
874 (void) fseek(dafp, (off_t)0, SEEK_SET);
877 * if the devalloc on/off string existed before,
878 * put it back before anything else.
879 * we need to check for the string only if the file
880 * exists.
882 if (stat(odevalloc, &dastat) == 0) {
883 is_on = da_is_on();
884 if (is_on == 0)
885 (void) fputs(DA_OFF_STR, dafp);
886 else if (is_on == 1)
887 (void) fputs(DA_ON_STR, dafp);
889 tmp_str = head_devallocp;
890 while (tmp_str) {
891 (void) fputs(tmp_str->se_str, dafp);
892 (void) fputs("\n", dafp);
893 old_str = tmp_str;
894 tmp_str = tmp_str->se_next;
895 free(old_str);
900 * _write_device_maps -
901 * writes current entries in the list to device_maps.
902 * and frees the strings
904 static void
905 _write_device_maps(FILE *dmfp, strentry_t *head_devmapp)
907 strentry_t *tmp_str, *old_str;
909 (void) fseek(dmfp, (off_t)0, SEEK_SET);
911 tmp_str = head_devmapp;
912 while (tmp_str) {
913 (void) fputs(tmp_str->se_str, dmfp);
914 (void) fputs("\n", dmfp);
915 old_str = tmp_str;
916 tmp_str = tmp_str->se_next;
917 free(old_str);
922 * _write_new_entry -
923 * writes the new devalloc_t to device_allocate or the new devmap_t to
924 * device_maps.
925 * returns 0 on success, -1 on error.
927 static int
928 _write_new_entry(FILE *fp, da_args *dargs, int flag)
930 int count;
931 char *tok = NULL, *tokp = NULL;
932 char *lasts;
933 devinfo_t *devinfo = dargs->devinfo;
935 if (flag & DA_MAPS_ONLY)
936 goto dmap_only;
938 if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
939 return (-1);
941 (void) fprintf(fp, "%s%s\\\n\t",
942 (devinfo->devname ? devinfo->devname : ""), KV_DELIMITER);
943 (void) fprintf(fp, "%s%s\\\n\t",
944 (devinfo->devtype ? devinfo->devtype : ""), KV_DELIMITER);
945 if (devinfo->devopts == NULL) {
946 (void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED,
947 KV_DELIMITER);
948 } else {
949 if ((tokp = (char *)malloc(strlen(devinfo->devopts) + 1))
950 != NULL) {
951 (void) strcpy(tokp, devinfo->devopts);
952 if ((tok = strtok_r(tokp, KV_TOKEN_DELIMIT, &lasts)) !=
953 NULL) {
954 (void) fprintf(fp, "%s", tok);
955 count = 1;
957 while ((tok = strtok_r(NULL, KV_TOKEN_DELIMIT,
958 &lasts)) != NULL) {
959 if (count)
960 (void) fprintf(fp, "%s",
961 KV_TOKEN_DELIMIT "\\\n\t");
962 (void) fprintf(fp, "%s", tok);
963 count++;
965 if (count)
966 (void) fprintf(fp, "%s",
967 KV_DELIMITER "\\\n\t");
968 } else {
969 (void) fprintf(fp, "%s%s", devinfo->devopts,
970 KV_DELIMITER "\\\n\t");
973 (void) fprintf(fp, "%s%s\\\n\t", DA_RESERVED, KV_DELIMITER);
974 (void) fprintf(fp, "%s%s\\\n\t",
975 (devinfo->devauths ? devinfo->devauths : DA_ANYUSER),
976 KV_DELIMITER);
977 (void) fprintf(fp, "%s\n",
978 (devinfo->devexec ? devinfo->devexec : KV_DELIMITER));
980 dmap_only:
981 if (flag & DA_ALLOC_ONLY)
982 return (0);
984 if (fseek(fp, (off_t)0, SEEK_END) == (off_t)-1)
985 return (-1);
987 (void) fprintf(fp, "%s%s\\\n",
988 (devinfo->devname ? devinfo->devname : ""), KV_TOKEN_DELIMIT);
989 (void) fprintf(fp, "\t%s%s\\\n",
990 (devinfo->devtype ? devinfo->devtype : ""), KV_TOKEN_DELIMIT);
991 (void) fprintf(fp, "\t%s\n",
992 (devinfo->devlist ? devinfo->devlist : KV_TOKEN_DELIMIT));
994 return (0);
998 * _da_lock_devdb -
999 * locks the database files; lock can be either broken explicitly by
1000 * closing the fd of the lock file, or it expires automatically at process
1001 * termination.
1002 * returns fd of the lock file or -1 on error.
1005 _da_lock_devdb(char *rootdir)
1007 int lockfd = -1;
1008 int ret;
1009 int count = 0;
1010 int retry = 10;
1011 int retry_sleep;
1012 uint_t seed;
1013 char *lockfile;
1014 char path[MAXPATHLEN];
1015 int size = sizeof (path);
1017 if (rootdir == NULL) {
1018 lockfile = DA_DB_LOCK;
1019 } else {
1020 path[0] = '\0';
1021 if (snprintf(path, size, "%s%s", rootdir, DA_DB_LOCK) >= size)
1022 return (-1);
1023 lockfile = path;
1026 if ((lockfd = open(lockfile, O_RDWR | O_CREAT, 0600)) == -1)
1027 /* cannot open lock file */
1028 return (-1);
1030 (void) fchown(lockfd, DA_UID, DA_GID);
1032 if (lseek(lockfd, (off_t)0, SEEK_SET) == -1) {
1033 /* cannot position lock file */
1034 (void) close(lockfd);
1035 return (-1);
1037 errno = 0;
1038 while (retry > 0) {
1039 count++;
1040 seed = (uint_t)gethrtime();
1041 ret = lockf(lockfd, F_TLOCK, 0);
1042 if (ret == 0) {
1043 (void) utime(lockfile, NULL);
1044 return (lockfd);
1046 if ((errno != EACCES) && (errno != EAGAIN)) {
1047 /* cannot set lock */
1048 (void) close(lockfd);
1049 return (-1);
1051 retry--;
1052 retry_sleep = rand_r(&seed)/((RAND_MAX + 2)/3) + count;
1053 (void) sleep(retry_sleep);
1054 errno = 0;
1057 return (-1);
1061 * da_open_devdb -
1062 * opens one or both database files - device_allocate, device_maps - in
1063 * the specified mode.
1064 * locks the database files; lock is either broken explicitly by the
1065 * caller by closing the lock file fd, or it expires automatically at
1066 * process termination.
1067 * writes the file pointer of opened file in the input args - dafp, dmfp.
1068 * returns fd of the lock file on success, -2 if database file does not
1069 * exist, -1 on other errors.
1072 da_open_devdb(char *rootdir, FILE **dafp, FILE **dmfp, int flag)
1074 int oflag = 0;
1075 int fda = -1;
1076 int fdm = -1;
1077 int lockfd = -1;
1078 char *fname;
1079 char *fmode;
1080 char path[MAXPATHLEN];
1081 FILE *devfile;
1083 if ((dafp == NULL) && (dmfp == NULL))
1084 return (-1);
1086 if (flag & DA_RDWR) {
1087 oflag = DA_RDWR;
1088 fmode = "r+F";
1089 } else if (flag & DA_RDONLY) {
1090 oflag = DA_RDONLY;
1091 fmode = "rF";
1094 if ((lockfd = _da_lock_devdb(rootdir)) == -1)
1095 return (-1);
1097 if ((dafp == NULL) || (flag & DA_MAPS_ONLY))
1098 goto dmap_only;
1100 path[0] = '\0';
1103 * open the device allocation file
1105 if (rootdir == NULL) {
1106 fname = DEVALLOC;
1107 } else {
1108 if (snprintf(path, sizeof (path), "%s%s", rootdir,
1109 DEVALLOC) >= sizeof (path)) {
1110 if (lockfd != -1)
1111 (void) close(lockfd);
1112 return (-1);
1114 fname = path;
1116 if ((fda = open(fname, oflag, DA_DBMODE)) == -1) {
1117 if (lockfd != -1)
1118 (void) close(lockfd);
1119 return ((errno == ENOENT) ? -2 : -1);
1121 if ((devfile = fdopen(fda, fmode)) == NULL) {
1122 (void) close(fda);
1123 if (lockfd != -1)
1124 (void) close(lockfd);
1125 return (-1);
1127 *dafp = devfile;
1128 (void) fchmod(fda, DA_DBMODE);
1130 if ((flag & DA_ALLOC_ONLY))
1131 goto out;
1133 dmap_only:
1134 path[0] = '\0';
1136 * open the device map file
1138 if (rootdir == NULL) {
1139 fname = DEVMAP;
1140 } else {
1141 if (snprintf(path, sizeof (path), "%s%s", rootdir,
1142 DEVMAP) >= sizeof (path)) {
1143 (void) close(fda);
1144 if (lockfd != -1)
1145 (void) close(lockfd);
1146 return (-1);
1148 fname = path;
1151 if ((fdm = open(fname, oflag, DA_DBMODE)) == -1) {
1152 if (lockfd != -1)
1153 (void) close(lockfd);
1154 return ((errno == ENOENT) ? -2 : -1);
1157 if ((devfile = fdopen(fdm, fmode)) == NULL) {
1158 (void) close(fdm);
1159 (void) close(fda);
1160 if (lockfd != -1)
1161 (void) close(lockfd);
1162 return (-1);
1164 *dmfp = devfile;
1165 (void) fchmod(fdm, DA_DBMODE);
1167 out:
1168 return (lockfd);
1172 * _record_on_off -
1173 * adds either DA_ON_STR or DA_OFF_STR to device_allocate
1174 * returns 0 on success, -1 on error.
1176 static int
1177 _record_on_off(da_args *dargs, FILE *tafp, FILE *dafp)
1179 int dafd;
1180 int nsize;
1181 int nitems = 1;
1182 int actionlen;
1183 int str_found = 0;
1184 int len = 0, nlen = 0, plen = 0;
1185 char *ptr = NULL;
1186 char *actionstr;
1187 char *nbuf = NULL;
1188 char line[MAX_CANON];
1189 struct stat dastat;
1191 if (dargs->optflag & DA_ON)
1192 actionstr = DA_ON_STR;
1193 else
1194 actionstr = DA_OFF_STR;
1195 actionlen = strlen(actionstr);
1196 dafd = fileno(dafp);
1197 if (fstat(dafd, &dastat) == -1)
1198 return (-1);
1200 /* check the old device_allocate for on/off string */
1201 ptr = fgets(line, MAX_CANON, dafp);
1202 if (ptr != NULL) {
1203 if ((strcmp(line, DA_ON_STR) == 0) ||
1204 (strcmp(line, DA_OFF_STR) == 0)) {
1205 str_found = 1;
1206 nsize = dastat.st_size;
1209 if (!ptr || !str_found) {
1211 * the file never had either the on or the off string;
1212 * make room for it.
1214 str_found = 0;
1215 nsize = dastat.st_size + actionlen + 1;
1217 if ((nbuf = (char *)malloc(nsize + 1)) == NULL)
1218 return (-1);
1219 nbuf[0] = '\0';
1220 /* put the on/off string */
1221 (void) strcpy(nbuf, actionstr);
1222 nlen = strlen(nbuf);
1223 plen = nlen;
1224 if (ptr && !str_found) {
1225 /* now put the first line that we read in fgets */
1226 nlen = plen + strlen(line) + 1;
1227 len = snprintf(nbuf + plen, nlen - plen, "%s", line);
1228 if (len >= nsize) {
1229 free(nbuf);
1230 return (-1);
1232 plen += len;
1235 /* now get the rest of the old file */
1236 while (fgets(line, MAX_CANON, dafp) != NULL) {
1237 nlen = plen + strlen(line) + 1;
1238 len = snprintf(nbuf + plen, nlen - plen, "%s", line);
1239 if (len >= nsize) {
1240 free(nbuf);
1241 return (-1);
1243 plen += len;
1245 len = strlen(nbuf) + 1;
1246 if (len < nsize)
1247 nbuf[len] = '\n';
1249 /* write the on/off str + the old device_allocate to the temp file */
1250 if (fwrite(nbuf, nsize, nitems, tafp) < nitems) {
1251 free(nbuf);
1252 return (-1);
1255 free(nbuf);
1257 return (0);
1261 * da_update_device -
1262 * Writes existing entries and the SINGLE change requested by da_args,
1263 * to device_allocate and device_maps.
1264 * Returns 0 on success, -1 on error.
1267 da_update_device(da_args *dargs)
1269 int rc;
1270 int tafd = -1, tmfd = -1;
1271 int lockfd = -1;
1272 char *rootdir = NULL;
1273 char *apathp = NULL, *mpathp = NULL;
1274 char *dapathp = NULL, *dmpathp = NULL;
1275 char apath[MAXPATHLEN], mpath[MAXPATHLEN];
1276 char dapath[MAXPATHLEN], dmpath[MAXPATHLEN];
1277 FILE *tafp = NULL, *tmfp = NULL, *dafp = NULL;
1278 struct stat dastat;
1279 devinfo_t *devinfo;
1280 strentry_t *head_devmapp = NULL;
1281 strentry_t *head_devallocp = NULL;
1283 if (dargs == NULL)
1284 return (0);
1286 rootdir = dargs->rootdir;
1287 devinfo = dargs->devinfo;
1290 * adding/removing entries should be done in both
1291 * device_allocate and device_maps. updates can be
1292 * done in both or either of the files.
1294 if (dargs->optflag & DA_ADD || dargs->optflag & DA_REMOVE) {
1295 if (dargs->optflag & DA_ALLOC_ONLY ||
1296 dargs->optflag & DA_MAPS_ONLY)
1297 return (0);
1301 * name, type and list are required fields for adding a new
1302 * device.
1304 if ((dargs->optflag & DA_ADD) &&
1305 ((devinfo->devname == NULL) ||
1306 (devinfo->devtype == NULL) ||
1307 (devinfo->devlist == NULL))) {
1308 return (-1);
1311 if (rootdir != NULL) {
1312 if (snprintf(apath, sizeof (apath), "%s%s", rootdir,
1313 TMPALLOC) >= sizeof (apath))
1314 return (-1);
1315 apathp = apath;
1316 if (snprintf(dapath, sizeof (dapath), "%s%s", rootdir,
1317 DEVALLOC) >= sizeof (dapath))
1318 return (-1);
1319 dapathp = dapath;
1320 if (!(dargs->optflag & DA_ALLOC_ONLY)) {
1321 if (snprintf(mpath, sizeof (mpath), "%s%s", rootdir,
1322 TMPMAP) >= sizeof (mpath))
1323 return (-1);
1324 mpathp = mpath;
1325 if (snprintf(dmpath, sizeof (dmpath), "%s%s", rootdir,
1326 DEVMAP) >= sizeof (dmpath))
1327 return (-1);
1328 dmpathp = dmpath;
1330 } else {
1331 apathp = TMPALLOC;
1332 dapathp = DEVALLOC;
1333 mpathp = TMPMAP;
1334 dmpathp = DEVMAP;
1337 if (dargs->optflag & DA_MAPS_ONLY)
1338 goto dmap_only;
1341 * Check if we are here just to record on/off status of
1342 * device_allocation.
1344 if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF)
1345 lockfd = da_open_devdb(dargs->rootdir, &dafp, NULL,
1346 DA_RDONLY|DA_ALLOC_ONLY);
1347 else
1348 lockfd = _da_lock_devdb(rootdir);
1349 if (lockfd == -1)
1350 return (-1);
1352 if ((tafd = open(apathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
1353 (void) close(lockfd);
1354 (void) fclose(dafp);
1355 return (-1);
1357 (void) fchown(tafd, DA_UID, DA_GID);
1358 if ((tafp = fdopen(tafd, "r+")) == NULL) {
1359 (void) close(tafd);
1360 (void) unlink(apathp);
1361 (void) fclose(dafp);
1362 (void) close(lockfd);
1363 return (-1);
1367 * We don't need to parse the file if we are here just to record
1368 * on/off status of device_allocation.
1370 if (dargs->optflag & DA_ON || dargs->optflag & DA_OFF) {
1371 if (_record_on_off(dargs, tafp, dafp) == -1) {
1372 (void) close(tafd);
1373 (void) unlink(apathp);
1374 (void) fclose(dafp);
1375 (void) close(lockfd);
1376 return (-1);
1378 (void) fclose(dafp);
1379 goto out;
1383 * If reacting to a hotplug, read the file entries,
1384 * figure out what dname (tname + a new number) goes to the
1385 * device being added/removed, and create a good head_devallocp and
1386 * head_devmapp with everything good still in it (_rebuild_lists)
1388 * Else examine all the entries, remove an old one if it is
1389 * a duplicate with a device being added, returning the
1390 * remaining list (_build_lists.)
1392 * We need to do this only if the file exists already.
1394 * Once we have built these lists, we need to free the strings
1395 * in the head_* arrays before returning.
1397 if (stat(dapathp, &dastat) == 0) {
1398 /* for device allocation, the /etc files are the "master" */
1399 if ((dargs->optflag & (DA_ADD| DA_EVENT)) &&
1400 (!(dargs->optflag & DA_FORCE)))
1401 rc = _rebuild_lists(dargs, &head_devallocp,
1402 &head_devmapp);
1403 else
1404 rc = _build_lists(dargs, &head_devallocp,
1405 &head_devmapp);
1407 if (rc != 0 && rc != 1) {
1408 (void) close(tafd);
1409 (void) unlink(apathp);
1410 (void) close(lockfd);
1411 return (-1);
1413 } else
1414 rc = 0;
1416 if ((dargs->optflag & DA_REMOVE) && (rc == 0)) {
1417 (void) close(tafd);
1418 (void) unlink(apathp);
1419 (void) close(lockfd);
1420 return (0);
1423 * TODO: clean up the workings of DA_UPDATE.
1424 * Due to da_match looking at fields that are missing
1425 * in dargs for DA_UPDATE, the da_match call returns no match,
1426 * but due to the way _da2str combines the devalloc_t info with
1427 * the *dargs info, the DA_ADD_ZONE and DA_REMOVE_ZONE work.
1429 * This would not scale if any type of update was ever needed
1430 * from the daemon.
1434 * Write out devallocp along with the devalloc on/off string.
1436 _write_device_allocate(dapathp, tafp, head_devallocp);
1438 if (dargs->optflag & DA_ALLOC_ONLY)
1439 goto out;
1441 dmap_only:
1442 if ((tmfd = open(mpathp, O_RDWR|O_CREAT, DA_DBMODE)) == -1) {
1443 (void) close(tafd);
1444 (void) unlink(apathp);
1445 (void) close(lockfd);
1446 return (-1);
1448 (void) fchown(tmfd, DA_UID, DA_GID);
1449 if ((tmfp = fdopen(tmfd, "r+")) == NULL) {
1450 (void) close(tafd);
1451 (void) unlink(apathp);
1452 (void) close(tmfd);
1453 (void) unlink(mpathp);
1454 (void) close(lockfd);
1455 return (-1);
1459 * Write back any non-removed pre-existing entries.
1461 if (head_devmapp != NULL)
1462 _write_device_maps(tmfp, head_devmapp);
1464 out:
1466 * Add any new entries here.
1468 if (dargs->optflag & DA_ADD && !(dargs->optflag & DA_NO_OVERRIDE)) {
1469 /* add any new entries */
1470 rc = _write_new_entry(tafp, dargs, DA_ALLOC_ONLY);
1471 (void) fclose(tafp);
1473 if (rc == 0)
1474 rc = _write_new_entry(tmfp, dargs, DA_MAPS_ONLY);
1475 (void) fclose(tmfp);
1476 } else {
1477 if (tafp)
1478 (void) fclose(tafp);
1479 if (tmfp)
1480 (void) fclose(tmfp);
1483 rc = 0;
1484 if (!(dargs->optflag & DA_MAPS_ONLY)) {
1485 if (rename(apathp, dapathp) != 0) {
1486 rc = -1;
1487 (void) unlink(apathp);
1490 if (!(dargs->optflag & DA_ALLOC_ONLY)) {
1491 if (rename(mpathp, dmpathp) != 0) {
1492 rc = -1;
1493 (void) unlink(mpathp);
1497 (void) close(lockfd);
1499 return (rc);
1503 * da_add_list -
1504 * adds new /dev link name to the linked list of devices.
1505 * returns 0 if link added successfully, -1 on error.
1508 da_add_list(devlist_t *dlist, char *link, int new_instance, int flag)
1510 int instance;
1511 int nlen, plen;
1512 int new_entry = 0;
1513 char *dtype, *dexec, *tname, *kval;
1514 char dname[DA_MAXNAME + 1];
1515 deventry_t *dentry = NULL, *nentry = NULL, *pentry = NULL;
1517 if (dlist == NULL || link == NULL)
1518 return (-1);
1520 dname[0] = '\0';
1521 if (flag & DA_AUDIO) {
1522 dentry = dlist->audio;
1523 tname = DA_AUDIO_NAME;
1524 dtype = DA_AUDIO_TYPE;
1525 dexec = DA_DEFAULT_AUDIO_CLEAN;
1526 } else if (flag & DA_CD) {
1527 dentry = dlist->cd;
1528 tname = DA_CD_NAME;
1529 dtype = DA_CD_TYPE;
1530 dexec = DA_DEFAULT_DISK_CLEAN;
1531 } else if (flag & DA_FLOPPY) {
1532 dentry = dlist->floppy;
1533 tname = DA_FLOPPY_NAME;
1534 dtype = DA_FLOPPY_TYPE;
1535 dexec = DA_DEFAULT_DISK_CLEAN;
1536 } else if (flag & DA_TAPE) {
1537 dentry = dlist->tape;
1538 tname = DA_TAPE_NAME;
1539 dtype = DA_TAPE_TYPE;
1540 dexec = DA_DEFAULT_TAPE_CLEAN;
1541 } else if (flag & DA_RMDISK) {
1542 dentry = dlist->rmdisk;
1543 tname = DA_RMDISK_NAME;
1544 dtype = DA_RMDISK_TYPE;
1545 dexec = DA_DEFAULT_DISK_CLEAN;
1546 } else {
1547 return (-1);
1550 for (nentry = dentry; nentry != NULL; nentry = nentry->next) {
1551 pentry = nentry;
1552 (void) sscanf(nentry->devinfo.devname, "%*[a-z]%d", &instance);
1553 if (nentry->devinfo.instance == new_instance)
1555 * Add the new link name to the list of links
1556 * that the device 'dname' has.
1558 break;
1561 if (nentry == NULL) {
1563 * Either this is the first entry ever, or no matching entry
1564 * was found. Create a new one and add to the list.
1566 if (dentry == NULL) /* first entry ever */
1567 instance = 0;
1568 else /* no matching entry */
1569 instance++;
1570 (void) snprintf(dname, sizeof (dname), "%s%d", tname, instance);
1571 if ((nentry = (deventry_t *)malloc(sizeof (deventry_t))) ==
1572 NULL)
1573 return (-1);
1574 if (pentry != NULL)
1575 pentry->next = nentry;
1576 new_entry = 1;
1577 nentry->devinfo.devname = strdup(dname);
1578 nentry->devinfo.devtype = dtype;
1579 nentry->devinfo.devauths = DEFAULT_DEV_ALLOC_AUTH;
1580 nentry->devinfo.devexec = dexec;
1581 nentry->devinfo.instance = new_instance;
1582 kval = NULL;
1583 nlen = strlen(KV_ASSIGN) + strlen(KV_TOKEN_DELIMIT) +
1584 strlen(KV_ASSIGN);
1585 if (kval = (char *)malloc(nlen))
1586 (void) snprintf(kval, nlen, "%s%s%s", KV_ASSIGN,
1587 KV_TOKEN_DELIMIT, KV_ASSIGN);
1588 nentry->devinfo.devopts = kval;
1590 nentry->devinfo.devlist = NULL;
1591 nentry->next = NULL;
1594 nlen = strlen(link) + 1; /* +1 terminator */
1595 if (nentry->devinfo.devlist) {
1596 plen = strlen(nentry->devinfo.devlist);
1597 nlen = nlen + plen + 1; /* +1 for blank to separate entries */
1598 } else {
1599 plen = 0;
1602 if ((nentry->devinfo.devlist =
1603 (char *)realloc(nentry->devinfo.devlist, nlen)) == NULL) {
1604 if (new_entry) {
1605 free(nentry->devinfo.devname);
1606 free(nentry);
1607 if (pentry != NULL)
1608 pentry->next = NULL;
1610 return (-1);
1613 if (plen == 0)
1614 (void) snprintf(nentry->devinfo.devlist, nlen, "%s", link);
1615 else
1616 (void) snprintf(nentry->devinfo.devlist + plen, nlen - plen,
1617 " %s", link);
1619 if (pentry == NULL) {
1621 * This is the first entry of this device type.
1623 if (flag & DA_AUDIO)
1624 dlist->audio = nentry;
1625 else if (flag & DA_CD)
1626 dlist->cd = nentry;
1627 else if (flag & DA_FLOPPY)
1628 dlist->floppy = nentry;
1629 else if (flag & DA_TAPE)
1630 dlist->tape = nentry;
1631 else if (flag & DA_RMDISK)
1632 dlist->rmdisk = nentry;
1635 return (0);
1639 * da_remove_list -
1640 * removes a /dev link name from the linked list of devices.
1641 * returns type of device if link for that device removed
1642 * successfully, else returns -1 on error.
1643 * if all links for a device are removed, stores that device
1644 * name in devname.
1647 da_remove_list(devlist_t *dlist, char *link, int type, char *devname, int size)
1649 int flag;
1650 int remove_dev = 0;
1651 int nlen, plen, slen;
1652 char *lasts, *lname, *oldlist;
1653 struct stat rmstat;
1654 deventry_t *dentry, *current, *prev;
1656 if (type != 0)
1657 flag = type;
1658 else if (link == NULL)
1659 return (-1);
1660 else if (strstr(link, DA_AUDIO_NAME) || strstr(link, DA_SOUND_NAME))
1661 flag = DA_AUDIO;
1662 else if (strstr(link, "dsk") || strstr(link, "rdsk") ||
1663 strstr(link, "sr") || strstr(link, "rsr"))
1664 flag = DA_CD;
1665 else if (strstr(link, "fd") || strstr(link, "rfd") ||
1666 strstr(link, "diskette") || strstr(link, "rdiskette"))
1667 flag = DA_FLOPPY;
1668 else if (strstr(link, DA_TAPE_NAME))
1669 flag = DA_TAPE;
1670 else
1671 flag = DA_RMDISK;
1673 switch (type) {
1674 case DA_AUDIO:
1675 dentry = dlist->audio;
1676 break;
1677 case DA_CD:
1678 dentry = dlist->cd;
1679 break;
1680 case DA_FLOPPY:
1681 dentry = dlist->floppy;
1682 break;
1683 case DA_TAPE:
1684 dentry = dlist->tape;
1685 break;
1686 case DA_RMDISK:
1687 dentry = dlist->rmdisk;
1688 break;
1689 default:
1690 return (-1);
1693 if ((type != 0) && (link == NULL)) {
1694 for (current = dentry, prev = dentry; current != NULL;
1695 current = current->next) {
1696 oldlist = strdup(current->devinfo.devlist);
1697 for (lname = strtok_r(oldlist, " ", &lasts);
1698 lname != NULL;
1699 lname = strtok_r(NULL, " ", &lasts)) {
1700 if (stat(lname, &rmstat) != 0) {
1701 remove_dev = 1;
1702 goto remove_dev;
1705 prev = current;
1707 return (-1);
1710 for (current = dentry, prev = dentry; current != NULL;
1711 current = current->next) {
1712 plen = strlen(current->devinfo.devlist);
1713 nlen = strlen(link);
1714 if (plen == nlen) {
1715 if (strcmp(current->devinfo.devlist, link) == 0) {
1716 /* last name in the list */
1717 remove_dev = 1;
1718 break;
1721 if (strstr(current->devinfo.devlist, link)) {
1722 nlen = plen - nlen + 1;
1723 oldlist = strdup(current->devinfo.devlist);
1724 if ((current->devinfo.devlist =
1725 (char *)realloc(current->devinfo.devlist,
1726 nlen)) == NULL) {
1727 free(oldlist);
1728 return (-1);
1730 current->devinfo.devlist[0] = '\0';
1731 nlen = plen = slen = 0;
1732 for (lname = strtok_r(oldlist, " ", &lasts);
1733 lname != NULL;
1734 lname = strtok_r(NULL, " ", &lasts)) {
1735 if (strcmp(lname, link) == 0)
1736 continue;
1737 nlen = strlen(lname) + plen + 1;
1738 if (plen == 0) {
1739 slen =
1740 snprintf(current->devinfo.devlist,
1741 nlen, "%s", lname);
1742 } else {
1743 slen =
1744 snprintf(current->devinfo.devlist +
1745 plen, nlen - plen, " %s", lname);
1747 plen = plen + slen + 1;
1749 free(oldlist);
1750 break;
1752 prev = current;
1755 remove_dev:
1756 if (remove_dev == 1) {
1757 (void) strlcpy(devname, current->devinfo.devname, size);
1758 free(current->devinfo.devname);
1759 free(current->devinfo.devlist);
1760 current->devinfo.devname = current->devinfo.devlist = NULL;
1761 prev->next = current->next;
1762 free(current);
1763 current = NULL;
1765 if ((remove_dev == 1) && (prev->devinfo.devname == NULL)) {
1766 if (prev->next) {
1768 * what we removed above was the first entry
1769 * in the list. make the next entry to be the
1770 * first.
1772 current = prev->next;
1773 } else {
1775 * the matching entry was the only entry in the list
1776 * for this type.
1778 current = NULL;
1780 if (flag & DA_AUDIO)
1781 dlist->audio = current;
1782 else if (flag & DA_CD)
1783 dlist->cd = current;
1784 else if (flag & DA_FLOPPY)
1785 dlist->floppy = current;
1786 else if (flag & DA_TAPE)
1787 dlist->tape = current;
1788 else if (flag & DA_RMDISK)
1789 dlist->rmdisk = current;
1792 return (flag);
1796 * da_rm_list_entry -
1798 * The adding of devnames to a devlist and the removal of a
1799 * device are not symmetrical -- hot_cleanup gives a /devices
1800 * name which is used to remove the dentry whose links all point to
1801 * that /devices entry.
1803 * The link argument is present if available to make debugging
1804 * easier.
1806 * da_rm_list_entry removes an entry from the linked list of devices.
1808 * Returns 1 if the devname was removed successfully,
1809 * 0 if not found, -1 for error.
1811 /*ARGSUSED*/
1813 da_rm_list_entry(devlist_t *dlist, char *link, int type, char *devname)
1815 int retval = 0;
1816 deventry_t **dentry, *current, *prev;
1818 switch (type) {
1819 case DA_AUDIO:
1820 dentry = &(dlist->audio);
1821 break;
1822 case DA_CD:
1823 dentry = &(dlist->cd);
1824 break;
1825 case DA_FLOPPY:
1826 dentry = &(dlist->floppy);
1827 break;
1828 case DA_TAPE:
1829 dentry = &(dlist->tape);
1830 break;
1831 case DA_RMDISK:
1832 dentry = &(dlist->rmdisk);
1833 break;
1834 default:
1835 return (-1);
1838 /* Presumably in daemon mode, no need to remove entry, list is empty */
1839 if (*dentry == (deventry_t *)NULL)
1840 return (0);
1842 prev = NULL;
1843 for (current = *dentry; current != NULL;
1844 prev = current, current = current->next) {
1845 if (strcmp(devname, current->devinfo.devname))
1846 continue;
1847 retval = 1;
1848 break;
1850 if (retval == 0)
1851 return (0);
1852 free(current->devinfo.devname);
1853 free(current->devinfo.devlist);
1854 free(current->devinfo.devopts);
1856 if (prev == NULL)
1857 *dentry = current->next;
1858 else
1859 prev->next = current->next;
1861 free(current);
1862 return (retval);
1866 * da_is_on -
1867 * checks if device allocation feature is turned on.
1868 * returns 1 if on, 0 if off, -1 if status string not
1869 * found in device_allocate.
1872 da_is_on()
1874 return (getdaon());
1878 * da_print_device -
1879 * debug routine to print device entries.
1881 void
1882 da_print_device(int flag, devlist_t *devlist)
1884 deventry_t *entry, *dentry;
1885 devinfo_t *devinfo;
1887 if (flag & DA_AUDIO)
1888 dentry = devlist->audio;
1889 else if (flag & DA_CD)
1890 dentry = devlist->cd;
1891 else if (flag & DA_FLOPPY)
1892 dentry = devlist->floppy;
1893 else if (flag & DA_TAPE)
1894 dentry = devlist->tape;
1895 else if (flag & DA_RMDISK)
1896 dentry = devlist->rmdisk;
1897 else
1898 return;
1900 for (entry = dentry; entry != NULL; entry = entry->next) {
1901 devinfo = &(entry->devinfo);
1902 (void) fprintf(stdout, "name: %s\n", devinfo->devname);
1903 (void) fprintf(stdout, "type: %s\n", devinfo->devtype);
1904 (void) fprintf(stdout, "auth: %s\n", devinfo->devauths);
1905 (void) fprintf(stdout, "exec: %s\n", devinfo->devexec);
1906 (void) fprintf(stdout, "list: %s\n\n", devinfo->devlist);