xref: /illumos-gate/usr/src/cmd/allocate/dminfo.c (revision 45916cd2)
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  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
22  * Use is subject to license terms.
23  */
24 
25 #pragma ident	"%Z%%M%	%I%	%E% SMI"
26 
27 #include <locale.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <malloc.h>
34 #include <memory.h>
35 #include <sys/param.h>
36 #include <sys/types.h>
37 #include <sys/file.h>
38 #include <fcntl.h>
39 #include <bsm/devices.h>
40 #define	DMPFILE	"/etc/security/device_maps"
41 #define	RETRY_SLEEP	6
42 #define	RETRY_COUNT	10
43 #define	EINVOKE	2
44 #define	EFAIL 1
45 
46 #if !defined(TEXT_DOMAIN)
47 #define	TEXT_DOMAIN "SUNW_BSM_DMINFO"
48 #endif
49 
50 extern off_t lseek();
51 
52 char	*getdmapfield();
53 char	*getdmapdfield();
54 static void	printdmapent();
55 static void	dmapi_err();
56 
57 static char	*prog_name;
58 
59 /*
60  * printdmapent(dmapp) prints a devmap_t structure pointed to by dmapp.
61  */
62 static void
63 printdmapent(dmapp)
64 	devmap_t *dmapp;
65 {
66 	(void) printf("%s:", dmapp->dmap_devname);
67 	(void) printf("%s:", dmapp->dmap_devtype);
68 	(void) printf("%s", dmapp->dmap_devlist);
69 	(void) printf("\n");
70 }
71 
72 
73 /*
74  * dmapi_err(exit_code,err_msg) prints message pointed to by err_msg to
75  * stderr. Then prints usage message to stderr. Then exits program with
76  * exit_code.
77  *
78  */
79 static void
80 dmapi_err(int exit_code, char *err_msg)
81 {
82 	if (err_msg != NULL) {
83 		(void) fprintf(stderr, "dmapinfo:%s\n", err_msg);
84 	}
85 	if (exit_code == EINVOKE) {
86 		(void) fprintf(stderr,
87 			"Usage: %s [-v] [-a] [-f filename] %s\n",
88 			prog_name,
89 			"[-d device ...]");
90 		(void) fprintf(stderr,
91 			"       %s [-v] [-a] [-f filename] %s\n",
92 			prog_name,
93 			"[-n name ...]");
94 		(void) fprintf(stderr,
95 			"       %s [-v] [-a] [-f filename] %s\n",
96 			prog_name,
97 			"[-t type ...]");
98 		(void) fprintf(stderr,
99 			"       %s [-v] [-a] [-f filename] %s\n",
100 			prog_name,
101 			"[-u Entry]");
102 	}
103 
104 	exit(exit_code);
105 }
106 
107 int
108 main(int argc, char **argv)
109 {
110 	devmap_t *dmapp;
111 	devmap_t dmap;
112 	char	*mptr;
113 	char	*tptr;
114 	char	*nptr;
115 	char	*filename = DMPFILE;
116 	int	name = 0;
117 	int	device = 0;
118 	int	file = 0;
119 	int	verbose = 0;
120 	int	cntr = 0;
121 	int	any = 0;
122 	int	update = 0;
123 	int	tp = 0;
124 	int	des;
125 	int	status;
126 
127 	/* Internationalization */
128 	(void) setlocale(LC_ALL, "");
129 	(void) textdomain(TEXT_DOMAIN);
130 
131 	/*
132 	 * point prog_name to invocation name
133 	 */
134 	if ((tptr = strrchr(*argv, '/')) != NULL)
135 		prog_name = ++tptr;
136 		else
137 		prog_name = *argv;
138 	argc--;
139 	argv++;
140 	/*
141 	 * parse arguments
142 	 */
143 	while ((argc >= 1) && (argv[0][0] == '-')) {
144 		switch (argv[0][1]) {
145 		case 'a':
146 			any++;
147 			break;
148 		case 'd':
149 			if ((name) || (device) || (update) || (tp)) {
150 				dmapi_err(EINVOKE,
151 					gettext("option conflict"));
152 			}
153 			device++;
154 			break;
155 		case 'f':
156 			argc--;
157 			argv++;
158 			if (argc <= 0)
159 				dmapi_err(EINVOKE,
160 					gettext("missing file name"));
161 			filename = *argv;
162 			file++;
163 			break;
164 		case 'n':
165 			if ((name) || (device) || (update) || (tp)) {
166 				dmapi_err(EINVOKE,
167 					gettext("option conflict"));
168 			}
169 			name++;
170 			break;
171 		case 't':
172 			if ((name) || (device) || (update) || (tp)) {
173 				dmapi_err(EINVOKE,
174 					gettext("option conflict"));
175 			}
176 			tp++;
177 			break;
178 		case 'u':
179 			if ((name) || (device) || (update) || (tp)) {
180 				dmapi_err(EINVOKE,
181 					gettext("option conflict"));
182 			}
183 			update++;
184 			break;
185 		case 'v':
186 			verbose++;
187 			break;
188 		default:
189 			dmapi_err(EINVOKE,
190 				gettext("bad option"));
191 			break;
192 		}
193 		argc--;
194 		argv++;
195 	}
196 	/*
197 	 * -d(device) -n(name) and -u(update) switches require at least one
198 	 * argument.
199 	 */
200 	if (file)
201 		setdmapfile(filename);
202 	if ((device) || (name) || (update) || (tp)) {
203 		if (argc < 1) {
204 			dmapi_err(EINVOKE,
205 				gettext("insufficient args for this option"));
206 		}
207 	}
208 	if (update) {
209 		/*
210 		 * -u(update) switch requires only one argument
211 		 */
212 		if (argc != 1) {
213 			dmapi_err(EINVOKE,
214 				gettext("too many args for this option"));
215 		}
216 		/*
217 		 * read entry argument from stdin into a devmap_t known as dmap
218 		 */
219 		if ((dmap.dmap_devname = getdmapfield(*argv)) == NULL) {
220 			dmapi_err(EINVOKE,
221 				gettext("Bad dmap_devname in entry argument"));
222 		}
223 		if ((dmap.dmap_devtype = getdmapfield(NULL)) ==
224 			NULL) {
225 			dmapi_err(EINVOKE,
226 				gettext("Bad dmap_devtype in entry Argument"));
227 		}
228 		if ((dmap.dmap_devlist = getdmapfield(NULL)) ==
229 			NULL) {
230 			dmapi_err(EINVOKE,
231 				gettext("Bad dmap_devlist in entry argument"));
232 		}
233 		/*
234 		 * Find out how long device list is and create a buffer to
235 		 * hold it.  Then copy it there. This is done since we do not
236 		 * want to corrupt the existing string.
237 		 */
238 		cntr = strlen(dmap.dmap_devlist) + 1;
239 		mptr = calloc((unsigned)cntr, sizeof (char));
240 		if (mptr == NULL) {
241 			if (verbose) {
242 				(void) fprintf(stderr,
243 					gettext(
244 					"dmapinfo: Cannot calloc memory\n"));
245 			}
246 			exit(1);
247 		}
248 		(void) strcpy(mptr, dmap.dmap_devlist);
249 		/*
250 		 * open the device maps file for read/ write. We are not
251 		 * sure we want to write to it yet but we may and this is a
252 		 * easy way to get the file descriptor. We want the file
253 		 * descriptor so we can lock the file.
254 		 */
255 		if ((des = open(filename, O_RDWR)) < 0) {
256 			if (verbose) {
257 				(void) fprintf(stderr,
258 				gettext("dmapinfo: Cannot open %s\n"),
259 				    filename);
260 			}
261 			exit(1);
262 		}
263 		cntr = 0;
264 #ifdef CMW
265 		while ((status = flock(des, LOCK_EX | LOCK_NB) == -1) &&
266 			(cntr++ < RETRY_COUNT)) {
267 			(void) sleep(RETRY_SLEEP);
268 		}
269 #else
270 		while (((status = lockf(des, F_TLOCK, 0)) == -1) &&
271 			(cntr++ < RETRY_COUNT)) {
272 			(void) sleep(RETRY_SLEEP);
273 		}
274 #endif
275 		if (status == -1) {
276 			if (verbose) {
277 				(void) fprintf(stderr,
278 			gettext("dmapinfo: Cannot lock %s\n"), filename);
279 			}
280 			exit(1);
281 		}
282 		/*
283 		 * Now that we have the device_maps file then lets check
284 		 * for previous entrys with the same name.  If it already
285 		 * exists then we will exit with status of 1.
286 		 */
287 		if (verbose) {
288 			(void) fprintf(stderr,
289 			gettext("dmapinfo: Checking %s for name (%s).\n"),
290 				filename, dmap.dmap_devname);
291 		}
292 		if (getdmapnam(dmap.dmap_devname) != NULL) {
293 			if (verbose) {
294 				(void) fprintf(stderr,
295 			gettext("dmapinfo: Device name (%s) found in %s.\n"),
296 					dmap.dmap_devname, filename);
297 			}
298 			exit(1);
299 		}
300 		if (verbose) {
301 			(void) fprintf(stderr,
302 		gettext("dmapinfo: Device name (%s) not found in %s.\n"),
303 				dmap.dmap_devname, filename);
304 		}
305 		/*
306 		 * We now Know name does not exist and now we need to check
307 		 * to see if any of the devices in the device list are in the
308 		 * device maps file. If the already exist then we will exit
309 		 * with a status of 1.
310 		 */
311 		nptr = mptr;
312 		nptr = getdmapdfield(nptr);
313 		while (nptr) {
314 			if (verbose) {
315 				(void) fprintf(stderr,
316 				    gettext("dmapinfo: "
317 					"Check %s for device (%s).\n"),
318 				    filename, nptr);
319 			}
320 			if (getdmapdev(nptr) != NULL) {
321 				if (verbose) {
322 					(void) fprintf(stderr,
323 					    gettext("dmapinfo: "
324 						"Device (%s) found in %s.\n"),
325 					    nptr, filename);
326 				}
327 				exit(1);
328 			}
329 			if (verbose) {
330 				(void) fprintf(stderr,
331 				    gettext("dmapinfo: "
332 					"Device (%s) not found in %s.\n"),
333 				    nptr, filename);
334 			}
335 			nptr = getdmapdfield(NULL);
336 		}
337 		/*
338 		 * Good the entry is uniq. So lets find out how long it is
339 		 * and add it to the end of device maps file in a pretty
340 		 * way.
341 		 */
342 		if (verbose) {
343 			(void) fprintf(stderr, "dmapinfo: Adding entry to %s\n",
344 				filename);
345 			printdmapent(&dmap);
346 		}
347 		cntr = strlen(dmap.dmap_devname);
348 		cntr += strlen(dmap.dmap_devtype);
349 		cntr += strlen(dmap.dmap_devlist);
350 		cntr += 15;
351 		tptr = calloc((unsigned)cntr, sizeof (char));
352 		if (tptr == NULL) {
353 			exit(1);
354 		}
355 		(void) strcat(tptr, dmap.dmap_devname);
356 		(void) strcat(tptr, ":\\\n\t");
357 		(void) strcat(tptr, dmap.dmap_devtype);
358 		(void) strcat(tptr, ":\\\n\t");
359 		(void) strcat(tptr, dmap.dmap_devlist);
360 		(void) strcat(tptr, ":\\\n\t");
361 		(void) strcat(tptr, "\n");
362 		cntr = strlen(tptr);
363 #ifdef CMW
364 		if (lseek(des, 0L, L_XTND) == -1L) {
365 			exit(1);
366 		}
367 #else
368 		if (lseek(des, 0L, SEEK_END) == -1L) {
369 			exit(1);
370 		}
371 #endif
372 		if (write(des, tptr, cntr) == -1) {
373 			exit(1);
374 		}
375 		if (close(des) == -1) {
376 			exit(1);
377 		}
378 		if (verbose) {
379 			(void) fprintf(stderr, "dmapinfo: Entry added to %s\n",
380 				filename);
381 		}
382 		exit(0);
383 	}
384 	/*
385 	 * Look for devices in device_maps file. If verbose switch is set
386 	 * then print entry(s) found. If "any" switch  is set then, if any
387 	 * device is found will result in a exit status of 0. If "any" switch
388 	 * is not set then, if any device is not will result in a exit status
389 	 * of 1.
390 	 */
391 	if (device) {
392 		setdmapent();
393 		while (argc >= 1) {
394 			if ((dmapp = getdmapdev(*argv)) != NULL) {
395 				if (verbose) {
396 					printdmapent(dmapp);
397 				}
398 				cntr++;
399 			} else if (any == 0) {
400 				enddmapent();
401 				exit(1);
402 			}
403 			argc--;
404 			argv++;
405 		}
406 		enddmapent();
407 		if (cntr != 0)
408 			exit(0);
409 		exit(1);
410 	}
411 	/*
412 	 * Look for names in device_maps file. If verbose switch is set
413 	 * then print entry(s) found. If "any" switch  is set then, if any
414 	 * name is found will result in a exit status of 0. If "any" switch
415 	 * is not set then, if any name is not will result in a exit status
416 	 * of 1.
417 	 */
418 	if (name) {
419 		setdmapent();
420 		while (argc >= 1) {
421 			if ((dmapp = getdmapnam(*argv)) != NULL) {
422 				if (verbose) {
423 					printdmapent(dmapp);
424 				}
425 				cntr++;
426 			} else if (any == 0)
427 				exit(1);
428 			argc--;
429 			argv++;
430 		}
431 		enddmapent();
432 		if (cntr != 0)
433 			exit(0);
434 		exit(1);
435 	}
436 	/*
437 	 * Read all entrys from device maps file. If verbose flag is set
438 	 * then all the device maps files are printed.  This is useful for
439 	 * piping to grep. Also this option used without the verbose option
440 	 * is useful to check for device maps file and for at least one
441 	 * entry.  If the device maps file is found and there is one entry
442 	 * the return status is 0.
443 	 */
444 	if (tp) {
445 		cntr = 0;
446 		setdmapent();
447 		while (argc >= 1) {
448 			while ((dmapp = getdmaptype(*argv)) != 0) {
449 				cntr++;
450 				if (verbose) {
451 					printdmapent(dmapp);
452 				}
453 			}
454 			if ((any == 0) && (cntr == 0)) {
455 				enddmapent();
456 				exit(1);
457 			}
458 			argc--;
459 			argv++;
460 		}
461 		enddmapent();
462 		if (cntr == 0)
463 			exit(1);
464 		exit(0);
465 	}
466 	/*
467 	 * Read all entrys from device maps file. If verbose flag is set
468 	 * then all the device maps files are printed.  This is useful for
469 	 * piping to grep. Also this option used without the verbose option
470 	 * is useful to check for device maps file and for atleast one
471 	 * entry.  If the device maps file is found and there is one entry
472 	 * the return status is 0.
473 	 */
474 	cntr = 0;
475 	setdmapent();
476 	while ((dmapp = getdmapent()) != 0) {
477 		cntr++;
478 		if (verbose) {
479 			printdmapent(dmapp);
480 		}
481 	}
482 	enddmapent();
483 	if (cntr == 0)
484 		exit(1);
485 	return (0);
486 }
487