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