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