/* * 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); }