Home | History | Annotate | Download | only in allocate
      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