Mercurial > illumos > onarm
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); +}