OpenSolaris_b135/cmd/allocate/dminfo.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include <unistd.h>
#include <malloc.h>
#include <memory.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/file.h>
#include <fcntl.h>
#include <bsm/devices.h>
#define	DMPFILE	"/etc/security/device_maps"
#define	RETRY_SLEEP	6
#define	RETRY_COUNT	10
#define	EINVOKE	2
#define	EFAIL 1

#if !defined(TEXT_DOMAIN)
#define	TEXT_DOMAIN "SUNW_BSM_DMINFO"
#endif

extern off_t lseek();

char	*getdmapfield();
char	*getdmapdfield();
static void	printdmapent();
static void	dmapi_err();

static char	*prog_name;

/*
 * printdmapent(dmapp) prints a devmap_t structure pointed to by dmapp.
 */
static void
printdmapent(dmapp)
	devmap_t *dmapp;
{
	(void) printf("%s:", dmapp->dmap_devname);
	(void) printf("%s:", dmapp->dmap_devtype);
	(void) printf("%s", dmapp->dmap_devlist);
	(void) printf("\n");
}


/*
 * dmapi_err(exit_code,err_msg) prints message pointed to by err_msg to
 * stderr. Then prints usage message to stderr. Then exits program with
 * exit_code.
 *
 */
static void
dmapi_err(int exit_code, char *err_msg)
{
	if (err_msg != NULL) {
		(void) fprintf(stderr, "dmapinfo:%s\n", err_msg);
	}
	if (exit_code == EINVOKE) {
		(void) fprintf(stderr,
			"Usage: %s [-v] [-a] [-f filename] %s\n",
			prog_name,
			"[-d device ...]");
		(void) fprintf(stderr,
			"       %s [-v] [-a] [-f filename] %s\n",
			prog_name,
			"[-n name ...]");
		(void) fprintf(stderr,
			"       %s [-v] [-a] [-f filename] %s\n",
			prog_name,
			"[-t type ...]");
		(void) fprintf(stderr,
			"       %s [-v] [-a] [-f filename] %s\n",
			prog_name,
			"[-u Entry]");
	}

	exit(exit_code);
}

