diff usr/src/cmd/allocate/add_allocatable.c @ 0:c9caec207d52 b86

Initial porting based on b86
author Koji Uno <koji.uno@sun.com>
date Tue, 02 Jun 2009 18:56:50 +0900
parents
children 1a15d5aaf794
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/allocate/add_allocatable.c	Tue Jun 02 18:56:50 2009 +0900
@@ -0,0 +1,505 @@
+/*
+ * 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 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"@(#)add_allocatable.c	1.1	07/05/24 SMI"
+
+/*
+ * add_allocatable -
+ *	a command-line interface to add device to device_allocate and
+ *	device_maps.
+ */
+
+#ifndef	__EXTENSIONS__
+#define	__EXTENSIONS__		/* needed for _strtok_r */
+#endif
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <locale.h>
+#include <libintl.h>
+#include <pwd.h>
+#include <nss_dbdefs.h>
+#include <auth_attr.h>
+#include <auth_list.h>
+#include <zone.h>
+#include <tsol/label.h>
+#include <bsm/devices.h>
+#include <bsm/devalloc.h>
+
+#define	NO_OVERRIDE	-1
+
+int check_args(da_args *);
+int process_args(int, char **, da_args *, char *);
+int scan_label(char *, char *);
+void usage(da_args *, char *);
+
+int system_labeled = 0;
+
+int
+main(int argc, char *argv[])
+{
+	int		rc;
+	uid_t		uid;
+	char		*progname;
+	char		pwbuf[NSS_LINELEN_PASSWD];
+	struct passwd	pwd;
+	da_args		dargs;
+	devinfo_t	devinfo;
+
+	(void) setlocale(LC_ALL, "");
+#if !defined(TEXT_DOMAIN)
+#define	TEXT_DOMAIN	"SYS_TEST"
+#endif
+	(void) textdomain(TEXT_DOMAIN);
+	if ((progname = strrchr(argv[0], '/')) == NULL)
+		progname = argv[0];
+	else
+		progname++;
+
+	system_labeled = is_system_labeled();
+	if (system_labeled) {
+		/*
+		 * this command can be run only in the global zone.
+		 */
+		if (getzoneid() != GLOBAL_ZONEID) {
+			(void) fprintf(stderr, "%s%s", progname,
+			    gettext(" : must be run in global zone\n"));
+			exit(1);
+		}
+	} else {
+		/*
+		 * this command works in Trusted Extensions only.
+		 */
+		(void) fprintf(stderr, "%s%s", progname,
+		    gettext(" : need to install Trusted Extensions\n"));
+		exit(1);
+	}
+
+	dargs.optflag = 0;
+	dargs.rootdir = NULL;
+	dargs.devnames = NULL;
+	dargs.devinfo = &devinfo;
+
+	if (strcmp(progname, "add_allocatable") == 0) {
+		dargs.optflag |= DA_ADD;
+	} else if (strcmp(progname, "remove_allocatable") == 0) {
+		dargs.optflag |= DA_REMOVE;
+	} else {
+		usage(&dargs, progname);
+		exit(1);
+	}
+
+	uid = getuid();
+	if ((getpwuid_r(uid, &pwd, pwbuf, sizeof (pwbuf))) == NULL) {
+		(void) fprintf(stderr, "%s%s", progname,
+		    gettext(" : getpwuid_r failed: "));
+		(void) fprintf(stderr, "%s\n", strerror(errno));
+		exit(2);
+	}
+
+	if (chkauthattr(DEVICE_CONFIG_AUTH, pwd.pw_name) != 1) {
+		(void) fprintf(stderr, "%s%s%s", progname,
+		    gettext(" : user lacks authorization:  \n"),
+		    DEVICE_CONFIG_AUTH);
+		exit(4);
+	}
+
+	if (process_args(argc, argv, &dargs, progname) != 0) {
+		usage(&dargs, progname);
+		exit(1);
+	}
+
+	if (dargs.optflag & DA_ADD) {
+		if (check_args(&dargs) == NO_OVERRIDE) {
+			(void) fprintf(stderr, "%s%s%s%s", progname,
+			    gettext(" : entry exists for "),
+			    dargs.devinfo->devname, gettext("\n"));
+			usage(&dargs, progname);
+			exit(3);
+		}
+	}
+
+	if (dargs.optflag & DA_DEFATTRS)
+		rc = da_update_defattrs(&dargs);
+	else
+		rc = da_update_device(&dargs);
+
+	if ((rc != 0) && (!(dargs.optflag & DA_SILENT))) {
+		if (rc == -2)
+			(void) fprintf(stderr, "%s%s", progname,
+			    gettext(" : device name/type/list missing\n"));
+		else if (dargs.optflag & DA_ADD)
+			(void) fprintf(stderr, "%s%s", progname,
+			    gettext(" : error adding/updating device\n"));
+		else if (dargs.optflag & DA_REMOVE)
+			(void) fprintf(stderr, "%s%s", progname,
+			    gettext(" : error removing device\n"));
+		rc = 2;	/* exit code for 'Unknown system error' in man page */
+	}
+
+	return (rc);
+}
+
+int
+process_args(int argc, char **argv, da_args *dargs, char *progname)
+{
+	int 		c;
+	int		aflag, cflag, dflag, fflag, lflag, nflag, oflag, tflag;
+	extern char	*optarg;
+	devinfo_t	*devinfo;
+
+	devinfo = dargs->devinfo;
+	aflag = cflag = dflag = fflag = lflag = nflag = oflag = tflag = 0;
+	devinfo->devname = devinfo->devtype = devinfo->devauths =
+	    devinfo->devexec = devinfo->devopts = devinfo->devlist = NULL;
+	devinfo->instance = 0;
+
+	while ((c = getopt(argc, argv, "a:c:dfl:n:o:st:")) != EOF) {
+		switch (c) {
+		case 'a':
+			devinfo->devauths = optarg;
+			aflag++;
+			break;
+		case 'c':
+			devinfo->devexec = optarg;
+			if (strlen(devinfo->devexec) == 0) {
+				if (!(dargs->optflag & DA_SILENT))
+					(void) fprintf(stderr, "%s%s", progname,
+					    gettext(" : device clean program"
+					    " name not found\n"));
+				return (1);
+			}
+			cflag++;
+			break;
+		case 'd':
+			dargs->optflag |= DA_DEFATTRS;
+			dflag++;
+			break;
+		case 'l':
+			devinfo->devlist = optarg;
+			if (strlen(devinfo->devlist) == 0) {
+				if (!(dargs->optflag & DA_SILENT))
+					(void) fprintf(stderr, "%s%s", progname,
+					    gettext(" : device file list"
+					    " not found\n"));
+				return (1);
+			}
+			lflag++;
+			break;
+		case 'f':
+			dargs->optflag |= DA_FORCE;
+			fflag++;
+			break;
+		case 'n':
+			devinfo->devname = optarg;
+			if (strlen(devinfo->devname) == 0) {
+				if (!(dargs->optflag & DA_SILENT))
+					(void) fprintf(stderr, "%s%s", progname,
+					    gettext(" : device name "
+					    "not found\n"));
+				return (1);
+			}
+			nflag++;
+			break;
+		case 'o':
+			/* check for field delimiters in the option */
+			if (strpbrk(optarg, ":;=") == NULL) {
+				if (!(dargs->optflag & DA_SILENT)) {
+					(void) fprintf(stderr, "%s%s%s",
+					    progname,
+					    gettext(" : invalid "
+					    "key=val string: "),
+					    optarg);
+					(void) fprintf(stderr, "%s",
+					    gettext("\n"));
+				}
+				return (1);
+			}
+			devinfo->devopts = optarg;
+			if (dargs->optflag & DA_ADD) {
+				if (scan_label(devinfo->devopts, progname) != 0)
+					return (1);
+			}
+			oflag++;
+			break;
+		case 's':
+			dargs->optflag |= DA_SILENT;
+			break;
+		case 't':
+			devinfo->devtype = optarg;
+			if (strlen(devinfo->devtype) == 0) {
+				if (!(dargs->optflag & DA_SILENT))
+					(void) fprintf(stderr, "%s%s", progname,
+					    gettext(" : device type "
+					    "not found\n"));
+				return (1);
+			}
+			tflag++;
+			break;
+		default	:
+			return (1);
+		}
+	}
+
+
+	if (dargs->optflag & DA_ADD) {
+		if (dflag) {
+			/* -d requires -t, but does not like -n */
+			if (nflag || tflag == 0)
+				return (1);
+		} else if (nflag == 0 && tflag == 0 && lflag == 0) {
+			/* require at least -n or -t or -l to be specified */
+			if (!(dargs->optflag & DA_SILENT))
+				(void) fprintf(stderr, "%s%s", progname,
+				    gettext(" : required options missing\n"));
+			return (1);
+		}
+	} else if (dargs->optflag & DA_REMOVE) {
+		if (dflag) {
+			/* -d requires -t, but does not like -n */
+			if (nflag || tflag == 0)
+				return (1);
+		} else if (nflag == 0 && tflag == 0) {
+			/* require at least -n or -t to be specified */
+			if (!(dargs->optflag & DA_SILENT))
+				(void) fprintf(stderr, "%s%s", progname,
+				    gettext(" : required options missing\n"));
+			return (1);
+		}
+		/* there's a bunch not accepted by remove_allocatable */
+		if (aflag || cflag || lflag || oflag)
+			return (1);
+	} else {
+		return (1);
+	}
+
+	/* check for option specified more than once */
+	if (aflag > 1 || cflag > 1 || lflag > 1 || fflag > 1 ||
+	    nflag > 1 || tflag > 1) {
+		if (!(dargs->optflag & DA_SILENT))
+			(void) fprintf(stderr, "%s%s", progname,
+			    gettext(" : multiple-defined options\n"));
+		return (1);
+	}
+
+	return (0);
+}
+
+int
+verify_label(char *token, char *progname)
+{
+	int		error = 0;
+	char		*p, *val, *str;
+
+	if ((strstr(token, DAOPT_MINLABEL) == NULL) &&
+	    (strstr(token, DAOPT_MAXLABEL) == NULL)) {
+		/* no label specified */
+		return (0);
+	}
+	if ((val = strchr(token, '=')) == NULL)
+		return (1);
+	val++;
+	/*
+	 * if non-default labels are specified, check if they are correct
+	 */
+	if ((strcmp(val, DA_DEFAULT_MIN) != 0) &&
+	    (strcmp(val, DA_DEFAULT_MAX) != 0)) {
+		m_label_t	*slabel = NULL;
+
+		str = strdup(val);
+		/* get rid of double quotes if they exist */
+		while (*str == '"')
+			str++;
+		if ((p = strchr(str, '"')) != NULL)
+			*p = '\0';
+		if (str_to_label(str, &slabel, MAC_LABEL, L_NO_CORRECTION,
+		    &error) == -1) {
+			(void) fprintf(stderr, "%s%s%s", progname,
+			    gettext(" : bad label input: "),
+			    val);
+			(void) fprintf(stderr, "%s", gettext("\n"));
+			free(str);
+			m_label_free(slabel);
+			return (1);
+		}
+		free(str);
+		m_label_free(slabel);
+	}
+
+	return (0);
+}
+
+int
+scan_label(char *devopts, char *progname)
+{
+	char		*tok = NULL;
+	char		*lasts, *optsarg;
+
+	if (devopts == NULL)
+		return (0);
+
+	if ((optsarg = strdup(devopts)) == NULL)
+		return (1);
+
+	if ((tok = strtok_r(optsarg, KV_TOKEN_DELIMIT, &lasts)) == NULL)
+		return (1);
+
+	if (verify_label(tok, progname) != 0) {
+		free(optsarg);
+		return (1);
+	}
+
+	while ((tok = strtok_r(NULL, KV_TOKEN_DELIMIT, &lasts)) != NULL) {
+		if (verify_label(tok, progname) != 0) {
+			free(optsarg);
+			return (1);
+		}
+	}
+
+	return (0);
+}
+
+int
+check_args(da_args *dargs)
+{
+	int		nlen;
+	char		*kval, *nopts, *ntok, *nstr,
+	    *defmin, *defmax, *defauths, *defexec;
+	kva_t		*kva;
+	devinfo_t	*devinfo;
+	devalloc_t	*da = NULL;
+	da_defs_t	*da_defs = NULL;
+
+	devinfo = dargs->devinfo;
+	/*
+	 * check if we're updating an existing entry without -f
+	 */
+	setdaent();
+	da = getdanam(devinfo->devname);
+	enddaent();
+	if (da && !(dargs->optflag & DA_FORCE)) {
+		freedaent(da);
+		return (NO_OVERRIDE);
+	}
+	if ((devinfo->devopts == NULL) ||
+	    (strstr(devinfo->devopts, DAOPT_MINLABEL) == NULL) ||
+	    (strstr(devinfo->devopts, DAOPT_MAXLABEL) == NULL) ||
+	    (devinfo->devauths == NULL) ||
+	    (devinfo->devexec == NULL)) {
+		/* fill in defaults as required */
+		defmin = DA_DEFAULT_MIN;
+		defmax = DA_DEFAULT_MAX;
+		defauths = DEFAULT_DEV_ALLOC_AUTH;
+		defexec = DA_DEFAULT_CLEAN;
+		setdadefent();
+		if (da_defs = getdadeftype(devinfo->devtype)) {
+			kva = da_defs->devopts;
+			if ((kval = kva_match(kva, DAOPT_MINLABEL)) != NULL)
+				defmin = strdup(kval);
+			if ((kval = kva_match(kva, DAOPT_MAXLABEL)) != NULL)
+				defmax = strdup(kval);
+			if ((kval = kva_match(kva, DAOPT_AUTHS)) != NULL)
+				defauths = strdup(kval);
+			if ((kval = kva_match(kva, DAOPT_CSCRIPT)) != NULL)
+				defexec = strdup(kval);
+			freedadefent(da_defs);
+		}
+		enddadefent();
+		if (devinfo->devauths == NULL)
+			devinfo->devauths = defauths;
+		if (devinfo->devexec == NULL)
+			devinfo->devexec = defexec;
+		if (devinfo->devopts == NULL) {
+			/* add default minlabel and maxlabel */
+			nlen = strlen(DAOPT_MINLABEL) + strlen(KV_ASSIGN) +
+			    strlen(defmin) + strlen(KV_TOKEN_DELIMIT) +
+			    strlen(DAOPT_MAXLABEL) + strlen(KV_ASSIGN) +
+			    strlen(defmax) + 1;		/* +1 for terminator */
+			if (nopts = (char *)malloc(nlen)) {
+				(void) snprintf(nopts, nlen, "%s%s%s%s%s%s%s",
+				    DAOPT_MINLABEL, KV_ASSIGN, defmin,
+				    KV_TOKEN_DELIMIT,
+				    DAOPT_MAXLABEL, KV_ASSIGN, defmax);
+				devinfo->devopts = nopts;
+			}
+		} else {
+			if (strstr(devinfo->devopts, DAOPT_MINLABEL) == NULL) {
+				/* add default minlabel */
+				ntok = DAOPT_MINLABEL;
+				nstr = defmin;
+				nlen = strlen(devinfo->devopts) +
+				    strlen(KV_TOKEN_DELIMIT) +
+				    strlen(ntok) + strlen(KV_ASSIGN) +
+				    strlen(nstr) + 1;
+				if (nopts = (char *)malloc(nlen)) {
+					(void) snprintf(nopts, nlen,
+					    "%s%s%s%s%s",
+					    devinfo->devopts, KV_TOKEN_DELIMIT,
+					    ntok, KV_ASSIGN, nstr);
+					devinfo->devopts = nopts;
+				}
+			}
+			if (strstr(devinfo->devopts, DAOPT_MAXLABEL) == NULL) {
+				/* add default maxlabel */
+				ntok = DAOPT_MAXLABEL;
+				nstr = defmax;
+				nlen = strlen(devinfo->devopts) +
+				    strlen(KV_TOKEN_DELIMIT) +
+				    strlen(ntok) + strlen(KV_ASSIGN) +
+				    strlen(nstr) + 1;
+				if (nopts = (char *)malloc(nlen)) {
+					(void) snprintf(nopts, nlen,
+					    "%s%s%s%s%s",
+					    devinfo->devopts, KV_TOKEN_DELIMIT,
+					    ntok, KV_ASSIGN, nstr);
+					devinfo->devopts = nopts;
+				}
+			}
+		}
+	}
+
+	return (0);
+}
+
+void
+usage(da_args *dargs, char *progname)
+{
+	if (dargs->optflag & DA_SILENT)
+		return;
+	if (dargs->optflag & DA_ADD)
+		(void) fprintf(stderr, "%s%s%s", gettext("Usage: "), progname,
+		    gettext(" [-f][-s][-d] -n name -t type -l device-list"
+		    "\n\t[-a authorization] [-c cleaning program] "
+		    "[-o key=value]\n"));
+	else if (dargs->optflag & DA_REMOVE)
+		(void) fprintf(stderr, "%s%s%s", gettext("Usage: "), progname,
+		    gettext(" [-f][-s][-d] [-n name|-t type]\n"));
+	else
+		(void) fprintf(stderr, gettext("Invalid usage\n"), progname);
+}