xref: /illumos-gate/usr/src/cmd/allocate/mkdevalloc.c (revision 45916cd2fec6e79bca5dee0421bd39e3c2910d1e)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * scan /dev directory for mountable objects and construct device_allocate
31  * file for allocate....
32  *
33  * devices are:
34  *	tape (cartridge)
35  *		/dev/rst*
36  *		/dev/nrst*
37  *		/dev/rmt/...
38  *	audio
39  *		/dev/audio
40  *		/dev/audioctl
41  *		/dev/sound/...
42  *	floppy
43  *		/dev/diskette
44  *		/dev/fd*
45  *		/dev/rdiskette
46  *		/dev/rfd*
47  *	CD
48  *		/dev/sr*
49  *		/dev/nsr*
50  *		/dev/dsk/c?t?d0s?
51  *		/dev/rdsk/c?t?d0s?
52  *
53  */
54 
55 #include <errno.h>
56 #include <fcntl.h>
57 #include <sys/types.h>	/* for stat(2), etc. */
58 #include <sys/stat.h>
59 #include <dirent.h>	/* for readdir(3), etc. */
60 #include <unistd.h>	/* for readlink(2) */
61 #include <stropts.h>
62 #include <string.h>	/* for strcpy(3), etc. */
63 #include <strings.h>	/* for bcopy(3C), etc. */
64 #include <stdio.h>	/* for perror(3) */
65 #include <stdlib.h>	/* for atoi(3) */
66 #include <sys/dkio.h>
67 #include <locale.h>
68 #include <libintl.h>
69 #include <libdevinfo.h>
70 #include <secdb.h>
71 #include <auth_attr.h>
72 #include <auth_list.h>
73 #include <bsm/devices.h>
74 #include <bsm/devalloc.h>
75 #include <tsol/label.h>
76 
77 #ifndef TEXT_DOMAIN
78 #define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
79 #endif
80 
81 #define	MKDEVALLOC	"mkdevalloc"
82 #define	MKDEVMAPS	"mkdevmaps"
83 
84 #define	DELTA	5	/* array size delta when full */
85 #define	SECLIB	"/etc/security/lib"
86 
87 /* "/dev/rst...", "/dev/nrst...", "/dev/rmt/..." */
88 struct tape {
89 	char	*name;
90 	char	*device;
91 	int	number;
92 } *tape;
93 #define	DFLT_NTAPE  10		/* size of initial array */
94 #define	SIZE_OF_RST  3		/* |rmt| */
95 #define	SIZE_OF_NRST 4		/* |nrmt| */
96 #define	SIZE_OF_TMP  4		/* |/tmp| */
97 #define	SIZE_OF_RMT  8		/* |/dev/rmt| */
98 #define	TAPE_CLEAN    SECLIB"/st_clean"
99 
100 /* "/dev/audio", "/dev/audioctl", "/dev/sound/..." */
101 struct audio {
102 	char	*name;
103 	char	*device;
104 	int	number;
105 } *audio;
106 #define	DFLT_NAUDIO   10	/* size of initial array */
107 #define	SIZE_OF_SOUND 10	/* |/dev/sound| */
108 #define	AUDIO_CLEAN   SECLIB"/audio_clean"
109 
110 /* "/dev/sr", "/dev/nsr", "/dev/dsk/c?t?d0s?", "/dev/rdsk/c?t?d0s?" */
111 struct cd {
112 	char	*name;
113 	char	*device;
114 	int	id;
115 	int	controller;
116 	int	number;
117 } *cd;
118 #define	DFLT_NCD    10		/* size of initial array */
119 #define	SIZE_OF_SR   2		/* |sr| */
120 #define	SIZE_OF_RSR  3		/* |rsr| */
121 #define	SIZE_OF_DSK  8		/* |/dev/dsk| */
122 #define	SIZE_OF_RDSK 9		/* |/dev/rdsk| */
123 #define	CD_CLEAN    SECLIB"/sr_clean"
124 
125 /* "/dev/sr", "/dev/nsr", "/dev/dsk/c?t?d0s?", "/dev/rdsk/c?t?d0s?" */
126 struct rmdisk {
127 	char	*name;
128 	char	*device;
129 	int	id;
130 	int	controller;
131 	int	number;
132 } *rmdisk, *rmdisk_r;
133 #define	DFLT_RMDISK	10	/* size of initial array */
134 
135 /* "/dev/fd0*", "/dev/rfd0*", "/dev/fd1*", "/dev/rfd1*" */
136 struct fp {
137 	char *name;
138 	char *device;
139 	int number;
140 } *fp;
141 #define	DFLT_NFP    10		/* size of initial array */
142 #define	SIZE_OF_FD0  3		/* |fd0| */
143 #define	SIZE_OF_RFD0 4		/* |rfd0| */
144 #define	FLOPPY_CLEAN SECLIB"/fd_clean"
145 
146 static void dotape();
147 static void doaudio();
148 static void dofloppy();
149 static int docd();
150 static void dormdisk(int);
151 static void initmem();
152 static int  expandmem(int, void **, int);
153 static void no_memory(void);
154 
155 int		system_labeled = 0;
156 int		do_devalloc = 0;
157 int		do_devmaps = 0;
158 int		do_files = 0;
159 devlist_t	devlist;
160 
161 int
162 main(int argc, char **argv)
163 {
164 	int		cd_count = 0;
165 	char		*progname;
166 	struct stat	tx_stat;
167 
168 	(void) setlocale(LC_ALL, "");
169 	(void) textdomain(TEXT_DOMAIN);
170 
171 	if ((progname = strrchr(argv[0], '/')) == NULL)
172 		progname = argv[0];
173 	else
174 		progname++;
175 	if (strcmp(progname, MKDEVALLOC) == 0)
176 		do_devalloc = 1;
177 	else if (strcmp(progname, MKDEVMAPS) == 0)
178 		do_devmaps = 1;
179 	else
180 		exit(1);
181 
182 	system_labeled = is_system_labeled();
183 	if (system_labeled == 0) {
184 		/*
185 		 * is_system_labeled() will return false in case we are
186 		 * starting before the first reboot after Trusted Extensions
187 		 * is installed. we check for a well known TX binary to
188 		 * to see if TX is installed.
189 		 */
190 		if (stat(DA_LABEL_CHECK, &tx_stat) == 0)
191 			system_labeled = 1;
192 	}
193 
194 	if (system_labeled && do_devalloc && (argc == 2) &&
195 	    (strcmp(argv[1], DA_IS_LABELED) == 0)) {
196 		/*
197 		 * write device entries to device_allocate and device_maps.
198 		 * default is to print them on stdout.
199 		 */
200 		do_files = 1;
201 	}
202 
203 	initmem();		/* initialize memory */
204 	dotape();
205 	doaudio();
206 	dofloppy();
207 	cd_count = docd();
208 	if (system_labeled)
209 		dormdisk(cd_count);
210 
211 	return (0);
212 }
213 
214 static void
215 dotape()
216 {
217 	DIR *dirp;
218 	struct dirent *dep;	/* directory entry pointer */
219 	int	i, j;
220 	char	*nm;		/* name/device of special device */
221 	char	linkvalue[2048];	/* symlink value */
222 	struct stat stat;	/* determine if it's a symlink */
223 	int	sz;		/* size of symlink value */
224 	char	*cp;		/* pointer into string */
225 	int	ntape;		/* max array size */
226 	int	tape_count;
227 	int	first = 0;
228 	char	*dname, *dtype, *dclean;
229 	da_args	dargs;
230 	deventry_t *entry;
231 
232 	ntape = DFLT_NTAPE;
233 
234 	/*
235 	 * look for rst* and nrst*
236 	 */
237 
238 	if ((dirp = opendir("/dev")) == NULL) {
239 		perror(gettext("open /dev failure"));
240 		exit(1);
241 	}
242 
243 	i = 0;
244 	while (dep = readdir(dirp)) {
245 		/* ignore if neither rst* nor nrst* */
246 		if (strncmp(dep->d_name, "rst", SIZE_OF_RST) &&
247 		    strncmp(dep->d_name, "nrst", SIZE_OF_NRST))
248 			continue;
249 
250 		/* if array full, then expand it */
251 		if (i == ntape) {
252 			/* will exit(1) if insufficient memory */
253 			ntape = expandmem(i, (void **)&tape,
254 					sizeof (struct tape));
255 		}
256 
257 		/* save name (/dev + / + d_name + \0) */
258 		nm = (char *)malloc(SIZE_OF_TMP + 1 + strlen(dep->d_name) + 1);
259 		if (nm == NULL)
260 			no_memory();
261 		(void) strcpy(nm, "/dev/");
262 		(void) strcat(nm, dep->d_name);
263 		tape[i].name = nm;
264 
265 		/* ignore if not symbolic link (note i not incremented) */
266 		if (lstat(tape[i].name, &stat) < 0) {
267 			perror("stat(2) failed ");
268 			exit(1);
269 		}
270 		if ((stat.st_mode & S_IFMT) != S_IFLNK)
271 			continue;
272 
273 		/* get name from symbolic link */
274 		if ((sz = readlink(tape[i].name, linkvalue,
275 				sizeof (linkvalue))) < 0)
276 			continue;
277 		nm = (char *)malloc(sz + 1);
278 		if (nm == NULL)
279 			no_memory();
280 		(void) strncpy(nm, linkvalue, sz);
281 		nm[sz] = '\0';
282 		tape[i].device = nm;
283 
284 		/* get device number */
285 		cp = strrchr(tape[i].device, '/');
286 		cp++;				/* advance to device # */
287 		(void) sscanf(cp, "%d", &tape[i].number);
288 
289 		i++;
290 	}
291 
292 	(void) closedir(dirp);
293 
294 	/*
295 	 * scan /dev/rmt and add entry to table
296 	 */
297 
298 	if ((dirp = opendir("/dev/rmt")) == NULL) {
299 		perror(gettext("open /dev failure"));
300 		exit(1);
301 	}
302 
303 	while (dep = readdir(dirp)) {
304 		/* skip . .. etc... */
305 		if (strncmp(dep->d_name, ".", 1) == NULL)
306 			continue;
307 
308 		/* if array full, then expand it */
309 		if (i == ntape) {
310 			/* will exit(1) if insufficient memory */
311 			ntape = expandmem(i, (void **)&tape,
312 					sizeof (struct tape));
313 		}
314 
315 		/* save name (/dev/rmt + / + d_name + \0) */
316 		nm = (char *)malloc(SIZE_OF_RMT + 1 + strlen(dep->d_name) + 1);
317 		if (nm == NULL)
318 			no_memory();
319 		(void) strcpy(nm, "/dev/rmt/");
320 		(void) strcat(nm, dep->d_name);
321 		tape[i].name = nm;
322 
323 		/* save device name (rmt/ + d_name + \0) */
324 		nm = (char *)malloc(SIZE_OF_TMP + strlen(dep->d_name) + 1);
325 		if (nm == NULL)
326 			no_memory();
327 		(void) strcpy(nm, "rmt/");
328 		(void) strcat(nm, dep->d_name);
329 		tape[i].device = nm;
330 
331 		(void) sscanf(dep->d_name, "%d", &tape[i].number);
332 
333 		i++;
334 	}
335 	tape_count = i;
336 
337 	(void) closedir(dirp);
338 
339 	/* remove duplicate entries */
340 	for (i = 0; i < tape_count - 1; i++) {
341 		for (j = i + 1; j < tape_count; j++) {
342 			if (strcmp(tape[i].device, tape[j].device))
343 				continue;
344 			tape[j].number = -1;
345 		}
346 	}
347 
348 	if (system_labeled) {
349 		dname = DA_TAPE_NAME;
350 		dtype = DA_TAPE_TYPE;
351 		dclean = DA_DEFAULT_TAPE_CLEAN;
352 	} else {
353 		dname = "st";
354 		dtype = "st";
355 		dclean = TAPE_CLEAN;
356 	}
357 	for (i = 0; i < 8; i++) {
358 		for (j = 0; j < tape_count; j++) {
359 			if (tape[j].number != i)
360 				continue;
361 			if (do_files) {
362 				(void) da_add_list(&devlist, tape[j].name, i,
363 				    DA_TAPE);
364 			} else if (do_devalloc) {
365 				/* print device_allocate for tape devices */
366 				if (system_labeled) {
367 					(void) printf("%s%d%s\\\n",
368 					    dname, i, KV_DELIMITER);
369 					(void) printf("\t%s%s\\\n",
370 					    DA_TAPE_TYPE, KV_DELIMITER);
371 					(void) printf("\t%s%s\\\n",
372 					    DA_RESERVED, KV_DELIMITER);
373 					(void) printf("\t%s%s\\\n",
374 					    DA_RESERVED, KV_DELIMITER);
375 					(void) printf("\t%s%s\\\n",
376 					    DEFAULT_DEV_ALLOC_AUTH,
377 					    KV_DELIMITER);
378 					(void) printf("\t%s\n\n", dclean);
379 				} else {
380 					(void) printf(
381 					    "st%d;st;reserved;reserved;%s;",
382 					    i, DEFAULT_DEV_ALLOC_AUTH);
383 					(void) printf("%s%s\n", SECLIB,
384 					    "/st_clean");
385 				}
386 				break;
387 			} else if (do_devmaps) {
388 				/* print device_maps for tape devices */
389 				if (first) {
390 					(void) printf(" ");
391 				} else {
392 					if (system_labeled) {
393 						(void) printf("%s%d%s\\\n",
394 						    dname, i, KV_TOKEN_DELIMIT);
395 						(void) printf("\t%s%s\\\n",
396 						    dtype, KV_TOKEN_DELIMIT);
397 						(void) printf("\t");
398 					} else {
399 						(void) printf("st%d:\\\n", i);
400 						(void) printf("\trmt:\\\n");
401 						(void) printf("\t");
402 					}
403 						first++;
404 				}
405 				(void) printf("%s", tape[j].name);
406 			}
407 		}
408 		if (do_devmaps && first) {
409 			(void) printf("\n\n");
410 			first = 0;
411 		}
412 	}
413 	if (do_files && tape_count) {
414 		dargs.rootdir = NULL;
415 		dargs.devnames = NULL;
416 		dargs.optflag = DA_ADD;
417 		for (entry = devlist.tape; entry != NULL; entry = entry->next) {
418 			dargs.devinfo = &(entry->devinfo);
419 			(void) da_update_device(&dargs);
420 		}
421 	}
422 }
423 
424 static void
425 doaudio()
426 {
427 	DIR *dirp;
428 	struct dirent *dep;	/* directory entry pointer */
429 	int	i, j;
430 	char	*nm;		/* name/device of special device */
431 	char	linkvalue[2048];	/* symlink value */
432 	struct stat stat;	/* determine if it's a symlink */
433 	int	sz;		/* size of symlink value */
434 	char	*cp;		/* pointer into string */
435 	int	naudio;		/* max array size */
436 	int	audio_count = 0;
437 	int	len, slen;
438 	int	first = 0;
439 	char	dname[128];
440 	char	*dclean;
441 	da_args	dargs;
442 	deventry_t *entry;
443 
444 	naudio = DFLT_NAUDIO;
445 
446 	if ((dirp = opendir("/dev")) == NULL) {
447 		perror(gettext("open /dev failure"));
448 		exit(1);
449 	}
450 
451 	i = 0;
452 	while (dep = readdir(dirp)) {
453 		if (strcmp(dep->d_name, "audio") &&
454 		    strcmp(dep->d_name, "audioctl"))
455 			continue;
456 
457 		/* if array full, then expand it */
458 		if (i == naudio) {
459 			/* will exit(1) if insufficient memory */
460 			naudio = expandmem(i, (void **)&audio,
461 					sizeof (struct audio));
462 		}
463 
464 		/* save name (/dev + 1 + d_name + \0) */
465 		nm = (char *)malloc(SIZE_OF_TMP + 1 + strlen(dep->d_name) + 1);
466 		if (nm == NULL)
467 			no_memory();
468 		(void) strcpy(nm, "/dev/");
469 		(void) strcat(nm, dep->d_name);
470 		audio[i].name = nm;
471 
472 		/* ignore if not symbolic link (note i not incremented) */
473 		if (lstat(audio[i].name, &stat) < 0) {
474 			perror(gettext("stat(2) failed "));
475 			exit(1);
476 		}
477 		if ((stat.st_mode & S_IFMT) != S_IFLNK)
478 			continue;
479 
480 		/* get name from symbolic link */
481 		if ((sz = readlink(audio[i].name, linkvalue,
482 				sizeof (linkvalue))) < 0)
483 			continue;
484 		nm = (char *)malloc(sz + 1);
485 		if (nm == NULL)
486 			no_memory();
487 		(void) strncpy(nm, linkvalue, sz);
488 		nm[sz] = '\0';
489 		audio[i].device = nm;
490 
491 		cp = strrchr(audio[i].device, '/');
492 		cp++;				/* advance to device # */
493 		(void) sscanf(cp, "%d", &audio[i].number);
494 
495 		i++;
496 	}
497 
498 	(void) closedir(dirp);
499 
500 	if ((dirp = opendir("/dev/sound")) == NULL) {
501 		goto skip;
502 	}
503 
504 	while (dep = readdir(dirp)) {
505 		/* skip . .. etc... */
506 		if (strncmp(dep->d_name, ".", 1) == NULL)
507 			continue;
508 
509 		/* if array full, then expand it */
510 		if (i == naudio) {
511 			/* will exit(1) if insufficient memory */
512 			naudio = expandmem(i, (void **)&audio,
513 					sizeof (struct audio));
514 		}
515 
516 		/* save name (/dev/sound + / + d_name + \0) */
517 		nm = (char *)malloc(SIZE_OF_SOUND + 1 +
518 		    strlen(dep->d_name) + 1);
519 		if (nm == NULL)
520 			no_memory();
521 		(void) strcpy(nm, "/dev/sound/");
522 		(void) strcat(nm, dep->d_name);
523 		audio[i].name = nm;
524 
525 		nm = (char *)malloc(SIZE_OF_SOUND + 1 +
526 		    strlen(dep->d_name) + 1);
527 		if (nm == NULL)
528 			no_memory();
529 		(void) strcpy(nm, "/dev/sound/");
530 		(void) strcat(nm, dep->d_name);
531 		audio[i].device = nm;
532 
533 		(void) sscanf(dep->d_name, "%d", &audio[i].number);
534 
535 		i++;
536 	}
537 
538 	(void) closedir(dirp);
539 
540 skip:
541 	audio_count = i;
542 
543 	/* remove duplicate entries */
544 	for (i = 0; i < audio_count - 1; i++) {
545 		for (j = i + 1; j < audio_count; j++) {
546 			if (strcmp(audio[i].device, audio[j].device))
547 				continue;
548 			audio[j].number = -1;
549 		}
550 	}
551 
552 	/* print out device_allocate entries for audio devices */
553 	(void) strcpy(dname, DA_AUDIO_NAME);
554 	slen = strlen(DA_AUDIO_NAME);
555 	len = sizeof (dname) - slen;
556 	dclean = system_labeled ? DA_DEFAULT_AUDIO_CLEAN : AUDIO_CLEAN;
557 	for (i = 0; i < 8; i++) {
558 		for (j = 0; j < audio_count; j++) {
559 			if (audio[j].number != i)
560 				continue;
561 			if (system_labeled)
562 				(void) snprintf(dname+slen, len, "%d", i);
563 			if (do_files) {
564 				(void) da_add_list(&devlist, audio[j].name,
565 				    i, DA_AUDIO);
566 			} else if (do_devalloc) {
567 				/* print device_allocate for audio devices */
568 				if (system_labeled) {
569 					(void) printf("%s%s\\\n",
570 					    dname, KV_DELIMITER);
571 					(void) printf("\t%s%s\\\n",
572 					    DA_AUDIO_TYPE, KV_DELIMITER);
573 					(void) printf("\t%s%s\\\n",
574 					    DA_RESERVED, KV_DELIMITER);
575 					(void) printf("\t%s%s\\\n",
576 					    DA_RESERVED, KV_DELIMITER);
577 					(void) printf("\t%s%s\\\n",
578 					    DEFAULT_DEV_ALLOC_AUTH,
579 					    KV_DELIMITER);
580 					(void) printf("\t%s\n\n", dclean);
581 				} else {
582 					(void) printf("audio;audio;");
583 					(void) printf("reserved;reserved;%s;",
584 					    DEFAULT_DEV_ALLOC_AUTH);
585 					(void) printf("%s%s\n", SECLIB,
586 					    "/audio_clean");
587 				}
588 				break;
589 			} else if (do_devmaps) {
590 				/* print device_maps for audio devices */
591 				if (first) {
592 					(void) printf(" ");
593 				} else {
594 					if (system_labeled) {
595 						(void) printf("%s%s\\\n",
596 						    dname, KV_TOKEN_DELIMIT);
597 						(void) printf("\t%s%s\\\n",
598 						    DA_AUDIO_TYPE,
599 						    KV_TOKEN_DELIMIT);
600 						(void) printf("\t");
601 					} else {
602 						(void) printf("audio:\\\n");
603 						(void) printf("\taudio:\\\n");
604 						(void) printf("\t");
605 					}
606 					first++;
607 				}
608 				(void) printf("%s", audio[j].name);
609 			}
610 		}
611 		if (do_devmaps && first) {
612 			(void) printf("\n\n");
613 			first = 0;
614 		}
615 	}
616 	if (do_files && audio_count) {
617 		dargs.rootdir = NULL;
618 		dargs.devnames = NULL;
619 		dargs.optflag = DA_ADD;
620 		for (entry = devlist.audio; entry != NULL;
621 		    entry = entry->next) {
622 			dargs.devinfo = &(entry->devinfo);
623 			(void) da_update_device(&dargs);
624 		}
625 	}
626 }
627 
628 static void
629 dofloppy()
630 {
631 	DIR *dirp;
632 	struct dirent *dep;	/* directory entry pointer */
633 	int i, j;
634 	char *nm;		/* name/device of special device */
635 	char linkvalue[2048];	/* symlink value */
636 	struct stat stat;	/* determine if it's a symlink */
637 	int sz;			/* size of symlink value */
638 	char *cp;		/* pointer into string */
639 	int nfp;		/* max array size */
640 	int floppy_count = 0;
641 	int first = 0;
642 	char *dname, *dclean;
643 	da_args dargs;
644 	deventry_t *entry;
645 
646 	nfp = DFLT_NFP;
647 
648 	/*
649 	 * look for fd* and rfd*
650 	 */
651 
652 	if ((dirp = opendir("/dev")) == NULL) {
653 		perror(gettext("open /dev failure"));
654 		exit(1);
655 	}
656 
657 	i = 0;
658 	while (dep = readdir(dirp)) {
659 		/* ignore if neither rst* nor nrst* */
660 		if (strncmp(dep->d_name, "fd0", SIZE_OF_FD0) &&
661 		    strncmp(dep->d_name, "rfd0", SIZE_OF_RFD0) &&
662 		    strncmp(dep->d_name, "fd1", SIZE_OF_FD0) &&
663 		    strncmp(dep->d_name, "rfd0", SIZE_OF_RFD0))
664 			continue;
665 
666 		/* if array full, then expand it */
667 		if (i == nfp) {
668 			/* will exit(1) if insufficient memory */
669 			nfp = expandmem(i, (void **)&fp, sizeof (struct fp));
670 		}
671 
672 		/* save name (/dev + 1 + d_name + \0) */
673 		nm = (char *)malloc(SIZE_OF_TMP + 1 + strlen(dep->d_name) + 1);
674 		if (nm == NULL)
675 			no_memory();
676 		(void) strcpy(nm, "/dev/");
677 		(void) strcat(nm, dep->d_name);
678 		fp[i].name = nm;
679 
680 		/* ignore if not symbolic link (note i not incremented) */
681 		if (lstat(fp[i].name, &stat) < 0) {
682 			perror(gettext("stat(2) failed "));
683 			exit(1);
684 		}
685 		if ((stat.st_mode&S_IFMT) != S_IFLNK)
686 			continue;
687 
688 		/* get name from symbolic link */
689 		if ((sz = readlink(fp[i].name, linkvalue,
690 		    sizeof (linkvalue))) < 0)
691 			continue;
692 		nm = (char *)malloc(sz+1);
693 		if (nm == NULL)
694 			no_memory();
695 		(void) strncpy(nm, linkvalue, sz);
696 		nm[sz] = '\0';
697 		fp[i].device = nm;
698 
699 		/* get device number */
700 		cp = strchr(fp[i].name, 'd');
701 		cp++;				/* advance to device # */
702 		cp = strchr(cp, 'd');
703 		cp++;				/* advance to device # */
704 		(void) sscanf(cp, "%d", &fp[i].number);
705 
706 		i++;
707 	}
708 
709 	(void) closedir(dirp);
710 
711 	floppy_count = i;
712 
713 	/* print out device_allocate entries for floppy devices */
714 	if (system_labeled) {
715 		dname = DA_FLOPPY_NAME;
716 		dclean = DA_DEFAULT_DISK_CLEAN;
717 	} else {
718 		dname = "fd";
719 		dclean = FLOPPY_CLEAN;
720 	}
721 	for (i = 0; i < 8; i++) {
722 		for (j = 0; j < floppy_count; j++) {
723 			if (fp[j].number != i)
724 				continue;
725 			if (do_files) {
726 				(void) da_add_list(&devlist, fp[j].name, i,
727 				    DA_FLOPPY);
728 			} else if (do_devalloc) {
729 				/* print device_allocate for floppy devices */
730 				if (system_labeled) {
731 					(void) printf("%s%d%s\\\n",
732 					    dname, i, KV_DELIMITER);
733 					(void) printf("\t%s%s\\\n",
734 					    DA_FLOPPY_TYPE, KV_DELIMITER);
735 					(void) printf("\t%s%s\\\n",
736 					    DA_RESERVED, KV_DELIMITER);
737 					(void) printf("\t%s%s\\\n",
738 					    DA_RESERVED, KV_DELIMITER);
739 					(void) printf("\t%s%s\\\n",
740 					    DEFAULT_DEV_ALLOC_AUTH,
741 					    KV_DELIMITER);
742 					(void) printf("\t%s\n\n", dclean);
743 				} else {
744 					(void) printf(
745 					    "fd%d;fd;reserved;reserved;%s;",
746 					    i, DEFAULT_DEV_ALLOC_AUTH);
747 					(void) printf("%s%s\n", SECLIB,
748 					    "/fd_clean");
749 				}
750 				break;
751 			} else if (do_devmaps) {
752 				/* print device_maps for floppy devices */
753 				if (first) {
754 					(void) printf(" ");
755 				} else {
756 					if (system_labeled) {
757 						(void) printf("%s%d%s\\\n",
758 						    dname, i, KV_TOKEN_DELIMIT);
759 						(void) printf("\t%s%s\\\n",
760 						    DA_FLOPPY_TYPE,
761 						    KV_TOKEN_DELIMIT);
762 						(void) printf("\t");
763 					} else {
764 						(void) printf("fd%d:\\\n", i);
765 						(void) printf("\tfd:\\\n");
766 						(void) printf("\t");
767 					}
768 					if (i == 0) {
769 						(void) printf("/dev/diskette ");
770 						(void) printf(
771 						    "/dev/rdiskette ");
772 					}
773 					first++;
774 				}
775 				(void) printf("%s", fp[j].name);
776 			}
777 		}
778 		if (do_devmaps && first) {
779 			(void) printf("\n\n");
780 			first = 0;
781 		}
782 	}
783 	if (do_files && floppy_count) {
784 		dargs.rootdir = NULL;
785 		dargs.devnames = NULL;
786 		dargs.optflag = DA_ADD;
787 		for (entry = devlist.floppy; entry != NULL;
788 		    entry = entry->next) {
789 			dargs.devinfo = &(entry->devinfo);
790 			(void) da_update_device(&dargs);
791 		}
792 	}
793 }
794 
795 static int
796 docd()
797 {
798 	DIR *dirp;
799 	struct dirent *dep;	/* directory entry pointer */
800 	int	i, j;
801 	char	*nm;		/* name/device of special device */
802 	char	linkvalue[2048];	/* symlink value */
803 	struct stat stat;	/* determine if it's a symlink */
804 	int	sz;		/* size of symlink value */
805 	char	*cp;		/* pointer into string */
806 	int	id;		/* disk id */
807 	int	ctrl;		/* disk controller */
808 	int	ncd;		/* max array size */
809 	int	cd_count = 0;
810 	int	first = 0;
811 	char	*dname, *dclean;
812 	da_args	dargs;
813 	deventry_t *entry;
814 
815 	ncd = DFLT_NCD;
816 
817 	/*
818 	 * look for sr* and rsr*
819 	 */
820 
821 	if ((dirp = opendir("/dev")) == NULL) {
822 		perror(gettext("open /dev failure"));
823 		exit(1);
824 	}
825 
826 	i = 0;
827 	while (dep = readdir(dirp)) {
828 		/* ignore if neither sr* nor rsr* */
829 		if (strncmp(dep->d_name, "sr", SIZE_OF_SR) &&
830 		    strncmp(dep->d_name, "rsr", SIZE_OF_RSR))
831 			continue;
832 
833 		/* if array full, then expand it */
834 		if (i == ncd) {
835 			/* will exit(1) if insufficient memory */
836 			ncd = expandmem(i, (void **)&cd, sizeof (struct cd));
837 		}
838 
839 		/* save name (/dev + / + d_name + \0) */
840 		nm = (char *)malloc(SIZE_OF_TMP + 1 + strlen(dep->d_name) + 1);
841 		if (nm == NULL)
842 			no_memory();
843 		(void) strcpy(nm, "/dev/");
844 		(void) strcat(nm, dep->d_name);
845 		cd[i].name = nm;
846 
847 		/* save id # */
848 		if (dep->d_name[0] == 'r')
849 			(void) sscanf(dep->d_name, "rsr%d", &cd[i].id);
850 		else
851 			(void) sscanf(dep->d_name, "sr%d", &cd[i].id);
852 
853 		/* ignore if not symbolic link (note i not incremented) */
854 		if (lstat(cd[i].name, &stat) < 0) {
855 			perror(gettext("stat(2) failed "));
856 			exit(1);
857 		}
858 		if ((stat.st_mode & S_IFMT) != S_IFLNK)
859 			continue;
860 
861 		/* get name from symbolic link */
862 		if ((sz = readlink(cd[i].name, linkvalue, sizeof (linkvalue))) <
863 		    0)
864 			continue;
865 
866 		nm = (char *)malloc(sz + 1);
867 		if (nm == NULL)
868 			no_memory();
869 		(void) strncpy(nm, linkvalue, sz);
870 		nm[sz] = '\0';
871 		cd[i].device = nm;
872 
873 		cp = strrchr(cd[i].device, '/');
874 		cp++;				/* advance to device # */
875 		(void) sscanf(cp, "c%dt%d", &cd[i].controller, &cd[i].number);
876 
877 		i++;
878 	}
879 	cd_count = i;
880 
881 	(void) closedir(dirp);
882 
883 	/*
884 	 * scan /dev/dsk for cd devices
885 	 */
886 
887 	if ((dirp = opendir("/dev/dsk")) == NULL) {
888 		perror("gettext(open /dev/dsk failure)");
889 		exit(1);
890 	}
891 
892 	while (dep = readdir(dirp)) {
893 		/* skip . .. etc... */
894 		if (strncmp(dep->d_name, ".", 1) == NULL)
895 			continue;
896 
897 		/* get device # (disk #) */
898 		if (sscanf(dep->d_name, "c%dt%d", &ctrl, &id) <= 0)
899 			continue;
900 
901 		/* see if this is one of the cd special devices */
902 		for (j = 0; j < cd_count; j++) {
903 			if (cd[j].number == id && cd[j].controller == ctrl)
904 				goto found;
905 		}
906 		continue;
907 
908 		/* add new entry to table (/dev/dsk + / + d_name + \0) */
909 found:
910 		/* if array full, then expand it */
911 		if (i == ncd) {
912 			/* will exit(1) if insufficient memory */
913 			ncd = expandmem(i, (void **)&cd, sizeof (struct cd));
914 		}
915 
916 		nm = (char *)malloc(SIZE_OF_DSK + 1 + strlen(dep->d_name) + 1);
917 		if (nm == NULL)
918 			no_memory();
919 		(void) strcpy(nm, "/dev/dsk/");
920 		(void) strcat(nm, dep->d_name);
921 		cd[i].name = nm;
922 
923 		cd[i].id = cd[j].id;
924 
925 		cd[i].device = "";
926 
927 		cd[i].number = id;
928 
929 		i++;
930 	}
931 
932 	(void) closedir(dirp);
933 
934 	/*
935 	 * scan /dev/rdsk for cd devices
936 	 */
937 
938 	if ((dirp = opendir("/dev/rdsk")) == NULL) {
939 		perror(gettext("open /dev/dsk failure"));
940 		exit(1);
941 	}
942 
943 	while (dep = readdir(dirp)) {
944 		/* skip . .. etc... */
945 		if (strncmp(dep->d_name, ".", 1) == NULL)
946 			continue;
947 
948 		/* get device # (disk #) */
949 		if (sscanf(dep->d_name, "c%dt%d", &ctrl, &id) != 2)
950 			continue;
951 
952 		/* see if this is one of the cd special devices */
953 		for (j = 0; j < cd_count; j++) {
954 			if (cd[j].number == id && cd[j].controller == ctrl)
955 				goto found1;
956 		}
957 		continue;
958 
959 		/* add new entry to table (/dev/rdsk + / + d_name + \0) */
960 found1:
961 		/* if array full, then expand it */
962 		if (i == ncd) {
963 			/* will exit(1) if insufficient memory */
964 			ncd = expandmem(i, (void **)&cd, sizeof (struct cd));
965 		}
966 
967 		nm = (char *)malloc(SIZE_OF_RDSK + 1 + strlen(dep->d_name) + 1);
968 		if (nm == NULL)
969 			no_memory();
970 		(void) strcpy(nm, "/dev/rdsk/");
971 		(void) strcat(nm, dep->d_name);
972 		cd[i].name = nm;
973 
974 		cd[i].id = cd[j].id;
975 
976 		cd[i].device = "";
977 
978 		cd[i].number = id;
979 
980 		cd[i].controller = ctrl;
981 
982 		i++;
983 	}
984 
985 	(void) closedir(dirp);
986 
987 	cd_count = i;
988 
989 	if (system_labeled) {
990 		dname = DA_CD_NAME;
991 		dclean = DA_DEFAULT_DISK_CLEAN;
992 	} else {
993 		dname = "sr";
994 		dclean = CD_CLEAN;
995 	}
996 	for (i = 0; i < 8; i++) {
997 		for (j = 0; j < cd_count; j++) {
998 			if (cd[j].id != i)
999 				continue;
1000 			if (do_files) {
1001 				(void) da_add_list(&devlist, cd[j].name, i,
1002 				    DA_CD);
1003 			} else if (do_devalloc) {
1004 				/* print device_allocate for cd devices */
1005 				if (system_labeled) {
1006 					(void) printf("%s%d%s\\\n",
1007 					    dname, i, KV_DELIMITER);
1008 					(void) printf("\t%s%s\\\n",
1009 					    DA_CD_TYPE, KV_DELIMITER);
1010 					(void) printf("\t%s%s\\\n",
1011 					    DA_RESERVED, KV_DELIMITER);
1012 					(void) printf("\t%s%s\\\n",
1013 					    DA_RESERVED, KV_DELIMITER);
1014 					(void) printf("\t%s%s\\\n",
1015 					    DEFAULT_DEV_ALLOC_AUTH,
1016 					    KV_DELIMITER);
1017 					(void) printf("\t%s\n\n", dclean);
1018 				} else {
1019 					(void) printf(
1020 					    "sr%d;sr;reserved;reserved;%s;",
1021 					    i, DEFAULT_DEV_ALLOC_AUTH);
1022 					(void) printf("%s%s\n", SECLIB,
1023 					    "/sr_clean");
1024 				}
1025 				break;
1026 			} else if (do_devmaps) {
1027 				/* print device_maps for cd devices */
1028 				if (first) {
1029 					(void) printf(" ");
1030 				} else {
1031 					if (system_labeled) {
1032 						(void) printf("%s%d%s\\\n",
1033 						    dname, i, KV_TOKEN_DELIMIT);
1034 						(void) printf("\t%s%s\\\n",
1035 						    DA_CD_TYPE,
1036 						    KV_TOKEN_DELIMIT);
1037 						(void) printf("\t");
1038 					} else {
1039 						(void) printf("sr%d:\\\n", i);
1040 						(void) printf("\tsr:\\\n");
1041 						(void) printf("\t");
1042 					}
1043 					first++;
1044 				}
1045 				(void) printf("%s", cd[j].name);
1046 			}
1047 		}
1048 		if (do_devmaps && first) {
1049 			(void) printf("\n\n");
1050 			first = 0;
1051 		}
1052 	}
1053 	if (do_files && cd_count) {
1054 		dargs.rootdir = NULL;
1055 		dargs.devnames = NULL;
1056 		dargs.optflag = DA_ADD;
1057 		for (entry = devlist.cd; entry != NULL; entry = entry->next) {
1058 			dargs.devinfo = &(entry->devinfo);
1059 			(void) da_update_device(&dargs);
1060 		}
1061 	}
1062 
1063 	return (cd_count);
1064 }
1065 
1066 static void
1067 dormdisk(int cd_count)
1068 {
1069 	DIR *dirp;
1070 	struct dirent *dep;	/* directory entry pointer */
1071 	int	i, j;
1072 	char	*nm;		/* name/device of special device */
1073 	int	id;		/* disk id */
1074 	int	ctrl;		/* disk controller */
1075 	int	nrmdisk;	/* max array size */
1076 	int	fd = -1;
1077 	int	rmdisk_count;
1078 	int	first = 0;
1079 	int	is_cd;
1080 	int	checked;
1081 	int	removable;
1082 	char	path[MAXPATHLEN];
1083 	da_args	dargs;
1084 	deventry_t *entry;
1085 
1086 	nrmdisk = DFLT_RMDISK;
1087 	i = rmdisk_count = 0;
1088 
1089 	/*
1090 	 * scan /dev/dsk for rmdisk devices
1091 	 */
1092 	if ((dirp = opendir("/dev/dsk")) == NULL) {
1093 		perror("gettext(open /dev/dsk failure)");
1094 		exit(1);
1095 	}
1096 
1097 	while (dep = readdir(dirp)) {
1098 		is_cd = 0;
1099 		checked = 0;
1100 		removable = 0;
1101 		/* skip . .. etc... */
1102 		if (strncmp(dep->d_name, ".", 1) == NULL)
1103 			continue;
1104 
1105 		/* get device # (disk #) */
1106 		if (sscanf(dep->d_name, "c%dt%d", &ctrl, &id) <= 0)
1107 			continue;
1108 
1109 		/* see if we've already examined this device */
1110 		for (j = 0; j < i; j++) {
1111 			if (id == rmdisk[j].id &&
1112 			    ctrl == rmdisk[j].controller &&
1113 			    (strcmp(dep->d_name, rmdisk[j].name) == 0)) {
1114 				checked = 1;
1115 				break;
1116 			}
1117 			if (id == rmdisk[j].id && ctrl != rmdisk[j].controller)
1118 				/*
1119 				 * c2t0d0s0 is a different rmdisk than c3t0d0s0.
1120 				 */
1121 				id = rmdisk[j].id + 1;
1122 		}
1123 		if (checked)
1124 			continue;
1125 
1126 		/* ignore if this is a cd */
1127 		for (j = 0; j < cd_count; j++) {
1128 			if (id == cd[j].number && ctrl == cd[j].controller) {
1129 				is_cd = 1;
1130 				break;
1131 			}
1132 		}
1133 		if (is_cd)
1134 			continue;
1135 
1136 		/* see if device is removable */
1137 		(void) snprintf(path, sizeof (path), "%s%s", "/dev/rdsk/",
1138 		    dep->d_name);
1139 		if ((fd = open(path, O_RDONLY | O_NONBLOCK)) < 0)
1140 			continue;
1141 		(void) ioctl(fd, DKIOCREMOVABLE, &removable);
1142 		(void) close(fd);
1143 		if (removable == 0)
1144 			continue;
1145 
1146 		/*
1147 		 * add new entry to table (/dev/dsk + / + d_name + \0)
1148 		 * if array full, then expand it
1149 		 */
1150 		if (i == nrmdisk) {
1151 			/* will exit(1) if insufficient memory */
1152 			nrmdisk = expandmem(i, (void **)&rmdisk,
1153 			    sizeof (struct rmdisk));
1154 		}
1155 		nm = (char *)malloc(SIZE_OF_DSK + 1 + strlen(dep->d_name) + 1);
1156 		if (nm == NULL)
1157 			no_memory();
1158 		(void) strcpy(nm, "/dev/dsk/");
1159 		(void) strcat(nm, dep->d_name);
1160 		rmdisk[i].name = nm;
1161 		rmdisk[i].id = id;
1162 		rmdisk[i].controller = ctrl;
1163 		rmdisk[i].device = "";
1164 		rmdisk[i].number = id;
1165 		rmdisk_r[i].name = strdup(path);
1166 		i++;
1167 	}
1168 
1169 	rmdisk_count = i;
1170 	(void) closedir(dirp);
1171 
1172 	for (i = 0, j = rmdisk_count; i < rmdisk_count; i++, j++) {
1173 		if (j == nrmdisk) {
1174 			/* will exit(1) if insufficient memory */
1175 			nrmdisk = expandmem(j, (void **)&rmdisk,
1176 			    sizeof (struct rmdisk));
1177 		}
1178 		rmdisk[j].name = rmdisk_r[i].name;
1179 		rmdisk[j].id = rmdisk[i].id;
1180 		rmdisk[j].controller = rmdisk[i].controller;
1181 		rmdisk[j].device = rmdisk[i].device;
1182 		rmdisk[j].number = rmdisk[i].number;
1183 	}
1184 	rmdisk_count = j;
1185 
1186 	for (i = 0; i < 8; i++) {
1187 		for (j = 0; j < rmdisk_count; j++) {
1188 			if (rmdisk[j].id != i)
1189 				continue;
1190 			if (do_files) {
1191 				(void) da_add_list(&devlist, rmdisk[j].name, i,
1192 				    DA_RMDISK);
1193 			} else if (do_devalloc) {
1194 				/* print device_allocate for rmdisk devices */
1195 				(void) printf("%s%d%s\\\n",
1196 				    DA_RMDISK_NAME, i, KV_DELIMITER);
1197 				(void) printf("\t%s%s\\\n",
1198 				    DA_RMDISK_TYPE, KV_DELIMITER);
1199 				(void) printf("\t%s%s\\\n",
1200 				    DA_RESERVED, KV_DELIMITER);
1201 				(void) printf("\t%s%s\\\n",
1202 				    DA_RESERVED, KV_DELIMITER);
1203 				(void) printf("\t%s%s\\\n",
1204 				    DEFAULT_DEV_ALLOC_AUTH, KV_DELIMITER);
1205 				(void) printf("\t%s\n", DA_DEFAULT_DISK_CLEAN);
1206 				break;
1207 			} else if (do_devmaps) {
1208 				/* print device_maps for rmdisk devices */
1209 				if (first) {
1210 					(void) printf(" ");
1211 				} else {
1212 					(void) printf("%s%d%s\\\n",
1213 					    DA_RMDISK_NAME, i,
1214 					    KV_TOKEN_DELIMIT);
1215 					(void) printf("\t%s%s\\\n",
1216 					    DA_RMDISK_TYPE, KV_TOKEN_DELIMIT);
1217 					(void) printf("\t");
1218 					first++;
1219 				}
1220 				(void) printf("%s", rmdisk[j].name);
1221 			}
1222 		}
1223 		if (do_devmaps && first) {
1224 			(void) printf("\n\n");
1225 			first = 0;
1226 		}
1227 	}
1228 	if (do_files && rmdisk_count) {
1229 		dargs.rootdir = NULL;
1230 		dargs.devnames = NULL;
1231 		dargs.optflag = DA_ADD;
1232 		for (entry = devlist.rmdisk; entry != NULL;
1233 		    entry = entry->next) {
1234 			dargs.devinfo = &(entry->devinfo);
1235 			(void) da_update_device(&dargs);
1236 		}
1237 	}
1238 }
1239 
1240 /* set default array sizes */
1241 static void
1242 initmem()
1243 {
1244 	tape  = (struct tape *)calloc(DFLT_NTAPE, sizeof (struct tape));
1245 	audio = (struct audio *)calloc(DFLT_NAUDIO, sizeof (struct audio));
1246 	cd    = (struct cd *)calloc(DFLT_NCD, sizeof (struct cd));
1247 	fp    = (struct fp *)calloc(DFLT_NFP, sizeof (struct fp));
1248 	if (system_labeled) {
1249 		rmdisk = (struct rmdisk *)calloc(DFLT_RMDISK,
1250 		    sizeof (struct rmdisk));
1251 		if (rmdisk == NULL)
1252 			no_memory();
1253 		rmdisk_r = (struct rmdisk *)calloc(DFLT_RMDISK,
1254 		    sizeof (struct rmdisk));
1255 		if (rmdisk_r == NULL)
1256 			no_memory();
1257 	}
1258 
1259 	if (tape == NULL || audio == NULL || cd == NULL || fp == NULL)
1260 		no_memory();
1261 
1262 	devlist.audio = devlist.cd = devlist.floppy = devlist.rmdisk =
1263 	    devlist.tape = NULL;
1264 }
1265 
1266 /* note n will be # elments in array (and could be 0) */
1267 static int
1268 expandmem(int n, void **array, int size)
1269 {
1270 	void *old = *array;
1271 	void *new;
1272 
1273 	/* get new array space (n + DELTA) */
1274 	new = (void *)calloc(n + DELTA,  size);
1275 
1276 	if (new == NULL) {
1277 		perror("memory allocation failed");
1278 		exit(1);
1279 	}
1280 
1281 	/* copy old array into new space */
1282 	bcopy(old, new, n * size);
1283 
1284 	/* now release old arrary */
1285 	free(old);
1286 
1287 	*array = new;
1288 
1289 	return (n + DELTA);
1290 }
1291 
1292 static void
1293 no_memory(void)
1294 {
1295 	(void) fprintf(stderr, "%s: %s\n", "mkdevalloc",
1296 	    gettext("out of memory"));
1297 	exit(1);
1298 	/* NOT REACHED */
1299 }
1300