int
main(int argc, char **argv)
{
	devmap_t *dmapp;
	devmap_t dmap;
	char	*mptr;
	char	*tptr;
	char	*nptr;
	char	*filename = DMPFILE;
	int	name = 0;
	int	device = 0;
	int	file = 0;
	int	verbose = 0;
	int	cntr = 0;
	int	any = 0;
	int	update = 0;
	int	tp = 0;
	int	des;
	int	status;

	/* Internationalization */
	(void) setlocale(LC_ALL, "");
	(void) textdomain(TEXT_DOMAIN);

	/*
	 * point prog_name to invocation name
	 */
	if ((tptr = strrchr(*argv, '/')) != NULL)
		prog_name = ++tptr;
		else
		prog_name = *argv;
	argc--;
	argv++;
	/*
	 * parse arguments
	 */
	while ((argc >= 1) && (argv[0][0] == '-')) {
		switch (argv[0][1]) {
		case 'a':
			any++;
			break;
		case 'd':
			if ((name) || (device) || (update) || (tp)) {
				dmapi_err(EINVOKE,
					gettext("option conflict"));
			}
			device++;
			break;
		case 'f':
			argc--;
			argv++;
			if (argc <= 0)
				dmapi_err(EINVOKE,
					gettext("missing file name"));
			filename = *argv;
			file++;
			break;
		case 'n':
			if ((name) || (device) || (update) || (tp)) {
				dmapi_err(EINVOKE,
					gettext("option conflict"));
			}
			name++;
			break;
		case 't':
			if ((name) || (device) || (update) || (tp)) {
				dmapi_err(EINVOKE,
					gettext("option conflict"));
			}
			tp++;
			break;
		case 'u':
			if ((name) || (device) || (update) || (tp)) {
				dmapi_err(EINVOKE,
					gettext("option conflict"));
			}
			update++;
			break;
		case 'v':
			verbose++;
			break;
		default:
			dmapi_err(EINVOKE,
				gettext("bad option"));
			break;
		}
		argc--;
		argv++;
	}
	/*
	 * -d(device) -n(name) and -u(update) switches require at least one
	 * argument.
	 */
	if (file)
		setdmapfile(filename);
	if ((device) || (name) || (update) || (tp)) {
		if (argc < 1) {
			dmapi_err(EINVOKE,
				gettext("insufficient args for this option"));
		}
	}
	if (update) {
		/*
		 * -u(update) switch requires only one argument
		 */
		if (argc != 1) {
			dmapi_err(EINVOKE,
				gettext("too many args for this option"));
		}
		/*
		 * read entry argument from stdin into a devmap_t known as dmap
		 */
		if ((dmap.dmap_devname = getdmapfield(*argv)) == NULL) {
			dmapi_err(EINVOKE,
				gettext("Bad dmap_devname in entry argument"));
		}
		if ((dmap.dmap_devtype = getdmapfield(NULL)) ==
			NULL) {
			dmapi_err(EINVOKE,
				gettext("Bad dmap_devtype in entry Argument"));
		}
		if ((dmap.dmap_devlist = getdmapfield(NULL)) ==
			NULL) {
			dmapi_err(EINVOKE,
				gettext("Bad dmap_devlist in entry argument"));
		}
		/*
		 * Find out how long device list is and create a buffer to
		 * hold it.  Then copy it there. This is done since we do not
		 * want to corrupt the existing string.
		 */
		cntr = strlen(dmap.dmap_devlist) + 1;
		mptr = calloc((unsigned)cntr, sizeof (char));
		if (mptr == NULL) {
			if (verbose) {
				(void) fprintf(stderr,
					gettext(
					"dmapinfo: Cannot calloc memory\n"));
			}
			exit(1);
		}
		(void) strcpy(mptr, dmap.dmap_devlist);
		/*
		 * open the device maps file for read/ write. We are not
		 * sure we want to write to it yet but we may and this is a
		 * easy way to get the file descriptor. We want the file
		 * descriptor so we can lock the file.
		 */
		if ((des = open(filename, O_RDWR)) < 0) {
			if (verbose) {
				(void) fprintf(stderr,
				gettext("dmapinfo: Cannot open %s\n"),
				    filename);
			}
			exit(1);
		}
		cntr = 0;
#ifdef CMW
		while ((status = flock(des, LOCK_EX | LOCK_NB) == -1) &&
			(cntr++ < RETRY_COUNT)) {
			(void) sleep(RETRY_SLEEP);
		}
#else
		while (((status = lockf(des, F_TLOCK, 0)) == -1) &&
			(cntr++ < RETRY_COUNT)) {
			(void) sleep(RETRY_SLEEP);
		}
#endif
		if (status == -1) {
			if (verbose) {
				(void) fprintf(stderr,
			gettext("dmapinfo: Cannot lock %s\n"), filename);
			}
			exit(1);
		}
		/*
		 * Now that we have the device_maps file then lets check
		 * for previous entrys with the same name.  If it already
		 * exists then we will exit with status of 1.
		 */
		if (verbose) {
			(void) fprintf(stderr,
			gettext("dmapinfo: Checking %s for name (%s).\n"),
				filename, dmap.dmap_devname);
		}
		if (getdmapnam(dmap.dmap_devname) != NULL) {
			if (verbose) {
				(void) fprintf(stderr,
			gettext("dmapinfo: Device name (%s) found in %s.\n"),
					dmap.dmap_devname, filename);
			}
			exit(1);
		}
		if (verbose) {
			(void) fprintf(stderr,
		gettext("dmapinfo: Device name (%s) not found in %s.\n"),
				dmap.dmap_devname, filename);
		}
		/*
		 * We now Know name does not exist and now we need to check
		 * to see if any of the devices in the device list are in the
		 * device maps file. If the already exist then we will exit
		 * with a status of 1.
		 */
		nptr = mptr;
		nptr = getdmapdfield(nptr);
		while (nptr) {
			if (verbose) {
				(void) fprintf(stderr,
				    gettext("dmapinfo: "
					"Check %s for device (%s).\n"),
				    filename, nptr);
			}
			if (getdmapdev(nptr) != NULL) {
				if (verbose) {
					(void) fprintf(stderr,
					    gettext("dmapinfo: "
						"Device (%s) found in %s.\n"),
					    nptr, filename);
				}
				exit(1);
			}
			if (verbose) {
				(void) fprintf(stderr,
				    gettext("dmapinfo: "
					"Device (%s) not found in %s.\n"),
				    nptr, filename);
			}
			nptr = getdmapdfield(NULL);
		}
		/*
		 * Good the entry is uniq. So lets find out how long it is
		 * and add it to the end of device maps file in a pretty
		 * way.
		 */
		if (verbose) {
			(void) fprintf(stderr, "dmapinfo: Adding entry to %s\n",
				filename);
			printdmapent(&dmap);
		}
		cntr = strlen(dmap.dmap_devname);
		cntr += strlen(dmap.dmap_devtype);
		cntr += strlen(dmap.dmap_devlist);
		cntr += 15;
		tptr = calloc((unsigned)cntr, sizeof (char));
		if (tptr == NULL) {
			exit(1);
		}
		(void) strcat(tptr, dmap.dmap_devname);
		(void) strcat(tptr, ":\\\n\t");
		(void) strcat(tptr, dmap.dmap_devtype);
		(void) strcat(tptr, ":\\\n\t");
		(void) strcat(tptr, dmap.dmap_devlist);
		(void) strcat(tptr, ":\\\n\t");
		(void) strcat(tptr, "\n");
		cntr = strlen(tptr);
#ifdef CMW
		if (lseek(des, 0L, L_XTND) == -1L) {
			exit(1);
		}
#else
		if (lseek(des, 0L, SEEK_END) == -1L) {
			exit(1);
		}
#endif
		if (write(des, tptr, cntr) == -1) {
			exit(1);
		}
		if (close(des) == -1) {
			exit(1);
		}
		if (verbose) {
			(void) fprintf(stderr, "dmapinfo: Entry added to %s\n",
				filename);
		}
		exit(0);
	}
	/*
	 * Look for devices in device_maps file. If verbose switch is set
	 * then print entry(s) found. If "any" switch  is set then, if any
	 * device is found will result in a exit status of 0. If "any" switch
	 * is not set then, if any device is not will result in a exit status
	 * of 1.
	 */
	if (device) {
		setdmapent();
		while (argc >= 1) {
			if ((dmapp = getdmapdev(*argv)) != NULL) {
				if (verbose) {
					printdmapent(dmapp);
				}
				cntr++;
			} else if (any == 0) {
				enddmapent();
				exit(1);
			}
			argc--;
			argv++;
		}
		enddmapent();
		if (cntr != 0)
			exit(0);
		exit(1);
	}
	/*
	 * Look for names in device_maps file. If verbose switch is set
	 * then print entry(s) found. If "any" switch  is set then, if any
	 * name is found will result in a exit status of 0. If "any" switch
	 * is not set then, if any name is not will result in a exit status
	 * of 1.
	 */
	if (name) {
		setdmapent();
		while (argc >= 1) {
			if ((dmapp = getdmapnam(*argv)) != NULL) {
				if (verbose) {
					printdmapent(dmapp);
				}
				cntr++;
			} else if (any == 0)
				exit(1);
			argc--;
			argv++;
		}
		enddmapent();
		if (cntr != 0)
			exit(0);
		exit(1);
	}
	/*
	 * Read all entrys from device maps file. If verbose flag is set
	 * then all the device maps files are printed.  This is useful for
	 * piping to grep. Also this option used without the verbose option
	 * is useful to check for device maps file and for at least one
	 * entry.  If the device maps file is found and there is one entry
	 * the return status is 0.
	 */
	if (tp) {
		cntr = 0;
		setdmapent();
		while (argc >= 1) {
			while ((dmapp = getdmaptype(*argv)) != 0) {
				cntr++;
				if (verbose) {
					printdmapent(dmapp);
				}
			}
			if ((any == 0) && (cntr == 0)) {
				enddmapent();
				exit(1);
			}
			argc--;
			argv++;
		}
		enddmapent();
		if (cntr == 0)
			exit(1);
		exit(0);
	}
	/*
	 * Read all entrys from device maps file. If verbose flag is set
	 * then all the device maps files are printed.  This is useful for
	 * piping to grep. Also this option used without the verbose option
	 * is useful to check for device maps file and for atleast one
	 * entry.  If the device maps file is found and there is one entry
	 * the return status is 0.
	 */
	cntr = 0;
	setdmapent();
	while ((dmapp = getdmapent()) != 0) {
		cntr++;
		if (verbose) {
			printdmapent(dmapp);
		}
	}
	enddmapent();
	if (cntr == 0)
		exit(1);
	return (0);
}