# # 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 (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. # # Copyright (c) 2018, Joyent, Inc. ETCTSOLFILES = devalloc_defaults include ../Makefile.cmd CERRWARN += -Wno-unused-value CERRWARN += $(CNOWARN_UNINIT) CERRWARN += -Wno-parentheses CERRWARN += -Wno-clobbered # not linted SMATCH=off ROOTSEC = $(ROOTETC)/security ROOTSECDEV = $(ROOTSEC)/dev ROOTSECLIB = $(ROOTSEC)/lib ROOTSECAUD = $(ROOTSEC)/audio ROOTDIRS = $(ROOTSECDEV) $(ROOTSECLIB) $(ROOTSECAUD) ROOTMANIFESTDIR= $(ROOTSVCSYSTEMDEVICE) SVCMETHOD = svc-allocate MANIFEST = allocate.xml RTLCKS = audio fd0 sr0 st0 st1 CLEANfd = fd_clean CLEANsr = sr_clean CLEANst = st_clean CLEANaudio = audio_clean CLEANdisk = disk_clean CLEAN_SCRIPTS = $(CLEANfd) $(CLEANsr) $(CLEANst) $(CLEANaudio) $(CLEANdisk) WDW_SCRIPTS = wdwmsg wdwwrapper WDW_LINKS = $(CLEANaudio) $(CLEANdisk) $(CLEANst) SCRIPTS = $(CLEAN_SCRIPTS) $(WDW_SCRIPTS) ALLSCRIPTS = allscripts.sh PROGalloc = allocate PROGmkdevalloc = mkdevalloc PROGdminfo = dminfo PROGaddalloc = add_allocatable PROG = $(PROGalloc) $(PROGmkdevalloc) $(PROGdminfo) \ $(PROGaddalloc) LINKPROGalloc = deallocate list_devices LINKPROGmkdevalloc = mkdevmaps LINKPROGaddalloc = remove_allocatable POFILE = allocate_all.po POFILES = $(OBJS:%.o=%.po) $(ALLSCRIPTS:%.sh=%.po) DFLAGS += -D_REENTRANT CPPFLAGS += $(DFLAGS) ROOTLOCKS = $(RTLCKS:%=$(ROOTSECDEV)/%) ROOTSCRIPTS = $(SCRIPTS:%=$(ROOTSECLIB)/%) ROOTWDWLINKS = $(WDW_LINKS:%=$(ROOTSECLIB)/%.windowing) ROOTPROG = $(PROGallocate:%=$(ROOTUSRSBIN)/%) \ $(PROGmkdevalloc:%=$(ROOTUSRSBIN)/%) \ $(PROGdminfo:%=$(ROOTUSRSBIN)/%) \ $(PROGaddaloc:%=$(ROOTUSRSBIN)/%) ROOTLINKalloc = $(LINKPROGalloc:%=$(ROOTUSRSBIN)/%) ROOTLINKmkdevalloc = $(LINKPROGmkdevalloc:%=$(ROOTUSRSBIN)/%) ROOTLINKaddalloc = $(LINKPROGaddalloc:%=$(ROOTUSRSBIN)/%) ROOTLINKS = $(ROOTLINKalloc) $(ROOTLINKmkdevalloc) $(ROOTLINKaddalloc) PROGallocOBJS = allocate.o allocate3.o PROGmkdevallocOBJS = mkdevalloc.o PROGdminfoOBJS = dminfo.o PROGaddallocOBJS = add_allocatable.o OBJS = $(PROGallocOBJS) \ $(PROGmkdevallocOBJS) \ $(PROGdminfoOBJS) \ $(PROGaddallocOBJS) SRCS = $(OBJS:%.o=%.c) $(ROOTUSRSBIN)/% : FILEMODE = 555 $(ROOTUSRSBIN)/allocate : FILEMODE = 4555 $(ROOTSECDEV)/% : FILEMODE = 0400 $(ROOTSECLIB)/% : FILEMODE = 0555 lint : LDLIBS += -lbsm -lsec -lsecdb -ldevinfo -ltsol $(PROGalloc) : LDLIBS += -lbsm -lsec -lsecdb -ldevinfo -ltsol $(PROGmkdevalloc) : LDLIBS += -lbsm $(PROGdminfo) : LDLIBS += -lbsm $(PROGaddalloc) : LDLIBS += -lbsm -lsecdb -ltsol CLOBBERFILES += $(SCRIPTS) .KEEP_STATE: all : $(PROG) $(RTLCKS) $(SCRIPTS) install : $(PROG) $(ROOTDIRS) $(ROOTPROG) $(ROOTLOCKS) \ $(ROOTSCRIPTS) $(ROOTLINKS) $(ROOTWDWLINKS) \ $(ROOTETCTSOLFILES) $(ROOTMANIFEST) $(ROOTSVCMETHOD) $(RTLCKS): $(TOUCH) $@ $(ROOTSECLIB)/%: %.sh $(INS.rename) $(PROGalloc) : $(PROGallocOBJS) $(LINK.c) $(PROGallocOBJS) -o $@ $(LDLIBS) $(POST_PROCESS) $(PROGaddalloc) : $(PROGaddallocOBJS) $(LINK.c) $(PROGaddallocOBJS) -o $@ $(LDLIBS) $(POST_PROCESS) $(PROGmkdevalloc) : $(PROGmkdevallocOBJS) $(LINK.c) $(PROGmkdevallocOBJS) -o $@ $(LDLIBS) $(POST_PROCESS) $(PROGdminfo) : $(PROGdminfoOBJS) $(LINK.c) $(PROGdminfoOBJS) -o $@ $(LDLIBS) $(POST_PROCESS) $(ROOTDIRS) : $(INS.dir) $(ROOTSECDEV)/%: % $(INS.file) $(ROOTSECLIB)/%: % $(RM) $@ $(INS.file) $(ROOTLINKalloc) : $(PROGalloc:%=$(ROOTUSRSBIN)/%) $(RM) $@ $(LN) $(PROGalloc:%=$(ROOTUSRSBIN)/%) $@ $(ROOTLINKaddalloc) : $(PROGaddalloc:%=$(ROOTUSRSBIN)/%) $(RM) $@ $(LN) $(PROGaddalloc:%=$(ROOTUSRSBIN)/%) $@ $(ROOTLINKmkdevalloc) : $(PROGmkdevalloc:%=$(ROOTUSRSBIN)/%) $(RM) $@ $(LN) $(PROGmkdevalloc:%=$(ROOTUSRSBIN)/%) $@ $(ROOTETCSECLIB)/%.windowing: % $(RM) $@ $(SYMLINK) $< $@ $(POFILE): $(POFILES) $(RM) $@ $(CAT) $(POFILES) > $@ # # Concatenate all the scripts into one before we build the catalogue. # Done to shrink the catalogue since some messages are shared between # the various scripts. # $(ALLSCRIPTS): $(SCRIPTS:%=%.sh) $(CAT) $(SCRIPTS:%=%.sh) > $@ clean : $(RM) $(PROG) $(RTLCKS) $(OBJS) \ $(SCRIPTS) $(ALLSCRIPTS) $(POFILE) $(POFILES) lint : lint_SRCS strip : $(STRIP) $(PROG) include ../Makefile.targ /* * 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. */ /* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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); } /* * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "allocate.h" #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SUNW_OST_OSCMD" #endif #define ALLOC "allocate" #define DEALLOC "deallocate" #define LIST "list_devices" extern void audit_allocate_argv(int, int, char *[]); extern int audit_allocate_record(int); int system_labeled = 0; static int windowing = 0; static int wdwmsg(char *name, char *msg); static void usage(int func) { if (system_labeled) { char *use[6]; use[0] = gettext("allocate [-s] [-w] [-U uname] [-z zonename] " "[-F] device|-g dev-type"); use[1] = gettext("deallocate [-s] [-w] [-z zonename] " "[-F] device|-c dev-class|-g dev-type"); use[2] = gettext("deallocate [-s] [-w] [-z zonename] -I"); use[3] = gettext("list_devices [-s] [-U uid] [-z zonename] " "[-a [-w]] -l|-n|-u [device]"); use[4] = gettext("list_devices [-s] [-U uid] [-z zonename] " "[-a [-w]] [-l|-n|-u] -c dev-class"); use[5] = gettext("list_devices [-s] -d [dev-type]"); switch (func) { case 0: (void) fprintf(stderr, "%s\n", use[0]); break; case 1: (void) fprintf(stderr, "%s\n%s\n", use[1], use[2]); break; case 2: (void) fprintf(stderr, "%s\n%s\n%s\n", use[3], use[4], use[5]); break; default: (void) fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n", use[0], use[1], use[2], use[3], use[4], use[5]); } } else { char *use[5]; use[0] = gettext("allocate " "[-s] [-U uname] [-F] device|-g dev-type"); use[1] = gettext("deallocate [-s] [-F] device|-c dev-class"); use[2] = gettext("deallocate [-s] -I"); use[3] = gettext("list_devices " "[-s] [-U uid] -l|-n|-u [device]"); use[4] = gettext("list_devices " "[-s] [-U uid] [-l|-n|-u] -c dev-class"); switch (func) { case 0: (void) fprintf(stderr, "%s\n", use[0]); break; case 1: (void) fprintf(stderr, "%s\n%s\n", use[1], use[2]); break; case 2: (void) fprintf(stderr, "%s\n%s\n", use[3], use[4]); break; default: (void) fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n", use[0], use[1], use[2], use[3], use[4]); } } exit(1); } void print_error(int error, char *name) { char *msg; char msgbuf[200]; switch (error) { case ALLOCUERR: msg = gettext("Specified device is allocated to another user."); break; case CHOWNERR: msg = gettext("Failed to chown."); break; case CLEANERR: msg = gettext("Unable to clean up device."); break; case CNTDEXECERR: msg = gettext( "Can't exec device-clean program for specified device."); break; case CNTFRCERR: msg = gettext("Can't force deallocate specified device."); break; case DACACCERR: msg = gettext( "Can't access DAC file for the device specified."); break; case DAOFFERR: msg = gettext( "Device allocation feature is not activated " "on this system."); break; case DAUTHERR: msg = gettext("Device not allocatable."); break; case DEFATTRSERR: msg = gettext("No default attributes for specified " "device type."); break; case DEVLKERR: msg = gettext("Concurrent operations for specified device, " "try later."); break; case DEVLONGERR: msg = gettext("Device name is too long."); break; case DEVNALLOCERR: msg = gettext("Device not allocated."); break; case DEVNAMEERR: msg = gettext("Device name error."); break; case DEVSTATEERR: msg = gettext("Device specified is in allocate error state."); break; case DEVZONEERR: msg = gettext("Can't find name of the zone to which " "device is allocated."); break; case DSPMISSERR: msg = gettext( "Device special file(s) missing for specified device."); break; case LABELRNGERR: msg = gettext( "Operation inconsistent with device's label range."); break; case LOGINDEVPERMERR: msg = gettext("Device controlled by logindevperm(5)"); break; case NODAERR: msg = gettext("No entry for specified device."); break; case NODMAPERR: msg = gettext("No entry for specified device."); break; case PREALLOCERR: msg = gettext("Device already allocated."); break; case SETACLERR: msg = gettext("Failed to set ACL."); break; case UAUTHERR: msg = gettext( "User lacks authorization required for this operation."); break; case ZONEERR: msg = gettext("Failed to configure device in zone."); break; default: msg = gettext("Unknown error code."); break; } if (windowing) { (void) snprintf(msgbuf, sizeof (msgbuf), "%s: %s\n", name, msg); (void) wdwmsg(name, msgbuf); } else { (void) fprintf(stderr, "%s: %s\n", name, msg); (void) fflush(stderr); } } char *newenv[] = {"PATH=/usr/bin:/usr/sbin", NULL, /* for LC_ALL */ NULL, /* for LC_COLLATE */ NULL, /* for LC_CTYPE */ NULL, /* for LC_MESSAGES */ NULL, /* for LC_NUMERIC */ NULL, /* for LC_TIME */ NULL, /* for LANG */ NULL }; static char * getenvent(char *name, char *env[]) { for (; *env != NULL; env++) { if (strncmp(*env, name, strlen(name)) == 0) return (*env); } return (NULL); } int main(int argc, char *argv[], char *envp[]) { char *name, *env; int func = -1, optflg = 0, error = 0, c; zoneid_t zoneid; uid_t uid; char *uname = NULL, *device = NULL, *zonename = NULL; char *zname; char pw_buf[NSS_BUFLEN_PASSWD]; struct passwd pw_ent; int env_num = 1; /* PATH= is 0 entry */ #ifdef DEBUG struct stat statbuf; #endif (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); system_labeled = is_system_labeled(); /* test hook: see also mkdevalloc.c and devfsadm.c */ if (!system_labeled) { system_labeled = is_system_labeled_debug(&statbuf); if (system_labeled) { fprintf(stderr, "/ALLOCATE_FORCE_LABEL is set,\n" "forcing system label on for testing...\n"); } } /* * get all enviroment variables * which affect on internationalization. */ env = getenvent("LC_ALL=", envp); if (env != NULL) newenv[env_num++] = env; env = getenvent("LC_COLLATE=", envp); if (env != NULL) newenv[env_num++] = env; env = getenvent("LC_CTYPE=", envp); if (env != NULL) newenv[env_num++] = env; env = getenvent("LC_MESSAGES=", envp); if (env != NULL) newenv[env_num++] = env; env = getenvent("LC_NUMERIC=", envp); if (env != NULL) newenv[env_num++] = env; env = getenvent("LC_TIME=", envp); if (env != NULL) newenv[env_num++] = env; env = getenvent("LANG=", envp); if (env != NULL) newenv[env_num] = env; if ((name = strrchr(argv[0], '/')) == NULL) name = argv[0]; else name++; if (strcmp(name, ALLOC) == 0) func = 0; else if (strcmp(name, DEALLOC) == 0) func = 1; else if (strcmp(name, LIST) == 0) func = 2; else usage(-1); audit_allocate_argv(func, argc, argv); if (system_labeled) { /* * allocate, deallocate, list_devices run in * global zone only. */ zoneid = getzoneid(); if (zoneid != GLOBAL_ZONEID) exit(GLOBALERR); zname = GLOBAL_ZONENAME; /* * check if device allocation is activated. */ if (da_is_on() == 0) { (void) fprintf(stderr, "%s%s", gettext("Turn device allocation on"), gettext(" to use this feature.\n")); exit(DAOFFERR); } } if (func == 0) { /* allocate */ while ((c = getopt(argc, argv, "g:swz:FU:")) != -1) { switch (c) { case 'g': optflg |= TYPE; device = optarg; break; case 's': optflg |= SILENT; break; case 'w': if (system_labeled) { optflg |= WINDOWING; windowing = 1; } else { usage(func); } break; case 'z': if (system_labeled) { optflg |= ZONENAME; zonename = optarg; } else { usage(func); } break; case 'F': optflg |= FORCE; break; case 'U': optflg |= USERNAME; uname = optarg; break; case '?': default : usage(func); } } /* * allocate(1) must be supplied with one device argument */ if (device && ((argc - optind) >= 1)) usage(func); if (device == NULL) { if ((argc - optind) != 1) usage(func); device = argv[optind]; } } else if (func == 1) { /* deallocate */ while ((c = getopt(argc, argv, "c:g:swz:FI")) != -1) { switch (c) { case 'c': if (optflg & (TYPE | FORCE_ALL)) usage(func); optflg |= CLASS; device = optarg; break; case 'g': if (system_labeled) { if (optflg & (CLASS | FORCE_ALL)) usage(func); optflg |= TYPE; device = optarg; } else { usage(func); } break; case 's': optflg |= SILENT; break; case 'w': if (system_labeled) { optflg |= WINDOWING; windowing = 1; } else { usage(func); } break; case 'z': if (system_labeled) { optflg |= ZONENAME; zonename = optarg; } else { usage(func); } break; case 'F': if (optflg & FORCE_ALL) usage(func); optflg |= FORCE; break; case 'I': if (optflg & (CLASS | TYPE | FORCE)) usage(func); optflg |= FORCE_ALL; break; case '?': default : usage(func); } } /* * deallocate(1) must be supplied with one device * argument unless the '-I' argument is supplied */ if (device || (optflg & FORCE_ALL)) { if ((argc - optind) >= 1) usage(func); } else if (device == NULL) { if ((argc - optind) != 1) usage(func); device = argv[optind]; } } else if (func == 2) { /* list_devices */ while ((c = getopt(argc, argv, "ac:dlnsuwz:U:")) != -1) { switch (c) { case 'a': if (system_labeled) { /* * list auths, cleaning programs, * labels. */ if (optflg & LISTDEFS) usage(func); optflg |= LISTATTRS; } else { usage(func); } break; case 'c': optflg |= CLASS; device = optarg; break; case 'd': if (system_labeled) { /* * List devalloc_defaults * This cannot used with anything other * than -s. */ if (optflg & (LISTATTRS | CLASS | LISTALL | LISTFREE | LISTALLOC | WINDOWING | ZONENAME | USERID)) usage(func); optflg |= LISTDEFS; } else { usage(func); } break; case 'l': if (optflg & (LISTFREE | LISTALLOC | LISTDEFS)) usage(func); optflg |= LISTALL; break; case 'n': if (optflg & (LISTALL | LISTALLOC | LISTDEFS)) usage(func); optflg |= LISTFREE; break; case 's': optflg |= SILENT; break; case 'u': if (optflg & (LISTALL | LISTFREE | LISTDEFS)) usage(func); optflg |= LISTALLOC; break; case 'w': if (system_labeled) { if (optflg & LISTDEFS) usage(func); optflg |= WINDOWING; } else { usage(func); } break; case 'z': if (system_labeled) { if (optflg & LISTDEFS) usage(func); optflg |= ZONENAME; zonename = optarg; } else { usage(func); } break; case 'U': if (optflg & LISTDEFS) usage(func); optflg |= USERID; uid = atoi(optarg); break; case '?': default : usage(func); } } if (system_labeled) { if (!(optflg & (LISTALL | LISTFREE | LISTALLOC | LISTDEFS | WINDOWING))) { if (!(optflg & CLASS)) usage(func); } } else if (!(optflg & (LISTALL | LISTFREE | LISTALLOC))) { if (!(optflg & CLASS)) usage(func); } /* * list_devices(1) takes an optional device argument. */ if (device && ((argc - optind) >= 1)) usage(func); if (device == NULL) { if ((argc - optind) == 1) device = argv[optind]; else if ((argc - optind) > 1) usage(func); } } if (optflg & USERNAME) { if (getpwnam_r(uname, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL) { (void) fprintf(stderr, gettext("Invalid user name -- %s -- \n"), uname); exit(1); } uid = pw_ent.pw_uid; } else if (optflg & USERID) { if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL) { (void) fprintf(stderr, gettext("Invalid user ID -- %d -- \n"), uid); exit(1); } uid = pw_ent.pw_uid; } else { /* * caller's uid is the default if no user specified. */ uid = getuid(); } /* * global zone is the default if no zonename specified. */ if (zonename == NULL) { zonename = zname; } else { if (zone_get_id(zonename, &zoneid) != 0) { (void) fprintf(stderr, gettext("Invalid zone name -- %s -- \n"), zonename); exit(1); } } if (func == 0) error = allocate(optflg, uid, device, zonename); else if (func == 1) error = deallocate(optflg, uid, device, zonename); else if (func == 2) error = list_devices(optflg, uid, device, zonename); (void) audit_allocate_record(error); if (error) { if (!(optflg & SILENT)) print_error(error, name); exit(error); } return (0); } /* * Display error message via /etc/security/lib/wdwmsg script */ static int wdwmsg(char *name, char *msg) { pid_t child_pid; pid_t wait_pid; int child_status; /* Fork a child */ switch (child_pid = fork()) { case -1: /* FAILURE */ return (-1); break; case 0: /* CHILD */ (void) execl("/etc/security/lib/wdwmsg", "wdwmsg", msg, name, "OK", NULL); /* If exec failed, send message to stderr */ (void) fprintf(stderr, "%s", msg); return (-1); default: /* PARENT */ /* Wait for child to exit */ wait_pid = waitpid(child_pid, &child_status, 0); if ((wait_pid < 0) && (errno == ECHILD)) return (0); if ((wait_pid < 0) || (wait_pid != child_pid)) return (-1); if (WIFEXITED(child_status)) return (WEXITSTATUS(child_status)); if (WIFSIGNALED(child_status)) return (WTERMSIG(child_status)); return (0); } } /* * 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. */ #ifndef _ALLOCATE_H #define _ALLOCATE_H #ifdef __cplusplus extern "C" { #endif /* Option Flags */ #define LISTATTRS 0x00000001 /* -a */ #define CLASS 0x00000002 /* -c */ #define LISTDEFS 0x00000004 /* -d */ #define TYPE 0x00000008 /* -g */ #define LISTALL 0x00000010 /* -l */ #define LISTFREE 0x00000020 /* -n */ #define SILENT 0x00000040 /* -s */ #define LISTALLOC 0x00000080 /* -u */ #define WINDOWING 0x00000100 /* -w */ #define ZONENAME 0x00000200 /* -z */ #define BOOT 0x00000400 /* -B */ #define FORCE 0x00000800 /* -F */ #define FORCE_ALL 0x00001000 /* -I */ #define USERID 0x00002000 /* -U for list_devices */ #define USERNAME 0x00004000 /* -U for allocate */ /* Device clean program exit codes */ #define DEVCLEAN_OK 0 #define DEVCLEAN_ERROR 1 #define DEVCLEAN_SYSERR 2 #define DEVCLEAN_BADMOUNT 3 #define DEVCLEAN_MOUNTOK 4 /* Error/Exit codes */ #define ALLOCUERR 1 #define CHOWNERR 2 /* Skip 3 to avoid conflict with DEVCLEAN_BADMOUNT */ #define CNTDEXECERR 4 #define CNTFRCERR 5 #define DACACCERR 6 #define DAOFFERR 7 #define DAUTHERR 8 #define DEFATTRSERR 9 #define DEVLKERR 10 #define DEVLONGERR 11 #define DEVNALLOCERR 12 #define DEVNAMEERR 13 #define DEVSTATEERR 14 #define DEVZONEERR 15 #define DSPMISSERR 16 #define GLOBALERR 17 #define LABELRNGERR 18 #define LOGINDEVPERMERR 19 #define NODAERR 20 #define NODMAPERR 21 #define PREALLOCERR 22 #define SETACLERR 23 #define UAUTHERR 24 #define ZONEERR 25 #define CLEANERR 26 #define ALLOC_ERRID (uid_t)2 /* bin */ #define ALLOC_ERR_MODE 0100 /* Functions */ extern int allocate(int optflg, uid_t uid, char *device, char *zonename); extern int deallocate(int optflg, uid_t uid, char *device, char *zonename); extern int list_devices(int optflg, uid_t uid, char *device, char *zonename); #ifdef __cplusplus } #endif #endif /* _ALLOCATE_H */ /* * 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 (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "allocate.h" extern void print_error(int, char *); #if defined(DEBUG) || defined(lint) #define dprintf(s, a) (void) fprintf(stderr, s, a) #define dperror(s) perror(s) #else /* !DEBUG */ #define dprintf(s, a) 0 #define dperror(s) 0 #endif /* DEBUG */ #define DEV_ERRORED(sbuf) (((sbuf).st_mode & ~S_IFMT) == ALLOC_ERR_MODE) #define DEV_ALLOCATED(sbuf) ((sbuf).st_uid != DA_UID || \ !(((sbuf).st_mode & ~S_IFMT) == DEALLOC_MODE || \ DEV_ERRORED(sbuf))) #define ALLOC_CLEAN "-A" #define DEALLOC_CLEAN "-D" #define DAC_DIR "/etc/security/dev" #define DEVICE_AUTH_SEPARATOR "," #define LOCALDEVICE "/dev/console" #define PROCFS "/proc/" #define SFF_NO_ERROR 0x1 #define ALLOC_BY_NONE -1 #define CHECK_DRANGE 1 #define CHECK_URANGE 2 #define CHECK_ZLABEL 3 extern void audit_allocate_list(char *); extern void audit_allocate_device(char *); extern int system_labeled; extern char *newenv[]; struct state_file { int sf_flags; char sf_path[MAXPATHLEN]; }; struct file_info { struct stat fi_stat; char *fi_message; }; struct zone_path { int count; char **path; }; struct dev_names { char **dnames; }; static int _dev_file_name(struct state_file *, devmap_t *); static int lock_dev(char *, struct stat *); static int _check_label(devalloc_t *, char *, uid_t, int); static int create_znode(char *, struct zone_path *, devmap_t *); static int remove_znode(char *, devmap_t *); static int update_device(char **, char *, int); /* * checks if the invoking user is local to the device */ /*ARGSUSED*/ int _is_local(uid_t uid) { struct stat statbuf; if (stat(LOCALDEVICE, &statbuf) == 0 && statbuf.st_uid == uid) return (1); return (0); } /* * Checks if the user with the specified uid has the specified authorization */ int _is_authorized(char *auths, uid_t uid) { char *dcp, *authlist, *lasts; char pw_buf[NSS_BUFLEN_PASSWD]; struct passwd pw_ent; /* * first, the easy cases */ if (strcmp(auths, "@") == 0) return (1); if (strcmp(auths, "*") == 0) return (ALLOC_BY_NONE); if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL) return (0); if (strpbrk(auths, DEVICE_AUTH_SEPARATOR) == NULL) return (chkauthattr(auths, pw_ent.pw_name)); authlist = strdup(auths); if (authlist == NULL) return (0); for (dcp = authlist; (dcp = strtok_r(dcp, DEVICE_AUTH_SEPARATOR, &lasts)) != NULL; dcp = NULL) { if (chkauthattr(dcp, pw_ent.pw_name)) break; } free(authlist); return (dcp != NULL); } /* * Checks if the specified user has authorization for the device */ int _is_dev_authorized(devalloc_t *da, uid_t uid) { int ares; char *auth_list, *dcp, *subauth = NULL; auth_list = da->da_devauth; if (auth_list == NULL) return (0); dcp = strpbrk(auth_list, KV_TOKEN_DELIMIT); if (dcp == NULL) return (_is_authorized(auth_list, uid)); if (_is_local(uid)) { /* the local authorization is before the separator */ ares = dcp - auth_list; subauth = malloc(ares + 1); if (subauth == NULL) return (0); (void) strlcpy(subauth, auth_list, (ares + 1)); auth_list = subauth; } else auth_list = dcp + 1; ares = _is_authorized(auth_list, uid); if (subauth != NULL) free(subauth); return (ares); } int check_devs(devmap_t *dm) { int status = 0; char **file; if (dm->dmap_devarray == NULL) return (NODMAPERR); for (file = dm->dmap_devarray; *file != NULL; file++) { if ((status = access(*file, F_OK)) == -1) { dprintf("Unable to access file %s\n", *file); break; } } return (status); } int print_da_defs(da_defs_t *da_defs) { char optbuf[BUFSIZ]; char *p = NULL; if (da_defs->devopts == NULL) { dprintf("No default attributes for %s\n", da_defs->devtype); return (DEFATTRSERR); } (void) printf("dev_type=%s\n", da_defs->devtype); if (_kva2str(da_defs->devopts, optbuf, sizeof (optbuf), KV_ASSIGN, KV_TOKEN_DELIMIT) == 0) { if (p = rindex(optbuf, ':')) *p = '\0'; (void) printf("\t%s\n", optbuf); } return (0); } void print_dev_attrs(int optflag, devalloc_t *da, devmap_t *dm, struct file_info *fip) { char *p = NULL; char optbuf[BUFSIZ]; (void) printf("device=%s%s", dm->dmap_devname, KV_DELIMITER); (void) printf("type=%s%s", dm->dmap_devtype, KV_DELIMITER); (void) printf("auths=%s%s", (da->da_devauth ? da->da_devauth : ""), KV_DELIMITER); (void) printf("clean=%s%s", (da->da_devexec ? da->da_devexec : ""), KV_DELIMITER); if (da->da_devopts != NULL) { if (_kva2str(da->da_devopts, optbuf, sizeof (optbuf), KV_ASSIGN, KV_TOKEN_DELIMIT) == 0) { if (p = rindex(optbuf, ':')) *p = '\0'; (void) printf("%s", optbuf); } } (void) printf("%s", KV_DELIMITER); if (optflag & WINDOWING) { if ((fip->fi_message != NULL) && (strcmp(fip->fi_message, DAOPT_CLASS) == 0)) (void) printf("owner=/FREE%s", KV_DELIMITER); else if (DEV_ERRORED(fip->fi_stat)) (void) printf("owner=/ERROR%s", KV_DELIMITER); else if (!DEV_ALLOCATED(fip->fi_stat)) (void) printf("owner=/FREE%s", KV_DELIMITER); else (void) printf("owner=%u%s", fip->fi_stat.st_uid, KV_DELIMITER); } (void) printf("files=%s", dm->dmap_devlist); (void) printf("\n"); } void print_dev(devmap_t *dm) { char **file; (void) printf(gettext("device: %s "), dm->dmap_devname); (void) printf(gettext("type: %s "), dm->dmap_devtype); (void) printf(gettext("files:")); file = dm->dmap_devarray; if (file != NULL) { for (; *file != NULL; file++) (void) printf(" %s", *file); } (void) printf("\n"); } /* ARGSUSED */ int _list_device(int optflag, uid_t uid, devalloc_t *da, char *zonename) { int bytes = 0; int error = 0; int is_authorized = 0; char *fname = NULL; char file_name[MAXPATHLEN]; devmap_t *dm; struct file_info fi; struct state_file sf; fi.fi_message = NULL; setdmapent(); if ((dm = getdmapnam(da->da_devname)) == NULL) { enddmapent(); dprintf("Unable to find %s in the maps database\n", da->da_devname); return (NODMAPERR); } enddmapent(); if ((optflag & CLASS) && (!(optflag & (LISTALL | LISTFREE | LISTALLOC)))) { fi.fi_message = DAOPT_CLASS; if (optflag & LISTATTRS) print_dev_attrs(optflag, da, dm, &fi); else print_dev(dm); goto out; } if (system_labeled) { if ((error = _dev_file_name(&sf, dm)) != 0) { freedmapent(dm); dprintf("Unable to find %s device files\n", da->da_devname); error = NODMAPERR; goto out; } fname = sf.sf_path; } else { bytes = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR, da->da_devname); if (bytes <= 0) { error = DEVNAMEERR; goto out; } else if (bytes >= MAXPATHLEN) { dprintf("device name %s is too long.\n", da->da_devname); error = DEVLONGERR; goto out; } fname = file_name; } if (stat(fname, &fi.fi_stat) != 0) { dprintf("Unable to stat %s\n", fname); dperror("Error:"); error = DACACCERR; goto out; } is_authorized = _is_dev_authorized(da, uid); if (optflag & LISTFREE) { /* list_devices -n */ /* * list all free devices */ if (DEV_ALLOCATED(fi.fi_stat)) { error = PREALLOCERR; goto out; } if (system_labeled) { /* * for this free device, check if - * 1. user has authorization to allocate * 2. the zone label is within the label range of the * device */ if (is_authorized == ALLOC_BY_NONE) { error = DAUTHERR; goto out; } else if (is_authorized == 0) { error = UAUTHERR; goto out; } if (_check_label(da, zonename, uid, CHECK_DRANGE) != 0) { error = LABELRNGERR; goto out; } } } else if (optflag & LISTALLOC) { /* list_devices -u */ /* * list all allocated devices */ if (!DEV_ALLOCATED(fi.fi_stat)) { error = DEVNALLOCERR; goto out; } if (fi.fi_stat.st_uid != uid) { error = DEVSTATEERR; goto out; } if (system_labeled) { /* * check if the zone label equals the label at which * the device is allocated. */ if (_check_label(da, zonename, uid, CHECK_ZLABEL) != 0) { error = LABELRNGERR; goto out; } } } else if (optflag & LISTALL) { /* list_devices -l */ /* * list all devices - free and allocated - available */ if (DEV_ALLOCATED(fi.fi_stat)) { if (optflag & WINDOWING && (is_authorized == ALLOC_BY_NONE)) { /* * don't complain if we're here for the GUI. */ error = 0; } else if (fi.fi_stat.st_uid != uid) { if (!(optflag & WINDOWING)) { error = ALLOCUERR; goto out; } } if (system_labeled && !(optflag & WINDOWING)) { /* * if we're not displaying in the GUI, * check if the zone label equals the label * at which the device is allocated. */ if (_check_label(da, zonename, uid, CHECK_ZLABEL) != 0) { error = LABELRNGERR; goto out; } } } else if (system_labeled && !(optflag & WINDOWING)) { /* * if we're not displaying in the GUI, * for this free device, check if - * 1. user has authorization to allocate * 2. the zone label is within the label range of the * device */ if (is_authorized == ALLOC_BY_NONE) { error = DAUTHERR; goto out; } else if (is_authorized == 0) { error = UAUTHERR; goto out; } if (_check_label(da, zonename, uid, CHECK_DRANGE) != 0) { error = LABELRNGERR; goto out; } } } if (system_labeled && DEV_ERRORED(fi.fi_stat) && !(optflag & LISTALL)) { error = DEVSTATEERR; goto out; } if (check_devs(dm) == -1) { error = DSPMISSERR; goto out; } if (optflag & LISTATTRS) print_dev_attrs(optflag, da, dm, &fi); else print_dev(dm); error = 0; out: freedmapent(dm); return (error); } /* ARGSUSED */ int list_devices(int optflag, uid_t uid, char *device, char *zonename) { int error = 0; char *class = NULL; da_defs_t *da_defs; devalloc_t *da; if (system_labeled && optflag & WINDOWING && !(optflag & LISTATTRS)) { /* * Private interface for GUI. */ (void) puts(DA_DB_LOCK); return (0); } if (optflag & USERID) { /* * we need device.revoke to list someone else's devices */ if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid())) return (UAUTHERR); } if (system_labeled) { if (!(optflag & USERID) && !_is_authorized(DEFAULT_DEV_ALLOC_AUTH, uid)) /* * we need device.allocate to list our devices */ return (UAUTHERR); if (optflag & LISTDEFS) { /* * list default attrs from devalloc_defaults */ setdadefent(); if (device) { /* * list default attrs for this device type */ da_defs = getdadeftype(device); if (da_defs == NULL) { enddadefent(); dprintf("No default attributes for " "%s\n", device); return (DEFATTRSERR); } error = print_da_defs(da_defs); freedadefent(da_defs); } else { /* * list everything in devalloc_defaults */ while ((da_defs = getdadefent()) != NULL) { (void) print_da_defs(da_defs); freedadefent(da_defs); } } enddadefent(); return (error); } } /* * Lock the database to make sure no body writes to it while we are * reading. */ (void) lock_dev(NULL, NULL); setdaent(); if (device) { if (optflag & CLASS) { /* * list all devices of this class. */ while ((da = getdaent()) != NULL) { class = kva_match(da->da_devopts, DAOPT_CLASS); if (class && (strcmp(class, device) == 0)) { (void) _list_device(optflag, uid, da, zonename); } freedaent(da); } } else { /* * list this device */ if ((da = getdanam(device)) == NULL) { enddaent(); return (NODAERR); } error = _list_device(optflag, uid, da, zonename); freedaent(da); } } else { /* * list all devices */ while ((da = getdaent()) != NULL) { (void) _list_device(optflag, uid, da, zonename); freedaent(da); } } enddaent(); return (error); } /* * Set the DAC characteristics of the file. * This uses a fancy chmod() by setting a minimal ACL which sets the mode * and discards any existing ACL. */ int _newdac(char *file, uid_t owner, gid_t group, o_mode_t mode) { int err = 0; if (mode == ALLOC_MODE) { if (chown(file, owner, group) == -1) { dperror("newdac: unable to chown"); err = CHOWNERR; } } else do { if (chown(file, owner, group) == -1) { dperror("newdac: unable to chown"); err = CHOWNERR; } } while (fdetach(file) == 0); if (err) return (err); if (strncmp(file, "/dev/", strlen("/dev/")) != 0) { /* * This could be a SunRay device that is in /tmp. */ if (chmod(file, mode) == -1) { dperror("newdac: unable to chmod"); err = SETACLERR; } } else { err = acl_strip(file, owner, group, (mode_t)mode); } if (err != 0) { dperror("newdac: unable to setacl"); err = SETACLERR; } return (err); } /* * lock_dev - * locks a section of DA_DB_LOCK. * returns lock fd if successful, else -1 on error. */ static int lock_dev(char *file, struct stat *statbuf) { static int lockfd = -1; int ret; int count = 0; int retry = 10; off_t size = 0; off_t offset; char *lockfile; if (system_labeled) lockfile = DA_DB_LOCK; else lockfile = file; if (statbuf) { offset = statbuf->st_rdev; dprintf("locking %s\n", file); } else { offset = 0; dprintf("locking %s\n", lockfile); } if ((lockfd == -1) && (lockfd = open(lockfile, O_RDWR | O_CREAT, 0600)) == -1) { dperror("lock_dev: cannot open lock file"); return (-1); } if (system_labeled) { (void) _newdac(lockfile, DA_UID, DA_GID, 0600); if (lseek(lockfd, offset, SEEK_SET) == -1) { dperror("lock_dev: cannot position lock file"); return (-1); } size = 1; } errno = 0; while (retry) { count++; ret = lockf(lockfd, F_TLOCK, size); if (ret == 0) return (lockfd); if ((errno != EACCES) && (errno != EAGAIN)) { dperror("lock_dev: cannot set lock"); return (-1); } retry--; (void) sleep(count); errno = 0; } return (-1); } int mk_alloc(devmap_t *list, uid_t uid, struct zone_path *zpath) { int i; int error = 0; char **file; gid_t gid = getgid(); mode_t mode = ALLOC_MODE; file = list->dmap_devarray; if (file == NULL) return (NODMAPERR); for (; *file != NULL; file++) { dprintf("Allocating %s\n", *file); if ((error = _newdac(*file, uid, gid, mode)) != 0) { (void) _newdac(*file, ALLOC_ERRID, DA_GID, ALLOC_ERR_MODE); break; } } if (system_labeled && zpath->count && (error == 0)) { /* * mark as allocated any new device nodes that we * created in local zone */ for (i = 0; i < zpath->count; i++) { dprintf("Allocating %s\n", zpath->path[i]); if ((error = _newdac(zpath->path[i], uid, gid, mode)) != 0) { (void) _newdac(zpath->path[i], ALLOC_ERRID, DA_GID, ALLOC_ERR_MODE); break; } } } return (error); } /* * mk_revoke() is used instead of system("/usr/sbin/fuser -k file") * because "/usr/sbin/fuser -k file" kills all processes * working with the file, even "vold" (bug #4095152). */ int mk_revoke(int optflag, char *file) { int r = 0, p[2], fp, lock; int fuserpid; char buf[MAXPATHLEN]; FILE *ptr; pid_t c_pid; prpsinfo_t info; (void) strcpy(buf, PROCFS); /* * vfork() and execl() just to make the same output * as before fixing of bug #4095152. * The problem is that the "fuser" command prints * one part of output into stderr and another into stdout, * but user sees them mixed. Of course, better to change "fuser" * or to intercept and not to print its output. */ if (!(optflag & SILENT)) { c_pid = vfork(); if (c_pid == -1) return (-1); if (c_pid == 0) { dprintf("first exec fuser %s\n", file); (void) execl("/usr/sbin/fuser", "fuser", file, NULL); dperror("first exec fuser"); _exit(1); } (void) waitpid(c_pid, &lock, 0); dprintf("exit status %x\n", lock); if (WEXITSTATUS(lock) != 0) return (-1); } dprintf("first continuing c_pid=%d\n", (int)c_pid); if (pipe(p)) { dperror("pipe"); return (-1); } /* vfork() and execl() to catch output and to process it */ c_pid = vfork(); if (c_pid == -1) { dperror("second vfork"); return (-1); } dprintf("second continuing c_pid=%d\n", (int)c_pid); if (c_pid == 0) { (void) close(p[0]); (void) close(1); (void) fcntl(p[1], F_DUPFD, 1); (void) close(p[1]); (void) close(2); dprintf("second exec fuser %s\n", file); (void) execl("/usr/sbin/fuser", "fuser", file, NULL); dperror("second exec fuser"); _exit(1); } (void) close(p[1]); if ((ptr = fdopen(p[0], "r")) != NULL) { while (!feof(ptr)) { if (fscanf(ptr, "%d", &fuserpid) > 0) { (void) sprintf(buf + strlen(PROCFS), "%d", fuserpid); if ((fp = open(buf, O_RDONLY)) == -1) { dperror(buf); continue; } if (ioctl(fp, PIOCPSINFO, (char *)&info) == -1) { dprintf("%d psinfo failed", fuserpid); dperror(""); (void) close(fp); continue; } (void) close(fp); if (strcmp(info.pr_fname, "vold") == 0) { dprintf("%d matched vold name\n", fuserpid); continue; } if (strcmp(info.pr_fname, "deallocate") == 0) { dprintf("%d matched deallocate name\n", fuserpid); continue; } dprintf("killing %s", info.pr_fname); dprintf("(%d)\n", fuserpid); if ((r = kill((pid_t)fuserpid, SIGKILL)) == -1) { dprintf("kill %d", fuserpid); dperror(""); break; } } } } else { dperror("fdopen(p[0], r)"); r = -1; } (void) fclose(ptr); return (r); } int mk_unalloc(int optflag, devmap_t *list) { int error = 0; int status; char **file; audit_allocate_list(list->dmap_devlist); file = list->dmap_devarray; if (file == NULL) return (NODMAPERR); for (; *file != NULL; file++) { dprintf("Deallocating %s\n", *file); if (mk_revoke(optflag, *file) < 0) { dprintf("mk_unalloc: unable to revoke %s\n", *file); dperror(""); error = CNTFRCERR; } status = _newdac(*file, DA_UID, DA_GID, DEALLOC_MODE); if (error == 0) error = status; } return (error); } int mk_error(devmap_t *list) { int status = 0; char **file; audit_allocate_list(list->dmap_devlist); file = list->dmap_devarray; if (file == NULL) return (NODMAPERR); for (; *file != NULL; file++) { dprintf("Putting %s in error state\n", *file); status = _newdac(*file, ALLOC_ERRID, DA_GID, ALLOC_ERR_MODE); } return (status); } int exec_clean(int optflag, char *devname, char *path, uid_t uid, char *zonename, char *clean_arg) { int c; int status = 0, exit_status; char *mode, *cmd, *wdwcmd, *zoneroot; char *devzone = zonename; char wdwpath[PATH_MAX]; char zonepath[MAXPATHLEN]; char title[100]; char pw_buf[NSS_BUFLEN_PASSWD]; struct passwd pw_ent; zonepath[0] = '\0'; if (system_labeled) { if ((zoneroot = getzonerootbyname(zonename)) == NULL) { if (strcmp(clean_arg, ALLOC_CLEAN) == 0) { return (-1); } else if (optflag & FORCE) { (void) strcpy(zonepath, "/"); devzone = GLOBAL_ZONENAME; } else { dprintf("unable to get label for %s zone\n", zonename); return (-1); } } else { (void) strcpy(zonepath, zoneroot); free(zoneroot); } } if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL) return (-1); if (optflag & FORCE_ALL) mode = "-I"; else if (optflag & FORCE) mode = "-f"; else mode = "-s"; if (path == NULL) return (0); if ((cmd = strrchr(path, '/')) == NULL) cmd = path; else cmd++; /* skip leading '/' */ c = vfork(); switch (c) { case -1: return (-1); case 0: (void) setuid(0); if (system_labeled && (optflag & WINDOWING)) { /* First try .windowing version of script */ (void) strncpy(wdwpath, path, PATH_MAX); (void) strncat(wdwpath, ".windowing", PATH_MAX); if ((wdwcmd = strrchr(wdwpath, '/')) == NULL) wdwcmd = wdwpath; (void) execl(wdwpath, wdwcmd, mode, devname, clean_arg, pw_ent.pw_name, devzone, zonepath, NULL); /* If that failed, run regular version via dtterm */ (void) snprintf(title, sizeof (title), "Device %s for %s", strcmp(clean_arg, ALLOC_CLEAN) == 0 ? "allocation" : "deallocation", devname); (void) execl("/usr/dt/bin/dtterm", "dtterm", "-title", title, "-geometry", "x10+100+400", "-e", "/etc/security/lib/wdwwrapper", path, mode, devname, clean_arg, pw_ent.pw_name, devzone, zonepath, NULL); /* * And if that failed, continue on to try * running regular version directly. */ } dprintf("clean script: %s, ", path); dprintf("cmd=%s, ", cmd); dprintf("mode=%s, ", mode); if (system_labeled) { dprintf("devname=%s ", devname); dprintf("zonename=%s ", devzone); dprintf("zonepath=%s ", zonepath); dprintf("username=%s\n", pw_ent.pw_name); (void) execl(path, cmd, mode, devname, clean_arg, pw_ent.pw_name, devzone, zonepath, NULL); } else { dprintf("devname=%s\n", devname); (void) execle(path, cmd, mode, devname, NULL, newenv); } dprintf("Unable to execute clean up script %s\n", path); dperror(""); exit(CNTDEXECERR); default: (void) waitpid(c, &status, 0); dprintf("Child %d", c); if (WIFEXITED(status)) { exit_status = WEXITSTATUS(status); dprintf(" exited, status: %d\n", exit_status); return (exit_status); } else if (WIFSIGNALED(status)) { dprintf(" killed, signal %d\n", WTERMSIG(status)); } else { dprintf(": exit status %d\n", status); } return (-1); } } int _deallocate_dev(int optflag, devalloc_t *da, devmap_t *dm_in, uid_t uid, char *zonename, int *lock_fd) { int bytes = 0; int error = 0; int is_authorized = 0; uid_t nuid; char *fname = NULL; char file_name[MAXPATHLEN]; char *devzone = NULL; devmap_t *dm = NULL, *dm_new = NULL; struct stat stat_buf; struct state_file sf; if (dm_in == NULL) { setdmapent(); if ((dm_new = getdmapnam(da->da_devname)) == NULL) { enddmapent(); dprintf("Unable to find %s in device map database\n", da->da_devname); return (NODMAPERR); } enddmapent(); dm = dm_new; } else { dm = dm_in; } if (system_labeled) { if (_dev_file_name(&sf, dm) != 0) { if (dm_new) freedmapent(dm_new); dprintf("Unable to find %s device files\n", da->da_devname); error = NODMAPERR; goto out; } fname = sf.sf_path; } else { bytes = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR, da->da_devname); if (bytes <= 0) { error = DEVNAMEERR; goto out; } else if (bytes >= MAXPATHLEN) { dprintf("device name %s is too long.\n", da->da_devname); error = DEVLONGERR; goto out; } fname = file_name; } audit_allocate_device(fname); if (stat(fname, &stat_buf) != 0) { dprintf("Unable to stat %s\n", fname); error = DACACCERR; goto out; } is_authorized = _is_dev_authorized(da, uid); if (is_authorized == ALLOC_BY_NONE) { dprintf("Not deallocating %s, not allocatable\n", da->da_devname); goto out; } if (!(optflag & (FORCE | FORCE_ALL)) && !is_authorized) { dprintf("User %d is unauthorized to deallocate\n", (int)uid); error = UAUTHERR; goto out; } if (system_labeled) { /* * unless we're here to deallocate by force, check if the * label at which the device is currently allocated is * within the user label range. */ if (!(optflag & FORCE) && _check_label(da, zonename, uid, CHECK_URANGE) != 0) { error = LABELRNGERR; goto out; } } if (!(optflag & FORCE) && stat_buf.st_uid != uid && DEV_ALLOCATED(stat_buf)) { error = ALLOCUERR; goto out; } if (!DEV_ALLOCATED(stat_buf)) { if (DEV_ERRORED(stat_buf)) { if (!(optflag & FORCE)) { error = DEVSTATEERR; goto out; } } else { error = DEVNALLOCERR; goto out; } } /* All checks passed, time to lock and deallocate */ if ((*lock_fd = lock_dev(fname, &stat_buf)) == -1) { error = DEVLKERR; goto out; } if (system_labeled) { devzone = kva_match(da->da_devopts, DAOPT_ZONE); if (devzone == NULL) { devzone = GLOBAL_ZONENAME; } else if (strcmp(devzone, GLOBAL_ZONENAME) != 0) { if ((remove_znode(devzone, dm) != 0) && !(optflag & FORCE)) { error = ZONEERR; goto out; } } } if ((error = mk_unalloc(optflag, dm)) != 0) { if (!(optflag & FORCE)) goto out; } if (system_labeled == 0) { if ((error = _newdac(fname, DA_UID, DA_GID, DEALLOC_MODE)) != 0) { (void) _newdac(file_name, DA_UID, DA_GID, ALLOC_ERR_MODE); goto out; } } /* * if we are deallocating device owned by someone else, * pass the owner's uid to the cleaning script. */ nuid = (stat_buf.st_uid == uid) ? uid : stat_buf.st_uid; error = exec_clean(optflag, da->da_devname, da->da_devexec, nuid, devzone, DEALLOC_CLEAN); if (error != 0) { if (!(optflag & (FORCE | FORCE_ALL))) { error = CLEANERR; (void) mk_error(dm); } else { error = 0; } } out: if (dm_new) freedmapent(dm_new); return (error); } int _allocate_dev(int optflag, uid_t uid, devalloc_t *da, char *zonename, int *lock_fd) { int i; int bytes = 0; int error = 0; int is_authorized = 0; int dealloc_optflag = 0; char *fname = NULL; char file_name[MAXPATHLEN]; devmap_t *dm; struct stat stat_buf; struct state_file sf; struct zone_path zpath; zpath.count = 0; zpath.path = NULL; setdmapent(); if ((dm = getdmapnam(da->da_devname)) == NULL) { enddmapent(); dprintf("Unable to find %s in device map database\n", da->da_devname); return (NODMAPERR); } enddmapent(); if (system_labeled) { if (_dev_file_name(&sf, dm) != 0) { freedmapent(dm); dprintf("Unable to find %s device files\n", da->da_devname); error = NODMAPERR; goto out; } fname = sf.sf_path; } else { bytes = snprintf(file_name, MAXPATHLEN, "%s/%s", DAC_DIR, da->da_devname); if (bytes <= 0) { error = DEVNAMEERR; goto out; } else if (bytes >= MAXPATHLEN) { dprintf("device name %s is too long.\n", da->da_devname); error = DEVLONGERR; goto out; } fname = file_name; } (void) audit_allocate_device(fname); if (stat(fname, &stat_buf) != 0) { dprintf("Unable to stat %s\n", fname); dperror("Error:"); error = DACACCERR; goto out; } if (DEV_ERRORED(stat_buf)) { error = DEVSTATEERR; goto out; } is_authorized = _is_dev_authorized(da, uid); if (is_authorized == ALLOC_BY_NONE) { dprintf("Device %s is not allocatable\n", da->da_devname); error = UAUTHERR; goto out; } else if (!is_authorized && !(optflag & USERNAME)) { dprintf("User %d is unauthorized to allocate\n", (int)uid); error = UAUTHERR; goto out; } if (system_labeled) { /* * check if label of the zone to which the device is being * allocated is within the device label range. */ if (_check_label(da, zonename, uid, CHECK_DRANGE) != 0) { error = LABELRNGERR; goto out; } } if (check_devs(dm) == -1) { error = DSPMISSERR; goto out; } if (DEV_ALLOCATED(stat_buf)) { if (optflag & FORCE) { if (optflag & SILENT) dealloc_optflag = FORCE|SILENT; else dealloc_optflag = FORCE; if (_deallocate_dev(dealloc_optflag, da, dm, uid, zonename, lock_fd)) { dprintf("Couldn't force deallocate device %s\n", da->da_devname); error = CNTFRCERR; goto out; } } else if (stat_buf.st_uid == uid) { error = PREALLOCERR; goto out; } else { error = ALLOCUERR; goto out; } } /* All checks passed, time to lock and allocate */ if ((*lock_fd = lock_dev(fname, &stat_buf)) == -1) { error = DEVLKERR; goto out; } if (system_labeled) { /* * Run the cleaning program; it also mounts allocated * device if required. */ error = exec_clean(optflag, da->da_devname, da->da_devexec, uid, zonename, ALLOC_CLEAN); if (error != DEVCLEAN_OK) { switch (error) { case DEVCLEAN_ERROR: case DEVCLEAN_SYSERR: dprintf("allocate: " "Error in device clean program %s\n", da->da_devexec); error = CLEANERR; (void) mk_error(dm); goto out; case DEVCLEAN_BADMOUNT: dprintf("allocate: Failed to mount device %s\n", da->da_devexec); goto out; case DEVCLEAN_MOUNTOK: break; default: error = 0; goto out; } } /* * If not mounted, create zonelinks, if this is not the * global zone. */ if ((strcmp(zonename, GLOBAL_ZONENAME) != 0) && (error != DEVCLEAN_MOUNTOK)) { if (create_znode(zonename, &zpath, dm) != 0) { error = ZONEERR; goto out; } } } (void) audit_allocate_list(dm->dmap_devlist); if ((error = mk_alloc(dm, uid, &zpath)) != 0) { (void) mk_unalloc(optflag, dm); goto out; } if (system_labeled == 0) { if ((error = _newdac(file_name, uid, getgid(), ALLOC_MODE)) != 0) { (void) _newdac(file_name, DA_UID, DA_GID, ALLOC_ERR_MODE); goto out; } } error = 0; out: if (zpath.count) { for (i = 0; i < zpath.count; i++) free(zpath.path[i]); free(zpath.path); } freedmapent(dm); return (error); } void _store_devnames(int *count, struct dev_names *dnms, char *zonename, devalloc_t *da, int flag) { int i; dnms->dnames = (char **)realloc(dnms->dnames, (*count + 1) * sizeof (char *)); if (da) { dnms->dnames[*count] = strdup(da->da_devname); (*count)++; } else { dnms->dnames[*count] = NULL; if (flag == DA_ADD_ZONE) (void) update_device(dnms->dnames, zonename, DA_ADD_ZONE); else if (flag == DA_REMOVE_ZONE) (void) update_device(dnms->dnames, NULL, DA_REMOVE_ZONE); for (i = 0; i < *count; i++) free(dnms->dnames[i]); free(dnms->dnames); } } int allocate(int optflag, uid_t uid, char *device, char *zonename) { int count = 0; int error = 0; int lock_fd = -1; devalloc_t *da; struct dev_names dnms; if (optflag & (FORCE | USERID | USERNAME)) { if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid())) return (UAUTHERR); } dnms.dnames = NULL; setdaent(); if (optflag & TYPE) { /* * allocate devices of this type */ while ((da = getdatype(device)) != NULL) { if (system_labeled && da_check_logindevperm(da->da_devname)) { freedaent(da); continue; } dprintf("trying to allocate %s\n", da->da_devname); error = _allocate_dev(optflag, uid, da, zonename, &lock_fd); if (system_labeled && (error == 0)) { /* * we need to record in device_allocate the * label (zone name) at which this device is * being allocated. store this device entry. */ _store_devnames(&count, &dnms, zonename, da, 0); } freedaent(da); error = 0; } } else { /* * allocate this device */ if ((da = getdanam(device)) == NULL) { enddaent(); return (NODAERR); } if (system_labeled && da_check_logindevperm(device)) { freedaent(da); return (LOGINDEVPERMERR); } dprintf("trying to allocate %s\n", da->da_devname); error = _allocate_dev(optflag, uid, da, zonename, &lock_fd); /* * we need to record in device_allocate the label (zone name) * at which this device is being allocated. store this device * entry. */ if (system_labeled && (error == 0)) _store_devnames(&count, &dnms, zonename, da, 0); freedaent(da); if (error == DEVCLEAN_BADMOUNT) error = 0; } enddaent(); if (lock_fd != -1) (void) close(lock_fd); /* * add to device_allocate labels (zone names) for the devices we * allocated. */ if (dnms.dnames) _store_devnames(&count, &dnms, zonename, NULL, DA_ADD_ZONE); return (error); } /* ARGSUSED */ int deallocate(int optflag, uid_t uid, char *device, char *zonename) { int count = 0; int error = 0; int lock_fd = -1; char *class = NULL; devalloc_t *da; struct dev_names dnms; if (optflag & (FORCE | FORCE_ALL)) { if (!_is_authorized(DEVICE_REVOKE_AUTH, getuid())) return (UAUTHERR); } if (optflag & FORCE_ALL) optflag |= FORCE; dnms.dnames = NULL; setdaent(); if (optflag & FORCE_ALL) { /* * deallocate all devices */ while ((da = getdaent()) != NULL) { if (system_labeled && da_check_logindevperm(da->da_devname)) { freedaent(da); continue; } dprintf("trying to deallocate %s\n", da->da_devname); error = _deallocate_dev(optflag, da, NULL, uid, zonename, &lock_fd); if (system_labeled && (error == 0)) { /* * we need to remove this device's allocation * label (zone name) from device_allocate. * store this device name. */ _store_devnames(&count, &dnms, zonename, da, 0); } freedaent(da); error = 0; } } else if (system_labeled && (optflag & TYPE)) { /* * deallocate all devices of this type */ while ((da = getdatype(device)) != NULL) { if (da_check_logindevperm(da->da_devname)) { freedaent(da); continue; } dprintf("trying to deallocate %s\n", da->da_devname); error = _deallocate_dev(optflag, da, NULL, uid, zonename, &lock_fd); if (error == 0) { /* * we need to remove this device's allocation * label (zone name) from device_allocate. * store this device name. */ _store_devnames(&count, &dnms, zonename, da, 0); } freedaent(da); error = 0; } } else if (system_labeled && (optflag & CLASS)) { /* * deallocate all devices of this class (for sunray) */ while ((da = getdaent()) != NULL) { class = kva_match(da->da_devopts, DAOPT_CLASS); if (class && (strcmp(class, device) == 0)) { dprintf("trying to deallocate %s\n", da->da_devname); error = _deallocate_dev(optflag, da, NULL, uid, zonename, &lock_fd); if (error == 0) { /* * we need to remove this device's * allocation label (zone name) from * device_allocate. store this device * name. */ _store_devnames(&count, &dnms, zonename, da, 0); } error = 0; } freedaent(da); } } else if (!(optflag & TYPE)) { /* * deallocate this device */ if ((da = getdanam(device)) == NULL) { enddaent(); return (NODAERR); } if (system_labeled && da_check_logindevperm(da->da_devname)) { freedaent(da); return (LOGINDEVPERMERR); } dprintf("trying to deallocate %s\n", da->da_devname); error = _deallocate_dev(optflag, da, NULL, uid, zonename, &lock_fd); if (system_labeled && (error == 0)) { /* * we need to remove this device's allocation label * (zone name) from device_allocate. store this * device name. */ _store_devnames(&count, &dnms, zonename, da, 0); } freedaent(da); if (error == DEVCLEAN_BADMOUNT) error = 0; } enddaent(); if (lock_fd != -1) (void) close(lock_fd); /* * remove from device_allocate labels (zone names) for the devices we * deallocated. */ if (dnms.dnames) _store_devnames(&count, &dnms, zonename, NULL, DA_REMOVE_ZONE); return (error); } static int _dev_file_name(struct state_file *sfp, devmap_t *dm) { sfp->sf_flags = 0; /* if devlist is generated, never leave device in error state */ if (dm->dmap_devlist[0] == '`') sfp->sf_flags |= SFF_NO_ERROR; if (dm->dmap_devarray == NULL || dm->dmap_devarray[0] == NULL) return (NODMAPERR); (void) strncpy(sfp->sf_path, dm->dmap_devarray[0], sizeof (sfp->sf_path)); sfp->sf_path[sizeof (sfp->sf_path) - 1] = '\0'; if (sfp->sf_path[0] == '\0') { dprintf("dev_file_name: no device list for %s\n", dm->dmap_devname); return (NODMAPERR); } return (0); } /* * _check_label - * checks the device label range against zone label, which is also * user's current label. * returns 0 if in range, -1 for all other conditions. * */ static int _check_label(devalloc_t *da, char *zonename, uid_t uid, int flag) { int err; int in_range = 0; char *alloczone, *lstr; char pw_buf[NSS_BUFLEN_PASSWD]; blrange_t *range; m_label_t *zlabel; struct passwd pw_ent; if ((da == NULL) || (zonename == NULL)) return (-1); if ((zlabel = getzonelabelbyname(zonename)) == NULL) { dprintf("unable to get label for %s zone\n", zonename); return (-1); } if (flag == CHECK_DRANGE) { blrange_t drange; drange.lower_bound = blabel_alloc(); lstr = kva_match(da->da_devopts, DAOPT_MINLABEL); if (lstr == NULL) { bsllow(drange.lower_bound); } else if (stobsl(lstr, drange.lower_bound, NO_CORRECTION, &err) == 0) { dprintf("bad min_label for device %s\n", da->da_devname); free(zlabel); blabel_free(drange.lower_bound); return (-1); } drange.upper_bound = blabel_alloc(); lstr = kva_match(da->da_devopts, DAOPT_MAXLABEL); if (lstr == NULL) { bslhigh(drange.upper_bound); } else if (stobsl(lstr, drange.upper_bound, NO_CORRECTION, &err) == 0) { dprintf("bad max_label for device %s\n", da->da_devname); free(zlabel); blabel_free(drange.lower_bound); blabel_free(drange.upper_bound); return (-1); } if (blinrange(zlabel, &drange) == 0) { char *zlbl = NULL, *min = NULL, *max = NULL; (void) bsltos(zlabel, &zlbl, 0, 0); (void) bsltos(drange.lower_bound, &min, 0, 0); (void) bsltos(drange.upper_bound, &max, 0, 0); dprintf("%s zone label ", zonename); dprintf("%s outside device label range: ", zlbl); dprintf("min - %s, ", min); dprintf("max - %s\n", max); free(zlabel); blabel_free(drange.lower_bound); blabel_free(drange.upper_bound); return (-1); } } else if (flag == CHECK_URANGE) { if (getpwuid_r(uid, &pw_ent, pw_buf, sizeof (pw_buf)) == NULL) { dprintf("Unable to get passwd entry for userid %d\n", (int)uid); free(zlabel); return (-1); } if ((range = getuserrange(pw_ent.pw_name)) == NULL) { dprintf("Unable to get label range for userid %d\n", (int)uid); free(zlabel); return (-1); } in_range = blinrange(zlabel, range); free(zlabel); blabel_free(range->lower_bound); blabel_free(range->upper_bound); free(range); if (in_range == 0) { dprintf("%s device label ", da->da_devname); dprintf("out of user %d label range\n", (int)uid); return (-1); } } else if (flag == CHECK_ZLABEL) { alloczone = kva_match(da->da_devopts, DAOPT_ZONE); if (alloczone == NULL) { free(zlabel); return (-1); } if (strcmp(zonename, alloczone) != 0) { dprintf("%s zone is different than ", zonename); dprintf("%s zone to which the device ", alloczone); dprintf("%s is allocated\n", da->da_devname); free(zlabel); return (-1); } } free(zlabel); return (0); } int create_znode(char *zonename, struct zone_path *zpath, devmap_t *list) { int size; int len = 0; int fcount = 0; char *p, *tmpfile, *zoneroot; char **file; char zonepath[MAXPATHLEN]; di_prof_t prof = NULL; file = list->dmap_devarray; if (file == NULL) return (NODMAPERR); if ((zoneroot = getzonerootbyname(zonename)) == NULL) { dprintf("unable to get label for %s zone\n", zonename); return (1); } (void) strcpy(zonepath, zoneroot); free(zoneroot); len = strlen(zonepath); size = sizeof (zonepath); (void) strlcat(zonepath, "/dev", size); if (di_prof_init(zonepath, &prof)) { dprintf("failed to initialize dev profile at %s\n", zonepath); return (1); } zonepath[len] = '\0'; for (; *file != NULL; file++) { /* * First time initialization */ tmpfile = strdup(*file); /* * Most devices have pathnames starting in /dev * but SunRay devices do not. In SRRS 3.1 they use /tmp. * * If the device pathname is not in /dev then create * a symbolic link to it and put the device in /dev */ if (strncmp(tmpfile, "/dev/", strlen("/dev/")) != 0) { char *linkdir; char srclinkdir[MAXPATHLEN]; char dstlinkdir[MAXPATHLEN]; linkdir = strchr(tmpfile + 1, '/'); p = strchr(linkdir + 1, '/'); *p = '\0'; (void) strcpy(dstlinkdir, "/dev"); (void) strncat(dstlinkdir, linkdir, MAXPATHLEN); (void) snprintf(srclinkdir, MAXPATHLEN, "%s/root%s", zonepath, tmpfile); (void) symlink(dstlinkdir, srclinkdir); *p = '/'; (void) strncat(dstlinkdir, p, MAXPATHLEN); free(tmpfile); tmpfile = strdup(dstlinkdir); } if (di_prof_add_dev(prof, tmpfile)) { dprintf("failed to add %s to profile\n", tmpfile); di_prof_fini(prof); return (1); } if (strlcat(zonepath, tmpfile, size) >= size) { dprintf("Buffer overflow in create_znode for %s\n", *file); free(tmpfile); di_prof_fini(prof); return (1); } free(tmpfile); fcount++; if ((zpath->path = (char **)realloc(zpath->path, (fcount * sizeof (char *)))) == NULL) { di_prof_fini(prof); return (1); } zpath->path[zpath->count] = strdup(zonepath); zpath->count = fcount; zonepath[len] = '\0'; } if (di_prof_commit(prof)) dprintf("failed to add devices to zone %s\n", zonename); di_prof_fini(prof); return (0); } int remove_znode(char *zonename, devmap_t *dm) { int len = 0; char *zoneroot; char **file; char zonepath[MAXPATHLEN]; di_prof_t prof = NULL; file = dm->dmap_devarray; if (file == NULL) return (NODMAPERR); if ((zoneroot = getzonerootbyname(zonename)) == NULL) { (void) snprintf(zonepath, MAXPATHLEN, "/zone/%s", zonename); } else { (void) strcpy(zonepath, zoneroot); free(zoneroot); } /* * To support SunRay we will just deal with the * file in /dev, not the symlinks. */ (void) strncat(zonepath, "/dev", MAXPATHLEN); len = strlen(zonepath); if (di_prof_init(zonepath, &prof)) { dprintf("failed to initialize dev profile at %s\n", zonepath); return (1); } for (; *file != NULL; file++) { char *devrelpath; /* * remove device node from zone. * * SunRay devices don't start with /dev * so skip over first directory to make * sure it is /dev. SunRay devices in zones * will have a symlink into /dev but * we don't ever delete it. */ devrelpath = strchr(*file + 1, '/'); if (di_prof_add_exclude(prof, devrelpath + 1)) { dprintf("Failed exclude %s in dev profile\n", *file); di_prof_fini(prof); return (1); } zonepath[len] = '\0'; } if (di_prof_commit(prof)) dprintf("failed to remove devices from zone %s\n", zonename); di_prof_fini(prof); return (0); } int update_device(char **devnames, char *zonename, int flag) { int len, rc; char *optstr = NULL; da_args dargs; devinfo_t devinfo; dargs.optflag = flag; dargs.optflag |= DA_UPDATE|DA_ALLOC_ONLY; dargs.rootdir = NULL; dargs.devnames = devnames; devinfo.devname = devinfo.devtype = devinfo.devauths = devinfo.devexec = devinfo.devlist = NULL; if (dargs.optflag & DA_ADD_ZONE) { len = strlen(DAOPT_ZONE) + strlen(zonename) + 3; if ((optstr = (char *)malloc(len)) == NULL) return (-1); (void) snprintf(optstr, len, "%s%s%s", DAOPT_ZONE, KV_ASSIGN, zonename); devinfo.devopts = optstr; } dargs.devinfo = &devinfo; rc = da_update_device(&dargs); if (optstr) free(optstr); return (rc); } #! /bin/sh # # 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 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # This is the audio_clean program. # # Following is the syntax for calling the script: # scriptname [-s|-f|-i|-I] devicename [-A|-D] [username] [zonename] # [zonepath] # # $1: -s for standard cleanup by a user # -f for forced cleanup by an administrator # -i for boot-time initialization (when the system is booted with -r) # -I to suppress error/warning messages; the script is run in the '-i' # mode # # $2: devicename - device to be allocated/deallocated, e.g., sr0 # # $3: -A if cleanup is for allocation, or -D if cleanup is for deallocation. # # $4: username - run the script as this user, rather than as the caller. # # $5: zonename - zone in which device to be allocated/deallocated # # $6: zonepath - root path of zonename # # Unless the clean script is being called for boot-time # initialization, it may communicate with the user via stdin and # stdout. To communicate with the user via CDE dialogs, create a # script or link with the same name, but with ".windowing" appended. # For example, if the clean script specified in device_allocate is # /etc/security/xyz_clean, that script must use stdin/stdout. If a # script named /etc/security/xyz_clean.windowing exists, it must use # dialogs. To present dialogs to the user, the dtksh script # /etc/security/lib/wdwmsg may be used. # # This particular script, audio_clean, will work using stdin/stdout, or # using dialogs. A symbolic link audio_clean.windowing points to # audio_clean. trap "" INT TERM QUIT TSTP ABRT USAGE="usage: $0 [-s|-f|-i|-I] devicename [-A|-D][username][zonename][zonepath]" PATH="/usr/bin:/usr/sbin" WDWMSG="/etc/security/lib/wdwmsg" MODE="allocate" if [ `basename $0` != `basename $0 .windowing` ]; then WINDOWING="yes" else WINDOWING="no" fi # # *** Shell Function Declarations *** # msg() { if [ "$WINDOWING" = "yes" ]; then if [ $MODE = "allocate" ]; then TITLE="Audio Device Allocation" else TITLE="Audio Device Dellocation" fi $WDWMSG "$*" "$TITLE" OK else echo "$*" fi } fail_msg() { if [ "$MODE" = "allocate" ]; then msg "$0: Allocate of $DEVICE failed." else msg "$0: Deallocate of $DEVICE failed." fi exit 1 } # # Main program # # Check syntax, parse arguments. while getopts ifsI c do case $c in i) FLAG=$c;; f) FLAG=$c;; s) FLAG=$c;; I) FLAG=i silent=y;; \?) msg $USAGE exit 1;; esac done shift `expr $OPTIND - 1` DEVICE=$1 if [ "$2" = "-A" ]; then MODE="allocate" elif [ "$2" = "-D" ]; then MODE="deallocate" fi if [ "$MODE" != "allocate" -a "$MODE" != "deallocate" ]; then msg $USAGE exit 1 fi ZONENAME=$4 ZONEPATH=$5 SAVEDIR=/etc/security/audio MAP=`dminfo -v -n $DEVICE` DEVICE=`echo $MAP | cut -f1 -d:` TYPE=`echo $MAP | cut -f2 -d:` FILES=`echo $MAP | cut -f3 -d:` if [ ! -d ${SAVEDIR} ] then /bin/mkdir -m 0755 -p ${SAVEDIR} || fail_msg /bin/chown root:sys ${SAVEDIR} || fail_msg fi for d in $FILES do x="`expr $d : '/dev/mixer[0-9][0-9]*'`" if [ "$x" -ne 0 ] ; then DEVNM=$d break fi done SAVEFILE="${SAVEDIR}/`basename ${DEVNM}`" if [ "${FLAG}" = "i" -a ! -r "${SAVEFILE}" ] then /usr/bin/audioctl save-controls -d ${DEVNM} -f ${SAVEFILE} || fail_msg else /usr/bin/audioctl load-controls -d ${DEVNM} ${SAVEFILE} || fail_msg fi exit 0 # # 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 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Default device_allocation attributes for device types. # Device types supported - # audio, fd, sr, st, rmdisk # # Syntax - # device-type:\ # minlabel=;\ # maxlabel=;\ # auths=;\ # cleanscript= # # Multi-word strings above should be in double quotes. # e.g.: minlabel="TS A B";maxlabel="TS AB";auths=solaris.device.allocate;\ # cleanscript=/bin/true # audio:minlabel=admin_low;maxlabel=admin_high;auths=solaris.device.allocate;cleanscript=/etc/security/lib/audio_clean fd:minlabel=admin_low;maxlabel=admin_high;auths=solaris.device.allocate;cleanscript=/etc/security/lib/disk_clean sr:minlabel=admin_low;maxlabel=admin_high;auths=solaris.device.allocate;cleanscript=/etc/security/lib/disk_clean st:minlabel=admin_low;maxlabel=admin_high;auths=solaris.device.allocate;cleanscript=/etc/security/lib/tape_clean rmdisk:minlabel=admin_low;maxlabel=admin_high;auths=solaris.device.allocate;cleanscript=/etc/security/lib/disk_clean #! /usr/bin/sh # # 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 2010 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # # This is a clean script for removable disks # # Following is the syntax for calling the script: # scriptname [-s|-f|-i|-I] devicename [-A|-D] username zonename zonepath # # -s for standard cleanup by a user # -f for forced cleanup by an administrator # -i for boot-time initialization (when the system is booted with -r) # -I to suppress error/warning messages; the script is run in the '-i' # mode # # $1: devicename - device to be allocated/deallocated, e.g., sr0 # # $2: -A if cleanup is for allocation, or -D if cleanup is for deallocation. # # $3: username - run the script as this user, rather than as the caller. # # $4: zonename - zone in which device to be allocated/deallocated # # $5: zonepath - root path of zonename # # A clean script for a removable media device should prompt the user to # insert correctly labeled media at allocation time, and ensure that the # media is ejected at deallocation time. # # Unless the clean script is being called for boot-time # initialization, it may communicate with the user via stdin and # stdout. To communicate with the user via CDE dialogs, create a # script or link with the same name, but with ".windowing" appended. # For example, if the clean script specified in device_allocate is # /etc/security/xyz_clean, that script must use stdin/stdout. If a # script named /etc/security/xyz_clean.windowing exists, it must use # dialogs. To present dialogs to the user, the dtksh script # /etc/security/lib/wdwmsg may be used. # # This particular script, disk_clean, will work using stdin/stdout, or # using dialogs. A symbolic link disk_clean.windowing points to # disk_clean. # # #################################################### # ################ Local Functions ################# # #################################################### # # Set up for windowing and non-windowing messages # msg_init() { if [ `basename $0` != `basename $0 .windowing` ]; then WINDOWING="yes" case $VOLUME_MEDIATYPE in cdrom) TITLE="CD-ROM";; rmdisk) TITLE="Removable Disk";; floppy) TITLE="Floppy";; *) TITLE="Disk";; esac if [ "$MODE" = "allocate" ]; then TITLE="$TITLE Allocation" else TITLE="$TITLE Deallocation" fi else WINDOWING="no" fi } # # Display a message for the user. For windowing, user must press OK button # to continue. For non-windowing, no response is required. # msg() { if [ "$WINDOWING" = "yes" ]; then $WDWMSG "$*" "$TITLE" OK elif [ "$silent" != "y" ]; then echo "$*" > /dev/${MSGDEV} fi } ok_msg() { if [ "$WINDOWING" = "yes" ]; then $WDWMSG "$*" "$TITLE" READY else form=`gettext "Media in %s is ready. Please store safely."` printf "${form}\n" $PROG $DEVICE > /dev/{MSGDEV} fi } error_msg() { if [ "$WINDOWING" = "yes" ]; then $WDWMSG "$*" "$TITLE" ERROR else form=`gettext "%s: Error cleaning up device %s."` printf "${form}\n" $PROG $DEVICE > /dev/${MSGDEV} fi } # # Ask the user an OK/Cancel question. Return 0 for OK, 1 for Cancel. # okcancel() { if [ "$WINDOWING" = "yes" ]; then $WDWMSG "$*" "$TITLE" OK Cancel elif [ "$silent" != "y" ]; then get_reply "$* (y to continue, n to cancel) \c" y n fi } # # Ask the user an Yes/No question. Return 0 for Yes, 1 for No # yesno() { if [ "$WINDOWING" = "yes" ]; then $WDWMSG "$*" "$TITLE" Yes No elif [ "$silent" != "y" ]; then get_reply "$* (y/n) \c" y n fi } # # Display an error message, put the device in the error state, and exit. # error_exit() { if [ "$silent" != "y" ]; then msg "$2" "$3" \ "\n\nDevice has been placed in allocation error state." \ "\nPlease inform system administrator." fi exit 1 } # # get_reply prompt choice ... # get_reply() { prompt=$1; shift while true do echo $prompt > /dev/tty read reply i=0 for choice in $* do if [ "$choice" = "$reply" ] then return $i else i=`expr $i + 1` fi done done } # # Find the first disk slice containing a file system # find_fs() { # The list of files in device_maps(5) is in an unspecified order. # To speed up the fstyp(8) scanning below in most cases, perform # the search for filesystems as follows: # 1) Select only block device files of the form "/dev/dsk/*". # 2) Sort the list of files in an order more likely to yield # matches: first the fdisk(8) partitions ("/dev/dsk/cNtNdNpN") # then the format(8) slices ("/dev/dsk/cNtNdNsN"), in ascending # numeric order within each group. DEVall="`echo $FILES | \ /bin/tr ' ' '\n' | \ /bin/sed '/^\/dev\/dsk\//!d; s/\([sp]\)\([0-9]*\)$/ \1 \2/;' | \ /bin/sort -t ' ' -k 2,2d -k 3,3n | \ /bin/tr -d ' '`" for DEVn in $DEVall ; do fstyp_output="`/usr/sbin/fstyp -a $DEVn 2>&1`" if [ $? = 0 ]; then FSPATH=$DEVn gen_volume_label="`echo "$fstyp_output" | \ sed -n '/^gen_volume_label: .\(.*\).$/s//\1/p'`" if [ "$gen_volume_label" != "" ]; then FSNAME="`echo $gen_volume_label | \ /usr/xpg4/bin/tr '[:upper:] ' '[:lower:]_'`" fi # For consistency, hsfs filesystems detected at # /dev/dsk/*p0 are mounted as /dev/dsk/*s2 FSTYPE=`echo "$fstyp_output" | /bin/head -1` if [ "$FSTYPE" = hsfs -a \ `/bin/expr $FSPATH : '.*p0'` -gt 0 ]; then FSPATH=`echo $FSPATH | /bin/sed 's/p0$/s2/'` fi return fi done } # # Find all mountpoints in use for a set of device special files. # Usage: findmounts devpath ... # findmounts() { nawk -f - -v vold_root="$VOLD_ROOT" -v devs="$*" /etc/mnttab <<\ "ENDOFAWKPGM" BEGIN { split(devs, devlist, " "); for (devN in devlist) { dev = devlist[devN]; realdevlist[dev] = 1; sub(/.*\//, "", dev); sub(/s[0-9]$/, "", dev); if (vold_root != "") { vold_dir[vold_root "/dev/dsk/" dev] = 1; vold_dir[vold_root "/dev/rdsk/" dev] = 1; } } } { for (dev in realdevlist) { if ($1 == dev) { mountpoint = $2; print mountpoint; } } for (dev in vold_dir) { if (substr($1, 1, length(dev)) == dev) { mountpoint = $2; print mountpoint; } } } ENDOFAWKPGM } # # Allocate a device. # Ask the user to make sure the disk is properly labeled. # Ask if the disk should be mounted. # do_allocate() { if [ $VOLUME_MEDIATYPE = floppy ]; then # Determine if media is in drive eject_msg="`eject -q $DEVFILE 2>&1`" eject_status="$?" case $eject_status in 1) # Media is not in drive okcancel "Insert disk in $DEVICE." if [ $? != 0 ]; then exit 0 fi;; 3) # Error error_exit $DEVICE \ "Error checking for media in drive.";; esac else okcancel "Insert disk in $DEVICE." if [ $? != 0 ]; then exit 0 fi fi yesno "Do you want $DEVICE mounted?" if [ $? != 0 ]; then exit 0 fi if [ $VOLUME_MEDIATYPE = cdrom -o $VOLUME_MEDIATYPE = rmdisk ]; then # Get the device path and volume name of a partition find_fs if [ "$FSPATH" != "" ]; then VOLUME_PATH=$FSPATH fi if [ "$FSNAME" != "" ]; then VOLUME_NAME=$FSNAME fi fi VOLUME_ACTION=insert # Give ourself write permission on device file so file system gets # mounted read/write if possible. # rmmount only cares about permissions not user... chown $VOLUME_USER $VOLUME_PATH chmod 700 $VOLUME_PATH # Do the actual mount. VOLUME_* environment variables are inputs to # rmmount. rmmount_msg="`/usr/sbin/rmmount 2>&1`" rmmount_status="$?" if [ $rmmount_status -eq 0 ]; then EXIT_STATUS=$CLEAN_MOUNT elif [ $rmmount_status -gt 0 -a $VOLUME_MEDIATYPE != cdrom ]; then # Try again in readonly mode. cdrom is always mounted ro, so # no need to try again. echo "Read-write mount of $DEVICE failed. Mounting read-only." VOLUME_ACTION=remount; export VOLUME_ACTION VOLUME_MOUNT_MODE=ro; export VOLUME_MOUNT_MODE `/usr/sbin/rmmount` if [ $? -eq 0 ]; then EXIT_STATUS=$CLEAN_MOUNT fi fi # Set permissions on directory used by vold, sdtvolcheck, etc. if [ -d /tmp/.removable ]; then chown root /tmp/.removable chmod 777 /tmp/.removable fi } do_deallocate() { if [ $VOLUME_MEDIATYPE = cdrom -o $VOLUME_MEDIATYPE = rmdisk ]; then if [ -h /$VOLUME_MEDIATYPE/$DEVICE ]; then # Get the device path and volume name of a partition VOLUME_PATH=`ls -l /$VOLUME_MEDIATYPE/$DEVICE|\ cut -d '>' -f2` VOLUME_DEVICE=`mount -p|grep $VOLUME_PATH|\ cut -d ' ' -f1` fi fi if [ -d "$VOLUME_PATH" ]; then VOLUME_ACTION=eject # Do the actual unmount. # VOLUME_* environment variables are inputs to rmmount. rmmount_msg="`/usr/sbin/rmmount 2>&1`" rmmount_status="$?" # Remove symbolic links to mount point for name in /$VOLUME_MEDIATYPE/*; do if [ -h $name ]; then target=`ls -l $name | awk '{ print $NF; }'` target_dir=`dirname $target` target_device=`echo $target_dir | \ sed -e 's/^.*-\(.*\)$/\1/'` if [ "$target_device" = "$DEVICE" ]; then rm -f $name fi fi done else rmmount_status=0 fi case $rmmount_status in 1) # still mounted error_exit $DEVICE "Error unmounting $DEVICE" "$rmmount_msg";; 0) # not mounted # Eject the media if [ "$FLAG" = "f" ] ; then eject_msg="`eject -f $DEVICE 2>&1`" else eject_msg="`eject $DEVICE 2>&1`" fi eject_status="$?" case $eject_status in 0|1|4) # Media has been ejected case $VOLUME_MEDIATYPE in floppy|cdrom|rmdisk) msg "Please remove the disk from $DEVICE.";; esac;; 3) # Media didn't eject msg $DEVICE "Error ejecting disk from $DEVICE" \ "$eject_msg";; esac esac } # # Reclaim a device # do_init() { eject_msg="`eject -f $DEVICE 2>&1`" eject_status="$?" case $eject_status in 0) # Media has been ejected if [ "$silent" != "y" ]; then ok_msg fi exit 0;; 1) # Media not ejected if [ "$silent" != "y" ]; then error_msg fi exit 0;; 3) # Error if [ "$silent" != "y" ]; then error_msg fi msg $DEVICE "Error ejecting disk from $DEVICE" \ "$eject_msg" exit 2;; esac } # #################################################### # ################ Begin main program ################ # #################################################### trap "" INT TERM QUIT TSTP ABRT PATH="/usr/bin:/usr/sbin" MODE="allocate" SILENT=n WDWMSG="/etc/security/lib/wdwmsg" VOLUME_ZONE_PATH="/" USAGE="Usage: disk_clean [-s|-f|-i|-I] devicename -[A|D] [username] [zonename] [zonepath]" EXIT_STATUS=0 CLEAN_MOUNT=4 MACH=`uname -p` FLAG=i # # Parse the command line arguments # while getopts ifsI c do case $c in i) FLAG=$c;; f) FLAG=$c;; s) FLAG=$c;; I) FLAG=i silent=y;; \?) echo $USAGE exit 1;; esac done shift `expr $OPTIND - 1` DEVICE=$1 MODE="deallocate" if [ "$2" = "-A" ]; then MODE="allocate" elif [ "$2" = "-D" ]; then MODE="deallocate" fi #get the device_maps information MAP=`/usr/sbin/list_devices -s -l $DEVICE` FILES=`echo $MAP | cut -f4 -d:` # e.g., /dev/dsk/c0t6d0s0 /dev/dsk/c0t6d0s1 ... DEVFILE=`echo $FILES | cut -f1 -d" "` # e.g., "/dev/dsk/c0t6d0s0" # Set VOLUME_ variables that are inputs to rmmount VOLUME_DEVICE=`echo $FILES | cut -f2 -d" "` # e.g., "/dev/dsk/c0t6d0s1" MEDIATYPE=`echo $MAP | cut -f3 -d: | cut -f2 -d" "` # e.g., "cdrom" or "floppy" if [ "$MEDIATYPE" = "sr" ]; then VOLUME_MEDIATYPE="cdrom" elif [ "$MEDIATYPE" = "fd" ]; then VOLUME_MEDIATYPE="floppy" elif [ "$MEDIATYPE" = "rmdisk" ]; then VOLUME_MEDIATYPE="rmdisk" fi VOLUME_PATH=$DEVFILE # e.g., "/dev/dsk/c0t6d0s0" if { [ "$MACH" = "amd64" ] || [ "$MACH" = "i386" ]; } && [ "$MEDIATYPE" = "rmdisk" ]; then VOLUME_PATH=`echo $DEVFILE | sed -e 's/s0/p0/'` fi SYMDEV=`echo $DEVICE | sed -e 's/_//'` # e.g., "cdrom" or "floppy" SYMNUM=`echo $SYMDEV | sed -e 's/[a-z]*//g'` SYMDEV=`echo $SYMDEV | sed -e 's/[0-9]*//g'` if [ "$SYMDEV" = "sr" ]; then VOLUME_SYMDEV="cdrom"$SYMNUM elif [ "$SYMDEV" = "fd" ]; then VOLUME_SYMDEV="floppy"$SYMNUM elif [ "$SYMDEV" = "rmdisk" ]; then VOLUME_SYMDEV="rmdisk"$SYMNUM else VOLUME_SYMDEV=$SYMDEV$SYMNUM fi VOLUME_ZONE_NAME=$4 VOLUME_ZONE_PATH=$5 if [ "$MODE" = "allocate" ]; then if [ -n "$3" ]; then # e.g., "joeuser" VOLUME_USER=$3 else VOLUME_USER=`/usr/xpg4/bin/id -u -nr` fi else # If there's a directory for the device under /, get the # user name from there, to use in cleaning up that directory. Otherwise, # the user name isn't actually used in deallocation. if [ -d ${VOLUME_ZONE_PATH}/${VOLUME_MEDIATYPE}/*-${DEVICE} ]; then VOLUME_USER=`ls -ld ${VOLUME_ZONE_PATH}/${VOLUME_MEDIATYPE}/*-${DEVICE} | awk '/^d/{print $3}'` else if [ -n "$3" ]; then VOLUME_USER=$3 else VOLUME_USER=`/usr/xpg4/bin/id -u -nr` fi fi fi VOLUME_NAME=unnamed_${VOLUME_MEDIATYPE} # e.g., "joeuser-cdrom0/unnamed_cdrom" if [ "$VOLUME_MEDIATYPE" = "rmdisk" ]; then VOLUME_PCFS_ID=1 else VOLUME_PCFS_ID= fi export VOLUME_ACTION VOLUME_DEVICE VOLUME_MEDIATYPE VOLUME_NAME VOLUME_PCFS_ID export VOLUME_PATH VOLUME_SYMDEV VOLUME_USER VOLUME_ZONE_NAME VOLUME_ZONE_PATH USERDIR=${VOLUME_USER}-${DEVICE} # e.g., "joeusr-cdrom0" msg_init if [ "$MODE" = "allocate" ]; then MSGDEV=tty do_allocate else if [ "$FLAG" = "i" ] ; then MSGDEV=console do_init else MSGDEV=tty do_deallocate fi fi exit $EXIT_STATUS /* * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #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); } #! /bin/sh # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (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 (c) 1992-1993, 1997-2001 by Sun Microsystems, Inc. # All rights reserved. # #ident "%Z%%M% %I% %E% SMI" # # This a clean script for the floppy drive # PROG=`basename $0` PATH="/usr/sbin:/usr/bin" TEXTDOMAIN="SUNW_OST_OSCMD" export TEXTDOMAIN USAGE=`gettext "%s [-I|-s|-f|-i] device"` # # *** Shell Function Declarations *** # con_msg() { form=`gettext "%s: Media in %s is ready. Please, label and store safely."` if [ "$silent" != "y" ] ; then printf "${form}\n" $PROG $DEVICE > /dev/console fi } e_con_msg() { form=`gettext "%s: Error cleaning up device %s."` if [ "$silent" != "y" ] ; then printf "${form}\n" $PROG $DEVICE > /dev/console fi } user_msg() { form=`gettext "%s: Media in %s is ready. Please, label and store safely."` if [ "$silent" != "y" ] ; then printf "${form}\n" $PROG $DEVICE > /dev/tty fi } e_user_msg() { form=`gettext "%s: Error cleaning up device %s."` if [ "$silent" != "y" ] ; then printf "${form}\n" $PROG $DEVICE > /dev/tty gettext "Please inform system administrator.\n" > /dev/tty fi } mk_error() { chown bin /etc/security/dev/$1 chmod 0100 /etc/security/dev/$1 } # # *** Begin main program *** # silent=n # Parse the argumnets while getopts Iifs c do case $c in I) FLAG=i silent=y;; i) FLAG=$c;; f) FLAG=$c;; s) FLAG=$c;; \?) printf "${USAGE}\n" $PROG exit 1 ;; esac done shift `expr $OPTIND - 1` # get the map information FLOPPY=$1 MAP=`dminfo -v -n $FLOPPY` DEVICE=`echo $MAP | cut -f1 -d:` TYPE=`echo $MAP | cut -f2 -d:` FILES=`echo $MAP | cut -f3 -d:` DEVFILE=`echo $FILES | cut -f1 -d" "` #if init then do once and exit lform=`gettext "%s error: %s."` if [ "$FLAG" = "i" ] ; then x="`eject -q $DEVFILE 2>&1`" # Determine if there is media in drive z="$?" case $z in 0) # Media is in the drive. a="`eject -f $DEVFILE 2>&1`" b="$?" case $b in 0) # Media has been ejected con_msg exit 0;; 1) # Media not ejected mk_error $DEVICE if [ "$silent" != "y" ] ; then printf "${lform}\n" $PROG $a >/dev/tty fi e_con_msg exit 1;; 2) # Error mk_error $DEVICE if [ "$silent" != "y" ] ; then printf "${lform}\n" $PROG $a >/dev/tty fi e_con_msg exit 1;; 3) # Error - Perhaps drive doesn't support ejection mk_error $DEVICE if [ "$silent" != "y" ] ; then printf "${lform}\n" $PROG $a >/dev/tty fi e_con_msg exit 1;; esac;; 1) # No media in drive con_msg exit 0;; 2) # Error mk_error $DEVICE if [ "$silent" != "y" ] ; then printf "${lform}\n" $PROG $x >/dev/tty fi e_con_msg exit 1;; 3) # Error mk_error $DEVICE if [ "$silent" != "y" ] ; then printf "${lform}\n" $PROG $x >/dev/tty fi e_con_msg exit 1;; esac else # interactive clean up x="`eject -q $DEVFILE 2>&1`" # Determine if there is media in drive z="$?" case $z in 0) # Media is in the drive. a="`eject -f $DEVFILE 2>&1`" b="$?" case $b in 0) # Media has been ejected user_msg exit 0;; 1) # Media didn't eject mk_error $DEVICE if [ "$silent" != "y" ] ; then printf "${lform}\n" $PROG $a >/dev/tty fi e_user_msg exit 1;; 2) # Other Error mk_error $DEVICE if [ "$silent" != "y" ] ; then printf "${lform}\n" $PROG $a >/dev/tty fi e_user_msg exit 1;; 3) if echo $a | grep "failed" >/dev/null ; then while true # Drive doesn't support eject, so loop do c="`eject -q $DEVFILE 2>&1`" # Is floppy in drive? d="$?" if [ $d -eq 0 ] ; then # Yes, Floppy in drive form=`gettext "Please remove the floppy from %s."` if [ "$silent" != "y" ] ; then printf "${form}\n" $DEVICE >/dev/tty /usr/5bin/echo \\007 > /dev/tty fi sleep 3 elif echo $c | grep "NOT" > /dev/null ; then # No,Floppy NOT in drive user_msg exit 0 else # Error occurred mk_error $DEVICE if [ "$silent" != "y" ] ; then printf "${lform}\n" $PROG $a >/dev/tty fi e_user_msg exit 1 fi done else # Some other failure if [ "$silent" != "y" ] ; then printf "${lform}\n" $PROG $a >/dev/tty fi e_user_msg mk_error $DEVICE exit 1 fi;; esac;; 1) # No media in the drive user_msg exit 0;; 2) mk_error $DEVICE if [ "$silent" != "y" ] ; then printf "${lform}\n" $PROG $x >/dev/tty fi e_user_msg exit 1;; 3) mk_error $DEVICE if [ "$silent" != "y" ] ; then printf "${lform}\n" $PROG $x >/dev/tty fi e_user_msg exit 1;; esac fi exit 2 /* * 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 2010 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * scan /dev directory for mountable objects and construct device_allocate * file for allocate.... * * devices are: * tape (cartridge) * /dev/rst* * /dev/nrst* * /dev/rmt/... * audio * /dev/audio * /dev/audioctl * /dev/sound/... * floppy * /dev/diskette * /dev/fd* * /dev/rdiskette * /dev/rfd* * CD * /dev/sr* * /dev/nsr* * /dev/dsk/c?t?d0s? * /dev/rdsk/c?t?d0s? * */ #include #include #include /* for stat(2), etc. */ #include #include /* for readdir(3), etc. */ #include /* for readlink(2) */ #include #include /* for strcpy(3), etc. */ #include /* for bcopy(3C), etc. */ #include /* for perror(3) */ #include /* for atoi(3) */ #include #include #include #include #include #include #include #include #include #include #include #ifndef TEXT_DOMAIN #define TEXT_DOMAIN "SUNW_OST_OSCMD" #endif #define MKDEVALLOC "mkdevalloc" #define MKDEVMAPS "mkdevmaps" #define DELTA 5 /* array size delta when full */ #define SECLIB "/etc/security/lib" /* "/dev/rst...", "/dev/nrst...", "/dev/rmt/..." */ struct tape { char *name; char *device; int number; } *tape; #define DFLT_NTAPE 10 /* size of initial array */ #define SIZE_OF_RST 3 /* |rmt| */ #define SIZE_OF_NRST 4 /* |nrmt| */ #define SIZE_OF_TMP 4 /* |/tmp| */ #define SIZE_OF_RMT 8 /* |/dev/rmt| */ #define TAPE_CLEAN SECLIB"/st_clean" /* "/dev/audio", "/dev/audioctl", "/dev/sound/..." */ struct audio { char *name; char *device; int number; } *audio; #define DFLT_NAUDIO 10 /* size of initial array */ #define SIZE_OF_SOUND 10 /* |/dev/sound| */ #define AUDIO_CLEAN SECLIB"/audio_clean" /* "/dev/sr", "/dev/nsr", "/dev/dsk/c?t?d0s?", "/dev/rdsk/c?t?d0s?" */ struct cd { char *name; char *device; int id; int controller; int number; } *cd; #define DFLT_NCD 10 /* size of initial array */ #define SIZE_OF_SR 2 /* |sr| */ #define SIZE_OF_RSR 3 /* |rsr| */ #define SIZE_OF_DSK 8 /* |/dev/dsk| */ #define SIZE_OF_RDSK 9 /* |/dev/rdsk| */ #define CD_CLEAN SECLIB"/sr_clean" /* "/dev/sr", "/dev/nsr", "/dev/dsk/c?t?d0s?", "/dev/rdsk/c?t?d0s?" */ struct rmdisk { char *name; char *device; int id; int controller; int number; } *rmdisk, *rmdisk_r; #define DFLT_RMDISK 10 /* size of initial array */ /* "/dev/fd0*", "/dev/rfd0*", "/dev/fd1*", "/dev/rfd1*" */ struct fp { char *name; char *device; int number; } *fp; #define DFLT_NFP 10 /* size of initial array */ #define SIZE_OF_FD0 3 /* |fd0| */ #define SIZE_OF_RFD0 4 /* |rfd0| */ #define FLOPPY_CLEAN SECLIB"/fd_clean" static void dotape(); static void doaudio(); static void dofloppy(); static int docd(); static void dormdisk(int); static void initmem(); static int expandmem(int, void **, int); static void no_memory(void); int system_labeled = 0; int do_devalloc = 0; int do_devmaps = 0; int do_files = 0; devlist_t devlist; int main(int argc, char **argv) { int cd_count = 0; char *progname; (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); if ((progname = strrchr(argv[0], '/')) == NULL) progname = argv[0]; else progname++; if (strcmp(progname, MKDEVALLOC) == 0) do_devalloc = 1; else if (strcmp(progname, MKDEVMAPS) == 0) do_devmaps = 1; else exit(1); system_labeled = is_system_labeled(); if (!system_labeled) { /* * is_system_labeled() will return false in case we are * starting before the first reboot after Trusted Extensions * is enabled. Check the setting in /etc/system to see if * TX is enabled (even if not yet booted). */ if (defopen("/etc/system") == 0) { if (defread("set sys_labeling=1") != NULL) system_labeled = 1; /* close defaults file */ (void) defopen(NULL); } } #ifdef DEBUG /* test hook: see also devfsadm.c and allocate.c */ if (!system_labeled) { struct stat tx_stat; system_labeled = is_system_labeled_debug(&tx_stat); if (system_labeled) { fprintf(stderr, "/ALLOCATE_FORCE_LABEL is set,\n" "forcing system label on for testing...\n"); } } #endif if (system_labeled && do_devalloc && (argc == 2) && (strcmp(argv[1], DA_IS_LABELED) == 0)) { /* * write device entries to device_allocate and device_maps. * default is to print them on stdout. */ do_files = 1; } initmem(); /* initialize memory */ dotape(); doaudio(); dofloppy(); cd_count = docd(); if (system_labeled) dormdisk(cd_count); return (0); } static void dotape() { DIR *dirp; struct dirent *dep; /* directory entry pointer */ int i, j; char *nm; /* name/device of special device */ char linkvalue[2048]; /* symlink value */ struct stat stat; /* determine if it's a symlink */ int sz; /* size of symlink value */ char *cp; /* pointer into string */ int ntape; /* max array size */ int tape_count; int first = 0; char *dname, *dtype, *dclean; da_args dargs; deventry_t *entry; ntape = DFLT_NTAPE; /* * look for rst* and nrst* */ if ((dirp = opendir("/dev")) == NULL) { perror(gettext("open /dev failure")); exit(1); } i = 0; while (dep = readdir(dirp)) { /* ignore if neither rst* nor nrst* */ if (strncmp(dep->d_name, "rst", SIZE_OF_RST) && strncmp(dep->d_name, "nrst", SIZE_OF_NRST)) continue; /* if array full, then expand it */ if (i == ntape) { /* will exit(1) if insufficient memory */ ntape = expandmem(i, (void **)&tape, sizeof (struct tape)); } /* save name (/dev + / + d_name + \0) */ nm = (char *)malloc(SIZE_OF_TMP + 1 + strlen(dep->d_name) + 1); if (nm == NULL) no_memory(); (void) strcpy(nm, "/dev/"); (void) strcat(nm, dep->d_name); tape[i].name = nm; /* ignore if not symbolic link (note i not incremented) */ if (lstat(tape[i].name, &stat) < 0) { perror("stat(2) failed "); exit(1); } if ((stat.st_mode & S_IFMT) != S_IFLNK) continue; /* get name from symbolic link */ if ((sz = readlink(tape[i].name, linkvalue, sizeof (linkvalue))) < 0) continue; nm = (char *)malloc(sz + 1); if (nm == NULL) no_memory(); (void) strncpy(nm, linkvalue, sz); nm[sz] = '\0'; tape[i].device = nm; /* get device number */ cp = strrchr(tape[i].device, '/'); cp++; /* advance to device # */ (void) sscanf(cp, "%d", &tape[i].number); i++; } (void) closedir(dirp); /* * scan /dev/rmt and add entry to table */ if ((dirp = opendir("/dev/rmt")) == NULL) { perror(gettext("open /dev failure")); exit(1); } while (dep = readdir(dirp)) { /* skip . .. etc... */ if (strncmp(dep->d_name, ".", 1) == 0) continue; /* if array full, then expand it */ if (i == ntape) { /* will exit(1) if insufficient memory */ ntape = expandmem(i, (void **)&tape, sizeof (struct tape)); } /* save name (/dev/rmt + / + d_name + \0) */ nm = (char *)malloc(SIZE_OF_RMT + 1 + strlen(dep->d_name) + 1); if (nm == NULL) no_memory(); (void) strcpy(nm, "/dev/rmt/"); (void) strcat(nm, dep->d_name); tape[i].name = nm; /* save device name (rmt/ + d_name + \0) */ nm = (char *)malloc(SIZE_OF_TMP + strlen(dep->d_name) + 1); if (nm == NULL) no_memory(); (void) strcpy(nm, "rmt/"); (void) strcat(nm, dep->d_name); tape[i].device = nm; (void) sscanf(dep->d_name, "%d", &tape[i].number); i++; } tape_count = i; (void) closedir(dirp); /* remove duplicate entries */ for (i = 0; i < tape_count - 1; i++) { for (j = i + 1; j < tape_count; j++) { if (strcmp(tape[i].device, tape[j].device)) continue; tape[j].number = -1; } } if (system_labeled) { dname = DA_TAPE_NAME; dtype = DA_TAPE_TYPE; dclean = DA_DEFAULT_TAPE_CLEAN; } else { dname = "st"; dtype = "st"; dclean = TAPE_CLEAN; } for (i = 0; i < 8; i++) { for (j = 0; j < tape_count; j++) { if (tape[j].number != i) continue; if (do_files) { (void) da_add_list(&devlist, tape[j].name, i, DA_TAPE); } else if (do_devalloc) { /* print device_allocate for tape devices */ if (system_labeled) { (void) printf("%s%d%s\\\n", dname, i, KV_DELIMITER); (void) printf("\t%s%s\\\n", DA_TAPE_TYPE, KV_DELIMITER); (void) printf("\t%s%s\\\n", DA_RESERVED, KV_DELIMITER); (void) printf("\t%s%s\\\n", DA_RESERVED, KV_DELIMITER); (void) printf("\t%s%s\\\n", DEFAULT_DEV_ALLOC_AUTH, KV_DELIMITER); (void) printf("\t%s\n\n", dclean); } else { (void) printf( "st%d;st;reserved;reserved;%s;", i, DEFAULT_DEV_ALLOC_AUTH); (void) printf("%s%s\n", SECLIB, "/st_clean"); } break; } else if (do_devmaps) { /* print device_maps for tape devices */ if (first) { (void) printf(" "); } else { if (system_labeled) { (void) printf("%s%d%s\\\n", dname, i, KV_TOKEN_DELIMIT); (void) printf("\t%s%s\\\n", dtype, KV_TOKEN_DELIMIT); (void) printf("\t"); } else { (void) printf("st%d:\\\n", i); (void) printf("\trmt:\\\n"); (void) printf("\t"); } first++; } (void) printf("%s", tape[j].name); } } if (do_devmaps && first) { (void) printf("\n\n"); first = 0; } } if (do_files && tape_count) { dargs.rootdir = NULL; dargs.devnames = NULL; dargs.optflag = DA_ADD; for (entry = devlist.tape; entry != NULL; entry = entry->next) { dargs.devinfo = &(entry->devinfo); (void) da_update_device(&dargs); } } } static void doaudio() { DIR *dirp; struct dirent *dep; /* directory entry pointer */ int i, j; char *nm; /* name/device of special device */ char linkvalue[2048]; /* symlink value */ struct stat stat; /* determine if it's a symlink */ int sz; /* size of symlink value */ char *cp; /* pointer into string */ int naudio; /* max array size */ int audio_count = 0; int len, slen; int first = 0; char dname[128]; char *dclean; da_args dargs; deventry_t *entry; naudio = DFLT_NAUDIO; if ((dirp = opendir("/dev")) == NULL) { perror(gettext("open /dev failure")); exit(1); } i = 0; while (dep = readdir(dirp)) { if (strcmp(dep->d_name, "audio") && strcmp(dep->d_name, "audioctl")) continue; /* if array full, then expand it */ if (i == naudio) { /* will exit(1) if insufficient memory */ naudio = expandmem(i, (void **)&audio, sizeof (struct audio)); } /* save name (/dev + 1 + d_name + \0) */ nm = (char *)malloc(SIZE_OF_TMP + 1 + strlen(dep->d_name) + 1); if (nm == NULL) no_memory(); (void) strcpy(nm, "/dev/"); (void) strcat(nm, dep->d_name); audio[i].name = nm; /* ignore if not symbolic link (note i not incremented) */ if (lstat(audio[i].name, &stat) < 0) { perror(gettext("stat(2) failed ")); exit(1); } if ((stat.st_mode & S_IFMT) != S_IFLNK) continue; /* get name from symbolic link */ if ((sz = readlink(audio[i].name, linkvalue, sizeof (linkvalue))) < 0) continue; nm = (char *)malloc(sz + 1); if (nm == NULL) no_memory(); (void) strncpy(nm, linkvalue, sz); nm[sz] = '\0'; audio[i].device = nm; cp = strrchr(audio[i].device, '/'); cp++; /* advance to device # */ (void) sscanf(cp, "%d", &audio[i].number); i++; } (void) closedir(dirp); if ((dirp = opendir("/dev/sound")) == NULL) { goto skip; } while (dep = readdir(dirp)) { /* skip . .. etc... */ if (strncmp(dep->d_name, ".", 1) == 0) continue; /* if array full, then expand it */ if (i == naudio) { /* will exit(1) if insufficient memory */ naudio = expandmem(i, (void **)&audio, sizeof (struct audio)); } /* save name (/dev/sound + / + d_name + \0) */ nm = (char *)malloc(SIZE_OF_SOUND + 1 + strlen(dep->d_name) + 1); if (nm == NULL) no_memory(); (void) strcpy(nm, "/dev/sound/"); (void) strcat(nm, dep->d_name); audio[i].name = nm; nm = (char *)malloc(SIZE_OF_SOUND + 1 + strlen(dep->d_name) + 1); if (nm == NULL) no_memory(); (void) strcpy(nm, "/dev/sound/"); (void) strcat(nm, dep->d_name); audio[i].device = nm; (void) sscanf(dep->d_name, "%d", &audio[i].number); i++; } (void) closedir(dirp); skip: audio_count = i; /* remove duplicate entries */ for (i = 0; i < audio_count - 1; i++) { for (j = i + 1; j < audio_count; j++) { if (strcmp(audio[i].device, audio[j].device)) continue; audio[j].number = -1; } } /* print out device_allocate entries for audio devices */ (void) strcpy(dname, DA_AUDIO_NAME); slen = strlen(DA_AUDIO_NAME); len = sizeof (dname) - slen; dclean = system_labeled ? DA_DEFAULT_AUDIO_CLEAN : AUDIO_CLEAN; for (i = 0; i < 8; i++) { for (j = 0; j < audio_count; j++) { if (audio[j].number != i) continue; if (system_labeled) (void) snprintf(dname+slen, len, "%d", i); if (do_files) { (void) da_add_list(&devlist, audio[j].name, i, DA_AUDIO); } else if (do_devalloc) { /* print device_allocate for audio devices */ if (system_labeled) { (void) printf("%s%s\\\n", dname, KV_DELIMITER); (void) printf("\t%s%s\\\n", DA_AUDIO_TYPE, KV_DELIMITER); (void) printf("\t%s%s\\\n", DA_RESERVED, KV_DELIMITER); (void) printf("\t%s%s\\\n", DA_RESERVED, KV_DELIMITER); (void) printf("\t%s%s\\\n", DEFAULT_DEV_ALLOC_AUTH, KV_DELIMITER); (void) printf("\t%s\n\n", dclean); } else { (void) printf("audio;audio;"); (void) printf("reserved;reserved;%s;", DEFAULT_DEV_ALLOC_AUTH); (void) printf("%s%s\n", SECLIB, "/audio_clean"); } break; } else if (do_devmaps) { /* print device_maps for audio devices */ if (first) { (void) printf(" "); } else { if (system_labeled) { (void) printf("%s%s\\\n", dname, KV_TOKEN_DELIMIT); (void) printf("\t%s%s\\\n", DA_AUDIO_TYPE, KV_TOKEN_DELIMIT); (void) printf("\t"); } else { (void) printf("audio:\\\n"); (void) printf("\taudio:\\\n"); (void) printf("\t"); } first++; } (void) printf("%s", audio[j].name); } } if (do_devmaps && first) { (void) printf("\n\n"); first = 0; } } if (do_files && audio_count) { dargs.rootdir = NULL; dargs.devnames = NULL; dargs.optflag = DA_ADD; for (entry = devlist.audio; entry != NULL; entry = entry->next) { dargs.devinfo = &(entry->devinfo); (void) da_update_device(&dargs); } } } static void dofloppy() { DIR *dirp; struct dirent *dep; /* directory entry pointer */ int i, j; char *nm; /* name/device of special device */ char linkvalue[2048]; /* symlink value */ struct stat stat; /* determine if it's a symlink */ int sz; /* size of symlink value */ char *cp; /* pointer into string */ int nfp; /* max array size */ int floppy_count = 0; int first = 0; char *dname, *dclean; da_args dargs; deventry_t *entry; nfp = DFLT_NFP; /* * look for fd* and rfd* */ if ((dirp = opendir("/dev")) == NULL) { perror(gettext("open /dev failure")); exit(1); } i = 0; while (dep = readdir(dirp)) { /* ignore if neither rst* nor nrst* */ if (strncmp(dep->d_name, "fd0", SIZE_OF_FD0) && strncmp(dep->d_name, "rfd0", SIZE_OF_RFD0) && strncmp(dep->d_name, "fd1", SIZE_OF_FD0) && strncmp(dep->d_name, "rfd0", SIZE_OF_RFD0)) continue; /* if array full, then expand it */ if (i == nfp) { /* will exit(1) if insufficient memory */ nfp = expandmem(i, (void **)&fp, sizeof (struct fp)); } /* save name (/dev + 1 + d_name + \0) */ nm = (char *)malloc(SIZE_OF_TMP + 1 + strlen(dep->d_name) + 1); if (nm == NULL) no_memory(); (void) strcpy(nm, "/dev/"); (void) strcat(nm, dep->d_name); fp[i].name = nm; /* ignore if not symbolic link (note i not incremented) */ if (lstat(fp[i].name, &stat) < 0) { perror(gettext("stat(2) failed ")); exit(1); } if ((stat.st_mode&S_IFMT) != S_IFLNK) continue; /* get name from symbolic link */ if ((sz = readlink(fp[i].name, linkvalue, sizeof (linkvalue))) < 0) continue; nm = (char *)malloc(sz+1); if (nm == NULL) no_memory(); (void) strncpy(nm, linkvalue, sz); nm[sz] = '\0'; fp[i].device = nm; /* get device number */ cp = strchr(fp[i].name, 'd'); cp++; /* advance to device # */ cp = strchr(cp, 'd'); cp++; /* advance to device # */ (void) sscanf(cp, "%d", &fp[i].number); i++; } (void) closedir(dirp); floppy_count = i; /* print out device_allocate entries for floppy devices */ if (system_labeled) { dname = DA_FLOPPY_NAME; dclean = DA_DEFAULT_DISK_CLEAN; } else { dname = "fd"; dclean = FLOPPY_CLEAN; } for (i = 0; i < 8; i++) { for (j = 0; j < floppy_count; j++) { if (fp[j].number != i) continue; if (do_files) { (void) da_add_list(&devlist, fp[j].name, i, DA_FLOPPY); } else if (do_devalloc) { /* print device_allocate for floppy devices */ if (system_labeled) { (void) printf("%s%d%s\\\n", dname, i, KV_DELIMITER); (void) printf("\t%s%s\\\n", DA_FLOPPY_TYPE, KV_DELIMITER); (void) printf("\t%s%s\\\n", DA_RESERVED, KV_DELIMITER); (void) printf("\t%s%s\\\n", DA_RESERVED, KV_DELIMITER); (void) printf("\t%s%s\\\n", DEFAULT_DEV_ALLOC_AUTH, KV_DELIMITER); (void) printf("\t%s\n\n", dclean); } else { (void) printf( "fd%d;fd;reserved;reserved;%s;", i, DEFAULT_DEV_ALLOC_AUTH); (void) printf("%s%s\n", SECLIB, "/fd_clean"); } break; } else if (do_devmaps) { /* print device_maps for floppy devices */ if (first) { (void) printf(" "); } else { if (system_labeled) { (void) printf("%s%d%s\\\n", dname, i, KV_TOKEN_DELIMIT); (void) printf("\t%s%s\\\n", DA_FLOPPY_TYPE, KV_TOKEN_DELIMIT); (void) printf("\t"); } else { (void) printf("fd%d:\\\n", i); (void) printf("\tfd:\\\n"); (void) printf("\t"); } if (i == 0) { (void) printf("/dev/diskette "); (void) printf( "/dev/rdiskette "); } first++; } (void) printf("%s", fp[j].name); } } if (do_devmaps && first) { (void) printf("\n\n"); first = 0; } } if (do_files && floppy_count) { dargs.rootdir = NULL; dargs.devnames = NULL; dargs.optflag = DA_ADD; for (entry = devlist.floppy; entry != NULL; entry = entry->next) { dargs.devinfo = &(entry->devinfo); (void) da_update_device(&dargs); } } } static int docd() { DIR *dirp; struct dirent *dep; /* directory entry pointer */ int i, j; char *nm; /* name/device of special device */ char linkvalue[2048]; /* symlink value */ struct stat stat; /* determine if it's a symlink */ int sz; /* size of symlink value */ char *cp; /* pointer into string */ int id; /* disk id */ int ctrl; /* disk controller */ int ncd; /* max array size */ int cd_count = 0; int first = 0; char *dname, *dclean; da_args dargs; deventry_t *entry; ncd = DFLT_NCD; /* * look for sr* and rsr* */ if ((dirp = opendir("/dev")) == NULL) { perror(gettext("open /dev failure")); exit(1); } i = 0; while (dep = readdir(dirp)) { /* ignore if neither sr* nor rsr* */ if (strncmp(dep->d_name, "sr", SIZE_OF_SR) && strncmp(dep->d_name, "rsr", SIZE_OF_RSR)) continue; /* if array full, then expand it */ if (i == ncd) { /* will exit(1) if insufficient memory */ ncd = expandmem(i, (void **)&cd, sizeof (struct cd)); } /* save name (/dev + / + d_name + \0) */ nm = (char *)malloc(SIZE_OF_TMP + 1 + strlen(dep->d_name) + 1); if (nm == NULL) no_memory(); (void) strcpy(nm, "/dev/"); (void) strcat(nm, dep->d_name); cd[i].name = nm; /* ignore if not symbolic link (note i not incremented) */ if (lstat(cd[i].name, &stat) < 0) { perror(gettext("stat(2) failed ")); exit(1); } if ((stat.st_mode & S_IFMT) != S_IFLNK) continue; /* get name from symbolic link */ if ((sz = readlink(cd[i].name, linkvalue, sizeof (linkvalue))) < 0) continue; nm = (char *)malloc(sz + 1); if (nm == NULL) no_memory(); (void) strncpy(nm, linkvalue, sz); nm[sz] = '\0'; cd[i].device = nm; cp = strrchr(cd[i].device, '/'); cp++; /* advance to device # */ (void) sscanf(cp, "c%dt%d", &cd[i].controller, &cd[i].number); cd[i].id = cd[i].number; i++; } cd_count = i; (void) closedir(dirp); /* * scan /dev/dsk for cd devices */ if ((dirp = opendir("/dev/dsk")) == NULL) { perror("gettext(open /dev/dsk failure)"); exit(1); } while (dep = readdir(dirp)) { /* skip . .. etc... */ if (strncmp(dep->d_name, ".", 1) == 0) continue; /* get device # (disk #) */ if (sscanf(dep->d_name, "c%dt%d", &ctrl, &id) != 2) continue; /* see if this is one of the cd special devices */ for (j = 0; j < cd_count; j++) { if (cd[j].number == id && cd[j].controller == ctrl) goto found; } continue; /* add new entry to table (/dev/dsk + / + d_name + \0) */ found: /* if array full, then expand it */ if (i == ncd) { /* will exit(1) if insufficient memory */ ncd = expandmem(i, (void **)&cd, sizeof (struct cd)); } nm = (char *)malloc(SIZE_OF_DSK + 1 + strlen(dep->d_name) + 1); if (nm == NULL) no_memory(); (void) strcpy(nm, "/dev/dsk/"); (void) strcat(nm, dep->d_name); cd[i].name = nm; cd[i].id = cd[j].id; cd[i].device = ""; cd[i].number = id; i++; } (void) closedir(dirp); /* * scan /dev/rdsk for cd devices */ if ((dirp = opendir("/dev/rdsk")) == NULL) { perror(gettext("open /dev/dsk failure")); exit(1); } while (dep = readdir(dirp)) { /* skip . .. etc... */ if (strncmp(dep->d_name, ".", 1) == 0) continue; /* get device # (disk #) */ if (sscanf(dep->d_name, "c%dt%d", &ctrl, &id) != 2) continue; /* see if this is one of the cd special devices */ for (j = 0; j < cd_count; j++) { if (cd[j].number == id && cd[j].controller == ctrl) goto found1; } continue; /* add new entry to table (/dev/rdsk + / + d_name + \0) */ found1: /* if array full, then expand it */ if (i == ncd) { /* will exit(1) if insufficient memory */ ncd = expandmem(i, (void **)&cd, sizeof (struct cd)); } nm = (char *)malloc(SIZE_OF_RDSK + 1 + strlen(dep->d_name) + 1); if (nm == NULL) no_memory(); (void) strcpy(nm, "/dev/rdsk/"); (void) strcat(nm, dep->d_name); cd[i].name = nm; cd[i].id = cd[j].id; cd[i].device = ""; cd[i].number = id; cd[i].controller = ctrl; i++; } (void) closedir(dirp); cd_count = i; if (system_labeled) { dname = DA_CD_NAME; dclean = DA_DEFAULT_DISK_CLEAN; } else { dname = "sr"; dclean = CD_CLEAN; } for (i = 0; i < 8; i++) { for (j = 0; j < cd_count; j++) { if (cd[j].id != i) continue; if (do_files) { (void) da_add_list(&devlist, cd[j].name, i, DA_CD); } else if (do_devalloc) { /* print device_allocate for cd devices */ if (system_labeled) { (void) printf("%s%d%s\\\n", dname, i, KV_DELIMITER); (void) printf("\t%s%s\\\n", DA_CD_TYPE, KV_DELIMITER); (void) printf("\t%s%s\\\n", DA_RESERVED, KV_DELIMITER); (void) printf("\t%s%s\\\n", DA_RESERVED, KV_DELIMITER); (void) printf("\t%s%s\\\n", DEFAULT_DEV_ALLOC_AUTH, KV_DELIMITER); (void) printf("\t%s\n\n", dclean); } else { (void) printf( "sr%d;sr;reserved;reserved;%s;", i, DEFAULT_DEV_ALLOC_AUTH); (void) printf("%s%s\n", SECLIB, "/sr_clean"); } break; } else if (do_devmaps) { /* print device_maps for cd devices */ if (first) { (void) printf(" "); } else { if (system_labeled) { (void) printf("%s%d%s\\\n", dname, i, KV_TOKEN_DELIMIT); (void) printf("\t%s%s\\\n", DA_CD_TYPE, KV_TOKEN_DELIMIT); (void) printf("\t"); } else { (void) printf("sr%d:\\\n", i); (void) printf("\tsr:\\\n"); (void) printf("\t"); } first++; } (void) printf("%s", cd[j].name); } } if (do_devmaps && first) { (void) printf("\n\n"); first = 0; } } if (do_files && cd_count) { dargs.rootdir = NULL; dargs.devnames = NULL; dargs.optflag = DA_ADD; for (entry = devlist.cd; entry != NULL; entry = entry->next) { dargs.devinfo = &(entry->devinfo); (void) da_update_device(&dargs); } } return (cd_count); } static void dormdisk(int cd_count) { DIR *dirp; struct dirent *dep; /* directory entry pointer */ int i, j; char *nm; /* name/device of special device */ int id; /* disk id */ int ctrl; /* disk controller */ int nrmdisk; /* max array size */ int fd = -1; int rmdisk_count; int first = 0; int is_cd; int checked; int removable; char path[MAXPATHLEN]; da_args dargs; deventry_t *entry; nrmdisk = DFLT_RMDISK; i = rmdisk_count = 0; /* * scan /dev/dsk for rmdisk devices */ if ((dirp = opendir("/dev/dsk")) == NULL) { perror("gettext(open /dev/dsk failure)"); exit(1); } while (dep = readdir(dirp)) { is_cd = 0; checked = 0; removable = 0; /* skip . .. etc... */ if (strncmp(dep->d_name, ".", 1) == 0) continue; /* get device # (disk #) */ if (sscanf(dep->d_name, "c%dt%d", &ctrl, &id) != 2) continue; /* see if we've already examined this device */ for (j = 0; j < i; j++) { if (id == rmdisk[j].id && ctrl == rmdisk[j].controller && (strcmp(dep->d_name, rmdisk[j].name) == 0)) { checked = 1; break; } if (id == rmdisk[j].id && ctrl != rmdisk[j].controller) /* * c2t0d0s0 is a different rmdisk than c3t0d0s0. */ id = rmdisk[j].id + 1; } if (checked) continue; /* ignore if this is a cd */ for (j = 0; j < cd_count; j++) { if (id == cd[j].id && ctrl == cd[j].controller) { is_cd = 1; break; } } if (is_cd) continue; /* see if device is removable */ (void) snprintf(path, sizeof (path), "%s%s", "/dev/rdsk/", dep->d_name); if ((fd = open(path, O_RDONLY | O_NONBLOCK)) < 0) continue; (void) ioctl(fd, DKIOCREMOVABLE, &removable); (void) close(fd); if (removable == 0) continue; /* * add new entry to table (/dev/dsk + / + d_name + \0) * if array full, then expand it */ if (i == nrmdisk) { /* will exit(1) if insufficient memory */ nrmdisk = expandmem(i, (void **)&rmdisk, sizeof (struct rmdisk)); /* When we expand rmdisk, need to expand rmdisk_r */ (void) expandmem(i, (void **)&rmdisk_r, sizeof (struct rmdisk)); } nm = (char *)malloc(SIZE_OF_DSK + 1 + strlen(dep->d_name) + 1); if (nm == NULL) no_memory(); (void) strcpy(nm, "/dev/dsk/"); (void) strcat(nm, dep->d_name); rmdisk[i].name = nm; rmdisk[i].id = id; rmdisk[i].controller = ctrl; rmdisk[i].device = ""; rmdisk[i].number = id; rmdisk_r[i].name = strdup(path); i++; } rmdisk_count = i; (void) closedir(dirp); for (i = 0, j = rmdisk_count; i < rmdisk_count; i++, j++) { if (j == nrmdisk) { /* will exit(1) if insufficient memory */ nrmdisk = expandmem(j, (void **)&rmdisk, sizeof (struct rmdisk)); } rmdisk[j].name = rmdisk_r[i].name; rmdisk[j].id = rmdisk[i].id; rmdisk[j].controller = rmdisk[i].controller; rmdisk[j].device = rmdisk[i].device; rmdisk[j].number = rmdisk[i].number; } rmdisk_count = j; for (i = 0; i < 8; i++) { for (j = 0; j < rmdisk_count; j++) { if (rmdisk[j].id != i) continue; if (do_files) { (void) da_add_list(&devlist, rmdisk[j].name, i, DA_RMDISK); } else if (do_devalloc) { /* print device_allocate for rmdisk devices */ (void) printf("%s%d%s\\\n", DA_RMDISK_NAME, i, KV_DELIMITER); (void) printf("\t%s%s\\\n", DA_RMDISK_TYPE, KV_DELIMITER); (void) printf("\t%s%s\\\n", DA_RESERVED, KV_DELIMITER); (void) printf("\t%s%s\\\n", DA_RESERVED, KV_DELIMITER); (void) printf("\t%s%s\\\n", DEFAULT_DEV_ALLOC_AUTH, KV_DELIMITER); (void) printf("\t%s\n", DA_DEFAULT_DISK_CLEAN); break; } else if (do_devmaps) { /* print device_maps for rmdisk devices */ if (first) { (void) printf(" "); } else { (void) printf("%s%d%s\\\n", DA_RMDISK_NAME, i, KV_TOKEN_DELIMIT); (void) printf("\t%s%s\\\n", DA_RMDISK_TYPE, KV_TOKEN_DELIMIT); (void) printf("\t"); first++; } (void) printf("%s", rmdisk[j].name); } } if (do_devmaps && first) { (void) printf("\n\n"); first = 0; } } if (do_files && rmdisk_count) { dargs.rootdir = NULL; dargs.devnames = NULL; dargs.optflag = DA_ADD; for (entry = devlist.rmdisk; entry != NULL; entry = entry->next) { dargs.devinfo = &(entry->devinfo); (void) da_update_device(&dargs); } } } /* set default array sizes */ static void initmem() { tape = (struct tape *)calloc(DFLT_NTAPE, sizeof (struct tape)); audio = (struct audio *)calloc(DFLT_NAUDIO, sizeof (struct audio)); cd = (struct cd *)calloc(DFLT_NCD, sizeof (struct cd)); fp = (struct fp *)calloc(DFLT_NFP, sizeof (struct fp)); if (system_labeled) { rmdisk = (struct rmdisk *)calloc(DFLT_RMDISK, sizeof (struct rmdisk)); if (rmdisk == NULL) no_memory(); rmdisk_r = (struct rmdisk *)calloc(DFLT_RMDISK, sizeof (struct rmdisk)); if (rmdisk_r == NULL) no_memory(); } if (tape == NULL || audio == NULL || cd == NULL || fp == NULL) no_memory(); devlist.audio = devlist.cd = devlist.floppy = devlist.rmdisk = devlist.tape = NULL; } /* note n will be # elments in array (and could be 0) */ static int expandmem(int n, void **array, int size) { void *old = *array; void *new; /* get new array space (n + DELTA) */ new = (void *)calloc(n + DELTA, size); if (new == NULL) { perror("memory allocation failed"); exit(1); } /* copy old array into new space */ bcopy(old, new, n * size); /* now release old arrary */ free(old); *array = new; return (n + DELTA); } static void no_memory(void) { (void) fprintf(stderr, "%s: %s\n", "mkdevalloc", gettext("out of memory")); exit(1); /* NOT REACHED */ } #! /bin/sh # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (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 (c) 1992-1993, 1997-2001 by Sun Microsystems, Inc. # All rights reserved. # #ident "%Z%%M% %I% %E% SMI" # # This a clean script for the CD_ROM # PROG=`basename $0` PATH="/usr/sbin:/usr/bin" TEXTDOMAIN="SUNW_OST_OSCMD" export TEXTDOMAIN USAGE=`gettext "%s [-I|-s|-f|-i] device"` # # *** Shell Function Definitions *** # con_msg() { form=`gettext "%s: Media in %s is ready. Please, label and store safely."` if [ "$silent" != "y" ] ; then printf "${form}\n" $PROG $DEVICE > /dev/console fi } e_con_msg() { form=`gettext "%s: Error cleaning up device %s."` if [ "$silent" != "y" ] ; then printf "${form}\n" `basename $0` $DEVICE > /dev/console fi } user_msg() { form=`gettext "%s: Media in %s is ready. Please, label and store safely."` if [ "$silent" != "y" ] ; then printf "${form}\n" $PROG $DEVICE > /dev/tty fi } e_user_msg() { form=`gettext "%s: Error cleaning up device %s."` if [ "$silent" != "y" ] ; then printf "${form}\n" $PROG $DEVICE > /dev/tty gettext "Please inform system administrator.\n" > /dev/tty fi } mk_error() { chown bin /etc/security/dev/$1 chmod 0100 /etc/security/dev/$1 } # # *** Begin Main Program *** # silent=n while getopts Iifs c do case $c in I) FLAG=i silent=y;; i) FLAG=$c;; f) FLAG=$c;; s) FLAG=$c;; \?) printf "${USAGE}\n" $PROG >/dev/tty exit 1 ;; esac done shift `expr $OPTIND - 1` # get the map information FLOPPY=$1 MAP=`dminfo -v -n $FLOPPY` DEVICE=`echo $MAP | cut -f1 -d:` TYPE=`echo $MAP | cut -f2 -d:` FILES=`echo $MAP | cut -f3 -d:` DEVFILE=`echo $FILES | cut -f1 -d" "` #if init then do once and exit lform=`gettext "%s error: %s."` if [ "$FLAG" = "i" ] ; then x="`eject -q $DEVFILE 2>&1`" # Determine if there is media in drive z="$?" case $z in 0) # Media is in the drive. a="`eject -f $DEVFILE 2>&1`" b="$?" case $b in 0) # Media has been ejected con_msg exit 0;; 1) # Media not ejected mk_error $DEVICE if [ "$silent" != "y" ] ; then printf "${lform}\n" $PROG $a >/dev/tty fi e_con_msg exit 1;; 2) # Error mk_error $DEVICE if [ "$silent" != "y" ] ; then printf "${lform}\n" $PROG $a >/dev/tty fi e_con_msg exit 1;; 3) # Error - Perhaps drive doesn't support ejection mk_error $DEVICE if [ "$silent" != "y" ] ; then printf "${lform}\n" $PROG $a >/dev/tty fi e_con_msg exit 1;; esac;; 1) # No media in drive con_msg exit 0;; 2) # Error mk_error $DEVICE if [ "$silent" != "y" ] ; then printf "${lform}\n" $PROG $x >/dev/tty fi e_con_msg exit 1;; 3) # Error mk_error $DEVICE if [ "$silent" != "y" ] ; then printf "${lform}\n" $PROG $x >/dev/tty fi e_con_msg exit 1;; esac else # interactive clean up x="`eject -q $DEVFILE 2>&1`" # Determine if there is media in drive z="$?" case $z in 0) # Media is in the drive. a="`eject -f $DEVFILE 2>&1`" b="$?" case $b in 0) # Media has been ejected user_msg exit 0;; 1) # Media not ejected mk_error $DEVICE if [ "$silent" != "y" ] ; then printf "${lform}\n" $PROG $a >/dev/tty fi e_user_msg exit 1;; 2) # Other Error mk_error $DEVICE if [ "$silent" != "y" ] ; then printf "${lform}\n" $PROG $a >/dev/tty fi e_user_msg exit 1;; 3) if echo $a | grep "failed" >/dev/null ; then while true # Drive doesn't support eject, so loop do c="`eject -q $DEVFILE 2>&1`" # Is caddy in drive? d="$?" if [ $d -eq 0 ] ; then # Yes, Caddy in drive form=`gettext "Please remove the caddy from %s."` if [ "$silent" != "y" ] ; then printf "${form}\n" $DEVICE >/dev/tty /usr/5bin/echo \\007 >/dev/tty fi sleep 3 elif echo $c | grep "NOT" > /dev/null ; then # No,Caddy NOT in drive user_msg exit 0 else # Error occurred mk_error $DEVICE if [ "$silent" != "y" ] ; then printf "${lform}\n" $PROG $a >/dev/tty fi e_user_msg exit 1 fi done else # Some other failure if [ "$silent" != "y" ] ; then printf "${lform}\n" $PROG $a >/dev/tty fi e_user_msg mk_error $DEVICE exit 1 fi;; esac;; 1) # No media in the drive user_msg exit 0;; 2) mk_error $DEVICE if [ "$silent" != "y" ] ; then printf "${lform}\n" $PROG $x >/dev/tty fi e_user_msg exit 1;; 3) mk_error $DEVICE if [ "$silent" != "y" ] ; then printf "${lform}\n" $PROG $x >/dev/tty fi e_user_msg exit 1;; esac fi exit 2 #! /bin/sh # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (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 (c) 1992-1993, 1997-2001 by Sun Microsystems, Inc. # All rights reserved. # #ident "%Z%%M% %I% %E% SMI" # # This a clean script for all tape drives # PROG=`basename $0` PATH="/usr/sbin:/usr/bin" TEXTDOMAIN="SUNW_OST_OSCMD" export TEXTDOMAIN USAGE=`gettext "%s [-I|-s|-f|-i] device"` # # *** Shell Function Declarations *** # con_msg() { form=`gettext "%s: Media in %s is ready. Please, label and store safely."` if [ "$silent" != "y" ] ; then printf "${form}\n" $PROG $DEVICE > /dev/console fi } e_con_msg() { form=`gettext "%s: Error cleaning up device %s."` if [ "$silent" != "y" ] ; then printf "${form}\n" $PROG $DEVICE > /dev/console fi } user_msg() { form=`gettext "%s: Media in %s is ready. Please, label and store safely."` if [ "$silent" != "y" ] ; then printf "${form}\n" $PROG $DEVICE > /dev/tty fi } e_user_msg() { form=`gettext "%s: Error cleaning up device %s."` if [ "$silent" != "y" ] ; then printf "${form}" $PROG $DEVICE > /dev/tty gettext "Please inform system administrator.\n" > /dev/tty fi } mk_error() { chown bin /etc/security/dev/$1 chmod 0100 /etc/security/dev/$1 } silent=n while getopts Iifs c do case $c in I) FLAG=i silent=y;; i) FLAG=$c;; f) FLAG=$c;; s) FLAG=$c;; \?) printf "${USAGE}\n" $PROG >/dev/tty exit 1 ;; esac done shift `expr $OPTIND - 1` # get the map information TAPE=$1 MAP=`dminfo -v -n $TAPE` DEVICE=`echo $MAP | cut -f1 -d:` TYPE=`echo $MAP | cut -f2 -d:` FILES=`echo $MAP | cut -f3 -d:` DEVFILE=`echo $FILES | cut -f1 -d" "` #if init then do once and exit if [ "$FLAG" = "i" ] ; then x="`mt -f $DEVFILE rewoffl 2>&1`" z="$?" case $z in 0) # if this is a open reel tape than we a sucessful # else must be a cartrige tape we failed if mt -f $DEVFILE status 2>&1 | grep "no tape loaded" >/dev/null ; then con_msg exit 0 else e_con_msg mk_error $DEVICE exit 1 fi;; 1) # only one error mesage is satisfactory if echo $x | grep "no tape loaded" >/dev/null ; then con_msg exit 0 else e_con_msg mk_error $DEVICE exit 1 fi;; 2) # clean up failed exit with error e_con_msg mk_error $DEVICE exit 1;; esac else # interactive clean up x="`mt -f $DEVFILE rewoffl 2>&1`" z="$?" case $z in 0) # if this is a open reel tape than we a sucessful # else must be a cartrige tape we must retry until user removes tape if mt -f $DEVFILE status 2>&1 | grep "no tape loaded" > /dev/null ; then user_msg exit 0 else while true do if mt -f $DEVFILE status 2>&1 | grep "no tape loaded" > /dev/null ; then user_msg exit 0 else form=`gettext "Please remove the tape from the %s."` if [ "$silent" != "y" ] ; then printf "${form}\n" $DEVICE >/dev/tty /usr/5bin/echo \\007 >/dev/tty fi sleep 3 fi done fi;; 1) # only one error mesage is satisfactory if echo $x | grep "no tape loaded" > /dev/null ; then user_msg exit 0 else e_user_msg mk_error $DEVICE exit 1 fi;; 2) # clean up failed exit with error e_user_msg mk_error $DEVICE exit 1;; esac fi exit 2 #! /bin/sh # # # 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 (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved. # . /lib/svc/share/smf_include.sh DEVALLOC=/etc/security/device_allocate DEVMAPS=/etc/security/device_maps DEVFSADM=/sbin/devfsadm MKDEVALLOC=/usr/sbin/mkdevalloc MKDEVMAPS=/usr/sbin/mkdevmaps HALFDI=/etc/hal/fdi/policy/30user/90-solaris-device-allocation.fdi # dev_allocation_convert # All the real work gets done in this function dev_allocation_convert() { # # If allocation already configured, just return # if [ -f ${HALFDI} -a -f ${DEVALLOC} -a -f ${DEVMAPS} ]; then return fi # Prevent automount of removable and hotpluggable volume # by forcing volume.ignore HAL property on all such volumes. if [ ! -f ${HALFDI} ]; then cat > ${HALFDI} < true true FDI fi # Initialize device allocation # Need to determine if Trusted Extensions is enabled. # Check the setting in etc/system (other methods won't work # because TX is likely not yet fully active.) # grep "^[ ]*set[ ][ ]*sys_labeling[ ]*=[ ]*1" \ /etc/system > /dev/null 2>&1 if [ $? = 0 ]; then # Trusted Extensions is enabled (but possibly not yet booted). ${DEVFSADM} -e else if [ ! -f ${DEVALLOC} ]; then echo "DEVICE_ALLOCATION=ON" > $DEVALLOC ${MKDEVALLOC} >> $DEVALLOC fi if [ ! -f ${DEVMAPS} ]; then ${MKDEVMAPS} > $DEVMAPS fi fi } dev_allocation_unconvert() { # Turn off device allocation. ${DEVFSADM} -d /bin/rm -f $DEVALLOC $DEVMAPS # Restore default policy for removable and hotpluggable volumes /bin/rm -f $HALFDI } case "$1" in 'start') dev_allocation_convert deallocate -Is ;; 'stop') state=`/usr/bin/svcprop -c -p general/enabled $SMF_FMRI 2>/dev/null` if [ "$state" = "true" ] ; then exit $SMF_EXIT_OK fi dev_allocation_unconvert ;; esac exit $SMF_EXIT_OK #! /bin/ksh # # 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. # ################## Check parameters ################################# if [ $# -lt 3 -o $# -gt 4 ]; then echo "Usage: `basename $0` TITLE OKBUTTONTEXT [CANCELBUTTONTEXT]" exit 127 fi ################## Create the Main UI ################################# messageString="$1" dialogTitle="$2" if [ $# -eq 4 -a "$4" != "" ];then type="--question" else type="--info" fi reply=$(/usr/bin/zenity $type \ --title="$dialogTitle" \ --height=100 \ --width=200 \ --text="$messageString") exit $reply #! /bin/ksh # # 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. # # Script to wrap a non-windowing clean script to provide a prompt # before the dtterm window closes, and to catch abnormal terminations. # For any abnormal termination of the clean script, kill our parent # process so that our grandparent will know that the script did not # terminate normally. (We expect our parent to be dtterm, and our # grandparent to be allocate.) # Trap any signal that would cause abnormal termination of the script, # This catches use of ^C, ^Z, etc., and it also catches the HUP signal # when the dtterm window is closed before the script is finished. PARENT_KILLED=no killparent() { if [ $PARENT_KILLED = "no" ]; then PARENT_KILLED=yes kill -9 $PPID fi } trap "killparent" HUP INT TERM QUIT TSTP ABRT SCRIPT=$1 shift if [ ! -e $SCRIPT ]; then echo **** Clean script $SCRIPT not found **** echo "**** Press RETURN to close window ****" read kill -9 $PPID fi echo "**** Device cleanup for $2 ****\n" $SCRIPT "$@" STAT=$? echo "\n**** Press RETURN to close window ****" read # If the script returned a non-zero exit status, kill our dtterm # parent process. if [ $STAT != 0 ]; then killparent fi