diff --git a/bin/chio/chio.c b/bin/chio/chio.c index 13392ee2de00..ddf996caee02 100644 --- a/bin/chio/chio.c +++ b/bin/chio/chio.c @@ -1,1220 +1,1176 @@ /* $NetBSD: chio.c,v 1.6 1998/01/04 23:53:58 thorpej Exp $ */ /* * Copyright (c) 1996 Jason R. Thorpe * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgements: * This product includes software developed by Jason R. Thorpe * for And Communications, http://www.and.com/ * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Additional Copyright (c) 1997, by Matthew Jacob, for NASA/Ames Research Ctr. * Addidional Copyright (c) 2000, by C. Stephen Gunn, Waterspout Communications */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1996 Jason R. Thorpe. All rights reserved."; static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include "defs.h" #include "pathnames.h" extern char *__progname; /* from crt0.o */ -static void usage __P((void)); -static void cleanup __P((void)); -static int parse_element_type __P((char *)); -static int parse_element_unit __P((char *)); -static const char * element_type_name __P((int et)); -static int parse_special __P((char *)); -static int is_special __P((char *)); -static const char *bits_to_string __P((ces_status_flags, const char *)); - -static void find_element __P((char *, u_int16_t *, u_int16_t *)); +static void usage(void); +static void cleanup(void); +static int parse_element_type(char *); +static int parse_element_unit(char *); +static const char * element_type_name(int et); +static int parse_special(char *); +static int is_special(char *); +static const char *bits_to_string(ces_status_flags, const char *); + +static void find_element(char *, u_int16_t *, u_int16_t *); static struct changer_element_status *get_element_status - __P((unsigned int, unsigned int)); - -static int do_move __P((const char *, int, char **)); -static int do_exchange __P((const char *, int, char **)); -static int do_position __P((const char *, int, char **)); -static int do_params __P((const char *, int, char **)); -static int do_getpicker __P((const char *, int, char **)); -static int do_setpicker __P((const char *, int, char **)); -static int do_status __P((const char *, int, char **)); -static int do_ielem __P((const char *, int, char **)); -static int do_return __P((const char *, int, char **)); -static int do_voltag __P((const char *, int, char **)); + (unsigned int, unsigned int); + +static int do_move(const char *, int, char **); +static int do_exchange(const char *, int, char **); +static int do_position(const char *, int, char **); +static int do_params(const char *, int, char **); +static int do_getpicker(const char *, int, char **); +static int do_setpicker(const char *, int, char **); +static int do_status(const char *, int, char **); +static int do_ielem(const char *, int, char **); +static int do_return(const char *, int, char **); +static int do_voltag(const char *, int, char **); #ifndef CHET_VT #define CHET_VT 10 /* Completely Arbitrary */ #endif /* Valid changer element types. */ const struct element_type elements[] = { { "drive", CHET_DT }, { "picker", CHET_MT }, { "portal", CHET_IE }, { "slot", CHET_ST }, { "voltag", CHET_VT }, /* Select tapes by barcode */ { NULL, 0 }, }; /* Valid commands. */ const struct changer_command commands[] = { { "exchange", do_exchange }, { "getpicker", do_getpicker }, { "ielem", do_ielem }, { "move", do_move }, { "params", do_params }, { "position", do_position }, { "setpicker", do_setpicker }, { "status", do_status }, { "return", do_return }, { "voltag", do_voltag }, { NULL, 0 }, }; /* Valid special words. */ const struct special_word specials[] = { { "inv", SW_INVERT }, { "inv1", SW_INVERT1 }, { "inv2", SW_INVERT2 }, { NULL, 0 }, }; static int changer_fd; static const char *changer_name; int -main(argc, argv) - int argc; - char **argv; +main(int argc, char **argv) { int ch, i; while ((ch = getopt(argc, argv, "f:")) != -1) { switch (ch) { case 'f': changer_name = optarg; break; default: usage(); } } argc -= optind; argv += optind; if (argc == 0) usage(); /* Get the default changer if not already specified. */ if (changer_name == NULL) if ((changer_name = getenv(CHANGER_ENV_VAR)) == NULL) changer_name = _PATH_CH; /* Open the changer device. */ if ((changer_fd = open(changer_name, O_RDWR, 0600)) == -1) err(1, "%s: open", changer_name); /* Register cleanup function. */ if (atexit(cleanup)) err(1, "can't register cleanup function"); /* Find the specified command. */ for (i = 0; commands[i].cc_name != NULL; ++i) if (strcmp(*argv, commands[i].cc_name) == 0) break; if (commands[i].cc_name == NULL) { /* look for abbreviation */ for (i = 0; commands[i].cc_name != NULL; ++i) if (strncmp(*argv, commands[i].cc_name, strlen(*argv)) == 0) break; } if (commands[i].cc_name == NULL) errx(1, "unknown command: %s", *argv); exit ((*commands[i].cc_handler)(commands[i].cc_name, argc, argv)); /* NOTREACHED */ } static int -do_move(cname, argc, argv) - const char *cname; - int argc; - char **argv; +do_move(const char *cname, int argc, char **argv) { struct changer_move cmd; int val; /* * On a move command, we expect the following: * * [inv] * * where ET == element type and EU == element unit. */ ++argv; --argc; if (argc < 4) { warnx("%s: too few arguments", cname); goto usage; } else if (argc > 5) { warnx("%s: too many arguments", cname); goto usage; } (void) memset(&cmd, 0, sizeof(cmd)); /* */ cmd.cm_fromtype = parse_element_type(*argv); ++argv; --argc; /* Check for voltag virtual type */ if (CHET_VT == cmd.cm_fromtype) { find_element(*argv, &cmd.cm_fromtype, &cmd.cm_fromunit); } else { /* */ cmd.cm_fromunit = parse_element_unit(*argv); } ++argv; --argc; /* */ cmd.cm_totype = parse_element_type(*argv); ++argv; --argc; /* Check for voltag virtual type, and report error */ if (CHET_VT == cmd.cm_totype) errx(1,"%s: voltag only makes sense as an element source", cname); /* */ cmd.cm_tounit = parse_element_unit(*argv); ++argv; --argc; /* Deal with optional command modifier. */ if (argc) { val = parse_special(*argv); switch (val) { case SW_INVERT: cmd.cm_flags |= CM_INVERT; break; default: errx(1, "%s: inappropriate modifier `%s'", cname, *argv); /* NOTREACHED */ } } /* Send command to changer. */ if (ioctl(changer_fd, CHIOMOVE, &cmd)) err(1, "%s: CHIOMOVE", changer_name); return (0); usage: (void) fprintf(stderr, "usage: %s %s " " [inv]\n", __progname, cname); return (1); } static int -do_exchange(cname, argc, argv) - const char *cname; - int argc; - char **argv; +do_exchange(const char *cname, int argc, char **argv) { struct changer_exchange cmd; int val; /* * On an exchange command, we expect the following: * * [ ] [inv1] [inv2] * * where ET == element type and EU == element unit. */ ++argv; --argc; if (argc < 4) { warnx("%s: too few arguments", cname); goto usage; } else if (argc > 8) { warnx("%s: too many arguments", cname); goto usage; } (void) memset(&cmd, 0, sizeof(cmd)); /* */ cmd.ce_srctype = parse_element_type(*argv); ++argv; --argc; /* Check for voltag virtual type */ if (CHET_VT == cmd.ce_srctype) { find_element(*argv, &cmd.ce_srctype, &cmd.ce_srcunit); } else { /* */ cmd.ce_srcunit = parse_element_unit(*argv); } ++argv; --argc; /* */ cmd.ce_fdsttype = parse_element_type(*argv); ++argv; --argc; /* Check for voltag virtual type */ if (CHET_VT == cmd.ce_fdsttype) { find_element(*argv, &cmd.ce_fdsttype, &cmd.ce_fdstunit); } else { /* */ cmd.ce_fdstunit = parse_element_unit(*argv); } ++argv; --argc; /* * If the next token is a special word or there are no more * arguments, then this is a case of simple exchange. * dst2 == src. */ if ((argc == 0) || is_special(*argv)) { cmd.ce_sdsttype = cmd.ce_srctype; cmd.ce_sdstunit = cmd.ce_srcunit; goto do_special; } /* */ cmd.ce_sdsttype = parse_element_type(*argv); ++argv; --argc; if (CHET_VT == cmd.ce_sdsttype) errx(1,"%s %s: voltag only makes sense as an element source", cname, *argv); /* */ cmd.ce_sdstunit = parse_element_unit(*argv); ++argv; --argc; do_special: /* Deal with optional command modifiers. */ while (argc) { val = parse_special(*argv); ++argv; --argc; switch (val) { case SW_INVERT1: cmd.ce_flags |= CE_INVERT1; break; case SW_INVERT2: cmd.ce_flags |= CE_INVERT2; break; default: errx(1, "%s: inappropriate modifier `%s'", cname, *argv); /* NOTREACHED */ } } /* Send command to changer. */ if (ioctl(changer_fd, CHIOEXCHANGE, &cmd)) err(1, "%s: CHIOEXCHANGE", changer_name); return (0); usage: (void) fprintf(stderr, "usage: %s %s \n" " [ ] [inv1] [inv2]\n", __progname, cname); return (1); } static int -do_position(cname, argc, argv) - const char *cname; - int argc; - char **argv; +do_position(const char *cname, int argc, char **argv) { struct changer_position cmd; int val; /* * On a position command, we expect the following: * * [inv] * * where ET == element type and EU == element unit. */ ++argv; --argc; if (argc < 2) { warnx("%s: too few arguments", cname); goto usage; } else if (argc > 3) { warnx("%s: too many arguments", cname); goto usage; } (void) memset(&cmd, 0, sizeof(cmd)); /* */ cmd.cp_type = parse_element_type(*argv); ++argv; --argc; /* */ cmd.cp_unit = parse_element_unit(*argv); ++argv; --argc; /* Deal with optional command modifier. */ if (argc) { val = parse_special(*argv); switch (val) { case SW_INVERT: cmd.cp_flags |= CP_INVERT; break; default: errx(1, "%s: inappropriate modifier `%s'", cname, *argv); /* NOTREACHED */ } } /* Send command to changer. */ if (ioctl(changer_fd, CHIOPOSITION, &cmd)) err(1, "%s: CHIOPOSITION", changer_name); return (0); usage: (void) fprintf(stderr, "usage: %s %s [inv]\n", __progname, cname); return (1); } /* ARGSUSED */ static int -do_params(cname, argc, argv) - const char *cname; - int argc; - char **argv; +do_params(const char *cname, int argc, char **argv) { struct changer_params data; int picker; /* No arguments to this command. */ ++argv; --argc; if (argc) { warnx("%s: no arguments expected", cname); goto usage; } /* Get params from changer and display them. */ (void) memset(&data, 0, sizeof(data)); if (ioctl(changer_fd, CHIOGPARAMS, &data)) err(1, "%s: CHIOGPARAMS", changer_name); (void) printf("%s: %d slot%s, %d drive%s, %d picker%s", changer_name, data.cp_nslots, (data.cp_nslots > 1) ? "s" : "", data.cp_ndrives, (data.cp_ndrives > 1) ? "s" : "", data.cp_npickers, (data.cp_npickers > 1) ? "s" : ""); if (data.cp_nportals) (void) printf(", %d portal%s", data.cp_nportals, (data.cp_nportals > 1) ? "s" : ""); /* Get current picker from changer and display it. */ if (ioctl(changer_fd, CHIOGPICKER, &picker)) err(1, "%s: CHIOGPICKER", changer_name); (void) printf("\n%s: current picker: %d\n", changer_name, picker); return (0); usage: (void) fprintf(stderr, "usage: %s %s\n", __progname, cname); return (1); } /* ARGSUSED */ static int -do_getpicker(cname, argc, argv) - const char *cname; - int argc; - char **argv; +do_getpicker(const char *cname, int argc, char **argv) { int picker; /* No arguments to this command. */ ++argv; --argc; if (argc) { warnx("%s: no arguments expected", cname); goto usage; } /* Get current picker from changer and display it. */ if (ioctl(changer_fd, CHIOGPICKER, &picker)) err(1, "%s: CHIOGPICKER", changer_name); (void) printf("%s: current picker: %d\n", changer_name, picker); return (0); usage: (void) fprintf(stderr, "usage: %s %s\n", __progname, cname); return (1); } static int -do_setpicker(cname, argc, argv) - const char *cname; - int argc; - char **argv; +do_setpicker(const char *cname, int argc, char **argv) { int picker; ++argv; --argc; if (argc < 1) { warnx("%s: too few arguments", cname); goto usage; } else if (argc > 1) { warnx("%s: too many arguments", cname); goto usage; } picker = parse_element_unit(*argv); /* Set the changer picker. */ if (ioctl(changer_fd, CHIOSPICKER, &picker)) err(1, "%s: CHIOSPICKER", changer_name); return (0); usage: (void) fprintf(stderr, "usage: %s %s \n", __progname, cname); return (1); } static int -do_status(cname, argc, argv) - const char *cname; - int argc; - char **argv; +do_status(const char *cname, int argc, char **argv) { struct changer_params cp; struct changer_element_status_request cesr; int i, count, base, chet, schet, echet; const char *description; int pvoltag = 0; int avoltag = 0; int sense = 0; int scsi = 0; int source = 0; int intaddr = 0; int c; count = 0; base = 0; description = NULL; optind = optreset = 1; while ((c = getopt(argc, argv, "vVsSbaI")) != -1) { switch (c) { case 'v': pvoltag = 1; break; case 'V': avoltag = 1; break; case 's': sense = 1; break; case 'S': source = 1; break; case 'b': scsi = 1; break; case 'I': intaddr = 1; break; case 'a': pvoltag = avoltag = source = sense = scsi = intaddr = 1; break; default: warnx("%s: bad option", cname); goto usage; } } argc -= optind; argv += optind; /* * On a status command, we expect the following: * * [ [ [] ] ] * * where ET == element type, start == first element to report, * end == number of elements to report * * If we get no arguments, we get the status of all * known element types. */ if (argc > 3) { warnx("%s: too many arguments", cname); goto usage; } /* * Get params from changer. Specifically, we need the element * counts. */ if (ioctl(changer_fd, CHIOGPARAMS, (char *)&cp)) err(1, "%s: CHIOGPARAMS", changer_name); if (argc > 0) schet = echet = parse_element_type(argv[0]); else { schet = CHET_MT; echet = CHET_DT; } if (argc > 1) { base = atol(argv[1]); count = 1; } if (argc > 2) count = atol(argv[2]) - base + 1; if (base < 0 || count < 0) errx(1, "bad arguments"); for (chet = schet; chet <= echet; ++chet) { switch (chet) { case CHET_MT: if (count == 0) count = cp.cp_npickers; else if (count > cp.cp_npickers) errx(1, "not that many pickers in device"); description = "picker"; break; case CHET_ST: if (count == 0) count = cp.cp_nslots; else if (count > cp.cp_nslots) errx(1, "not that many slots in device"); description = "slot"; break; case CHET_IE: if (count == 0) count = cp.cp_nportals; else if (count > cp.cp_nportals) errx(1, "not that many portals in device"); description = "portal"; break; case CHET_DT: if (count == 0) count = cp.cp_ndrives; else if (count > cp.cp_ndrives) errx(1, "not that many drives in device"); description = "drive"; break; default: /* To appease gcc -Wuninitialized. */ count = 0; description = NULL; } if (count == 0) { if (argc == 0) continue; else { printf("%s: no %s elements\n", changer_name, description); return (0); } } bzero(&cesr, sizeof(cesr)); cesr.cesr_element_type = chet; cesr.cesr_element_base = base; cesr.cesr_element_count = count; /* Allocate storage for the status structures. */ cesr.cesr_element_status = (struct changer_element_status *) calloc((size_t)count, sizeof(struct changer_element_status)); if (!cesr.cesr_element_status) errx(1, "can't allocate status storage"); if (avoltag || pvoltag) cesr.cesr_flags |= CESR_VOLTAGS; if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr)) { free(cesr.cesr_element_status); err(1, "%s: CHIOGSTATUS", changer_name); } /* Dump the status for each reported element. */ for (i = 0; i < count; ++i) { struct changer_element_status *ces = &(cesr.cesr_element_status[i]); printf("%s %d: %s", description, ces->ces_addr, bits_to_string(ces->ces_flags, CESTATUS_BITS)); if (sense) printf(" sense: <0x%02x/0x%02x>", ces->ces_sensecode, ces->ces_sensequal); if (pvoltag) printf(" voltag: <%s:%d>", ces->ces_pvoltag.cv_volid, ces->ces_pvoltag.cv_serial); if (avoltag) printf(" avoltag: <%s:%d>", ces->ces_avoltag.cv_volid, ces->ces_avoltag.cv_serial); if (source) { if (ces->ces_flags & CES_SOURCE_VALID) printf(" source: <%s %d>", element_type_name( ces->ces_source_type), ces->ces_source_addr); else printf(" source: <>"); } if (intaddr) printf(" intaddr: <%d>", ces->ces_int_addr); if (scsi) { printf(" scsi: <"); if (ces->ces_flags & CES_SCSIID_VALID) printf("%d", ces->ces_scsi_id); else putchar('?'); putchar(':'); if (ces->ces_flags & CES_LUN_VALID) printf("%d", ces->ces_scsi_lun); else putchar('?'); putchar('>'); } putchar('\n'); } free(cesr.cesr_element_status); count = 0; } return (0); usage: (void) fprintf(stderr, "usage: %s %s [-vVsSbaA] [ [ [] ] ]\n", __progname, cname); return (1); } static int -do_ielem(cname, argc, argv) - const char *cname; - int argc; - char **argv; +do_ielem(const char *cname, int argc, char **argv) { int timeout = 0; if (argc == 2) { timeout = atol(argv[1]); } else if (argc > 1) { warnx("%s: too many arguments", cname); goto usage; } if (ioctl(changer_fd, CHIOIELEM, &timeout)) err(1, "%s: CHIOIELEM", changer_name); return (0); usage: (void) fprintf(stderr, "usage: %s %s []\n", __progname, cname); return (1); } static int -do_voltag(cname, argc, argv) - const char *cname; - int argc; - char **argv; +do_voltag(const char *cname, int argc, char **argv) { int force = 0; int clear = 0; int alternate = 0; int c; struct changer_set_voltag_request csvr; bzero(&csvr, sizeof(csvr)); optind = optreset = 1; while ((c = getopt(argc, argv, "fca")) != -1) { switch (c) { case 'f': force = 1; break; case 'c': clear = 1; break; case 'a': alternate = 1; break; default: warnx("%s: bad option", cname); goto usage; } } argc -= optind; argv += optind; if (argc < 2) { warnx("%s: missing element specification", cname); goto usage; } csvr.csvr_type = parse_element_type(argv[0]); csvr.csvr_addr = atol(argv[1]); if (!clear) { if (argc < 3 || argc > 4) { warnx("%s: missing argument", cname); goto usage; } if (force) csvr.csvr_flags = CSVR_MODE_REPLACE; else csvr.csvr_flags = CSVR_MODE_SET; if (strlen(argv[2]) > sizeof(csvr.csvr_voltag.cv_volid)) { warnx("%s: volume label too long", cname); goto usage; } strlcpy((char *)csvr.csvr_voltag.cv_volid, argv[2], sizeof(csvr.csvr_voltag.cv_volid)); if (argc == 4) { csvr.csvr_voltag.cv_serial = atol(argv[3]); } } else { if (argc != 2) { warnx("%s: unexpected argument", cname); goto usage; } csvr.csvr_flags = CSVR_MODE_CLEAR; } if (alternate) { csvr.csvr_flags |= CSVR_ALTERNATE; } if (ioctl(changer_fd, CHIOSETVOLTAG, &csvr)) err(1, "%s: CHIOSETVOLTAG", changer_name); return 0; usage: (void) fprintf(stderr, "usage: %s %s [-fca] [ [] ]\n", __progname, cname); return 1; } static int -parse_element_type(cp) - char *cp; +parse_element_type(char *cp) { int i; for (i = 0; elements[i].et_name != NULL; ++i) if (strcmp(elements[i].et_name, cp) == 0) return (elements[i].et_type); errx(1, "invalid element type `%s'", cp); /* NOTREACHED */ } static const char * -element_type_name(et) - int et; +element_type_name(int et) { int i; for (i = 0; elements[i].et_name != NULL; i++) if (elements[i].et_type == et) return elements[i].et_name; return "unknown"; } static int -parse_element_unit(cp) - char *cp; +parse_element_unit(char *cp) { int i; char *p; i = (int)strtol(cp, &p, 10); if ((i < 0) || (*p != '\0')) errx(1, "invalid unit number `%s'", cp); return (i); } static int -parse_special(cp) - char *cp; +parse_special(char *cp) { int val; val = is_special(cp); if (val) return (val); errx(1, "invalid modifier `%s'", cp); /* NOTREACHED */ } static int -is_special(cp) - char *cp; +is_special(char *cp) { int i; for (i = 0; specials[i].sw_name != NULL; ++i) if (strcmp(specials[i].sw_name, cp) == 0) return (specials[i].sw_value); return (0); } static const char * -bits_to_string(v, cp) - ces_status_flags v; - const char *cp; +bits_to_string(ces_status_flags v, const char *cp) { const char *np; char f, sep, *bp; static char buf[128]; bp = buf; (void) memset(buf, 0, sizeof(buf)); for (sep = '<'; (f = *cp++) != 0; cp = np) { for (np = cp; *np >= ' ';) np++; if ((v & (1 << (f - 1))) == 0) continue; (void) snprintf(bp, sizeof(buf) - (bp - &buf[0]), "%c%.*s", sep, (int)(long)(np - cp), cp); bp += strlen(bp); sep = ','; } if (sep != '<') *bp = '>'; return (buf); } /* * do_return() * * Given an element reference, ask the changer/picker to move that * element back to its source slot. */ static int -do_return(cname, argc, argv) - const char *cname; - int argc; - char **argv; +do_return(const char *cname, int argc, char **argv) { struct changer_element_status *ces; struct changer_move cmd; u_int16_t type, element; ++argv; --argc; if (argc < 2) { warnx("%s: too few arguments", cname); goto usage; } else if (argc > 3) { warnx("%s: too many arguments", cname); goto usage; } type = parse_element_type(*argv); ++argv; --argc; /* Handle voltag virtual Changer Element Type */ if (CHET_VT == type) { find_element(*argv, &type, &element); } else { element = parse_element_unit(*argv); } ++argv; --argc; /* Get the status */ ces = get_element_status((unsigned int)type, (unsigned int)element); if (NULL == ces) errx(1, "%s: null element status pointer", cname); if (!(ces->ces_flags & CES_SOURCE_VALID)) errx(1, "%s: no source information", cname); (void) memset(&cmd, 0, sizeof(cmd)); cmd.cm_fromtype = type; cmd.cm_fromunit = element; cmd.cm_totype = ces->ces_source_type; cmd.cm_tounit = ces->ces_source_addr; if (ioctl(changer_fd, CHIOMOVE, &cmd) == -1) err(1, "%s: CHIOMOVE", changer_name); free(ces); return(0); usage: (void) fprintf(stderr, "usage: %s %s " " \n", __progname, cname); return(1); } /* * get_element_status() * * return a *cesr for the specified changer element. This * routing will malloc()/calloc() the memory. The caller * should free() it when done. */ static struct changer_element_status * -get_element_status(type, element) - unsigned int type; - unsigned int element; +get_element_status(unsigned int type, unsigned int element) { struct changer_element_status_request cesr; struct changer_element_status *ces; ces = (struct changer_element_status *) calloc((size_t)1, sizeof(struct changer_element_status)); if (NULL == ces) errx(1, "can't allocate status storage"); (void)memset(&cesr, 0, sizeof(cesr)); cesr.cesr_element_type = (u_int16_t)type; cesr.cesr_element_base = (u_int16_t)element; cesr.cesr_element_count = 1; /* Only this one element */ cesr.cesr_flags |= CESR_VOLTAGS; /* Grab voltags as well */ cesr.cesr_element_status = ces; if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { free(ces); err(1, "%s: CHIOGSTATUS", changer_name); /* NOTREACHED */ } return ces; } /* * find_element() * * Given a find the chager element and unit, or exit * with an error if it isn't found. We grab the changer status * and iterate until we find a match, or crap out. */ static void -find_element(voltag, et, eu) - char *voltag; - u_int16_t *et; - u_int16_t *eu; +find_element(char *voltag, u_int16_t *et, u_int16_t *eu) { struct changer_params cp; struct changer_element_status_request cesr; struct changer_element_status *ch_ces, *ces; int found = 0; size_t elem, total_elem; /* * Get the changer parameters, we're interested in the counts * for all types of elements to perform our search. */ if (ioctl(changer_fd, CHIOGPARAMS, (char *)&cp)) err(1, "%s: CHIOGPARAMS", changer_name); /* Allocate some memory for the results */ total_elem = (cp.cp_nslots + cp.cp_ndrives + cp.cp_npickers + cp.cp_nportals); ch_ces = (struct changer_element_status *) calloc(total_elem, sizeof(struct changer_element_status)); if (NULL == ch_ces) errx(1, "can't allocate status storage"); ces = ch_ces; /* Read in the changer slots */ if (cp.cp_nslots > 0) { cesr.cesr_element_type = CHET_ST; cesr.cesr_element_base = 0; cesr.cesr_element_count = cp.cp_nslots; cesr.cesr_flags |= CESR_VOLTAGS; cesr.cesr_element_status = ces; if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { free(ch_ces); err(1, "%s: CHIOGSTATUS", changer_name); } ces += cp.cp_nslots; } /* Read in the drive information */ if (cp.cp_ndrives > 0 ) { (void) memset(&cesr, 0, sizeof(cesr)); cesr.cesr_element_type = CHET_DT; cesr.cesr_element_base = 0; cesr.cesr_element_count = cp.cp_ndrives; cesr.cesr_flags |= CESR_VOLTAGS; cesr.cesr_element_status = ces; if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { free(ch_ces); err(1, "%s: CHIOGSTATUS", changer_name); } ces += cp.cp_ndrives; } /* Read in the portal information */ if (cp.cp_nportals > 0 ) { (void) memset(&cesr, 0, sizeof(cesr)); cesr.cesr_element_type = CHET_IE; cesr.cesr_element_base = 0; cesr.cesr_element_count = cp.cp_nportals; cesr.cesr_flags |= CESR_VOLTAGS; cesr.cesr_element_status = ces; if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { free(ch_ces); err(1, "%s: CHIOGSTATUS", changer_name); } ces += cp.cp_nportals; } /* Read in the picker information */ if (cp.cp_npickers > 0) { (void) memset(&cesr, 0, sizeof(cesr)); cesr.cesr_element_type = CHET_MT; cesr.cesr_element_base = 0; cesr.cesr_element_count = cp.cp_npickers; cesr.cesr_flags |= CESR_VOLTAGS; cesr.cesr_element_status = ces; if (ioctl(changer_fd, CHIOGSTATUS, (char *)&cesr) == -1) { free(ch_ces); err(1, "%s: CHIOGSTATUS", changer_name); } } /* * Now search the list the specified */ for (elem = 0; elem <= total_elem; ++elem) { ces = &ch_ces[elem]; /* Make sure we have a tape in this element */ if ((ces->ces_flags & (CES_STATUS_ACCESS|CES_STATUS_FULL)) != (CES_STATUS_ACCESS|CES_STATUS_FULL)) continue; /* Check to see if it is our target */ if (strcasecmp(voltag, (const char *)ces->ces_pvoltag.cv_volid) == 0) { *et = ces->ces_type; *eu = ces->ces_addr; ++found; break; } } if (!found) { errx(1, "%s: unable to locate voltag: %s", changer_name, voltag); } free(ch_ces); return; } static void -cleanup() +cleanup(void) { /* Simple enough... */ (void)close(changer_fd); } static void -usage() +usage(void) { - (void) fprintf(stderr, "usage: %s [-f changer] command [-] " + (void)fprintf(stderr, "usage: %s [-f changer] command [-] " "arg1 arg2 [arg3 [...]]\n", __progname); exit(1); } diff --git a/bin/chio/defs.h b/bin/chio/defs.h index 863e3dba7745..17d2abf33a28 100644 --- a/bin/chio/defs.h +++ b/bin/chio/defs.h @@ -1,57 +1,57 @@ /* $FreeBSD$ */ /* * Copyright (c) 1996 Jason R. Thorpe * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgements: * This product includes software developed by Jason R. Thorpe * for And Communications, http://www.and.com/ * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ struct element_type { const char *et_name; /* name; i.e. "picker, "slot", etc. */ int et_type; /* type number */ }; struct changer_command { const char *cc_name; /* command name */ /* command handler */ - int (*cc_handler) __P((const char *, int, char **)); + int (*cc_handler)(const char *, int, char **); }; struct special_word { const char *sw_name; /* special word */ int sw_value; /* token value */ }; /* sw_value */ #define SW_INVERT 1 /* set "invert media" flag */ #define SW_INVERT1 2 /* set "invert media 1" flag */ #define SW_INVERT2 3 /* set "invert media 2" flag */ /* Environment variable to check for default changer. */ #define CHANGER_ENV_VAR "CHANGER" diff --git a/bin/chmod/chmod.c b/bin/chmod/chmod.c index 83a31c7d92fc..295e21040610 100644 --- a/bin/chmod/chmod.c +++ b/bin/chmod/chmod.c @@ -1,230 +1,228 @@ /* * Copyright (c) 1989, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static char const copyright[] = "@(#) Copyright (c) 1989, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)chmod.c 8.8 (Berkeley) 4/1/94"; #endif static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include -int main __P((int, char *[])); -void usage __P((void)); +int main(int, char *[]); +void usage(void); int -main(argc, argv) - int argc; - char *argv[]; +main(int argc, char *argv[]) { FTS *ftsp; FTSENT *p; mode_t *set; long val; int oct, omode; int Hflag, Lflag, Pflag, Rflag, ch, fflag, fts_options, hflag, rval; int vflag; char *ep, *mode; int newmode; - int (*change_mode) __P((const char *, mode_t)); + int (*change_mode)(const char *, mode_t); set = NULL; omode = 0; Hflag = Lflag = Pflag = Rflag = fflag = hflag = vflag = 0; while ((ch = getopt(argc, argv, "HLPRXfghorstuvwx")) != -1) switch (ch) { case 'H': Hflag = 1; Lflag = Pflag = 0; break; case 'L': Lflag = 1; Hflag = Pflag = 0; break; case 'P': Pflag = 1; Hflag = Lflag = 0; break; case 'R': Rflag = 1; break; case 'f': fflag = 1; break; case 'h': /* * In System V (and probably POSIX.2) the -h option * causes chmod to change the mode of the symbolic * link. 4.4BSD's symbolic links didn't have modes, * so it was an undocumented noop. In FreeBSD 3.0, * lchmod(2) is introduced and this option does real * work. */ hflag = 1; break; /* * XXX * "-[rwx]" are valid mode commands. If they are the entire * argument, getopt has moved past them, so decrement optind. * Regardless, we're done argument processing. */ case 'g': case 'o': case 'r': case 's': case 't': case 'u': case 'w': case 'X': case 'x': if (argv[optind - 1][0] == '-' && argv[optind - 1][1] == ch && argv[optind - 1][2] == '\0') --optind; goto done; case 'v': vflag = 1; break; case '?': default: usage(); } done: argv += optind; argc -= optind; if (argc < 2) usage(); if (Rflag) { fts_options = FTS_PHYSICAL; if (hflag) errx(1, "the -R and -h options may not be specified together."); if (Hflag) fts_options |= FTS_COMFOLLOW; if (Lflag) { fts_options &= ~FTS_PHYSICAL; fts_options |= FTS_LOGICAL; } } else fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL; if (hflag) change_mode = lchmod; else change_mode = chmod; mode = *argv; if (*mode >= '0' && *mode <= '7') { errno = 0; val = strtol(mode, &ep, 8); if (val > INT_MAX || val < 0) errno = ERANGE; if (errno) err(1, "invalid file mode: %s", mode); if (*ep) errx(1, "invalid file mode: %s", mode); omode = val; oct = 1; } else { if ((set = setmode(mode)) == NULL) errx(1, "invalid file mode: %s", mode); oct = 0; } if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL) err(1, NULL); for (rval = 0; (p = fts_read(ftsp)) != NULL;) { switch (p->fts_info) { case FTS_D: /* Change it at FTS_DP. */ if (!Rflag) fts_set(ftsp, p, FTS_SKIP); continue; case FTS_DNR: /* Warn, chmod, continue. */ warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); rval = 1; break; case FTS_ERR: /* Warn, continue. */ case FTS_NS: warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); rval = 1; continue; case FTS_SL: /* Ignore. */ case FTS_SLNONE: /* * The only symlinks that end up here are ones that * don't point to anything and ones that we found * doing a physical walk. */ if (!hflag) continue; /* else */ /* FALLTHROUGH */ default: break; } newmode = oct ? omode : getmode(set, p->fts_statp->st_mode); if ((newmode & ALLPERMS) == (p->fts_statp->st_mode & ALLPERMS)) continue; if ((*change_mode)(p->fts_accpath, newmode) && !fflag) { warn("%s", p->fts_path); rval = 1; } else { if (vflag) (void)printf("%s\n", p->fts_accpath); } } if (errno) err(1, "fts_read"); free(set); exit(rval); } void -usage() +usage(void) { (void)fprintf(stderr, "usage: chmod [-fhv] [-R [-H | -L | -P]] mode file ...\n"); exit(1); } diff --git a/bin/cp/cp.c b/bin/cp/cp.c index 19faa2899613..0aede8bd8b69 100644 --- a/bin/cp/cp.c +++ b/bin/cp/cp.c @@ -1,479 +1,473 @@ /* * Copyright (c) 1988, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * David Hitz of Auspex Systems Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static char const copyright[] = "@(#) Copyright (c) 1988, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)cp.c 8.2 (Berkeley) 4/1/94"; #endif static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ /* * Cp copies source files to target files. * * The global PATH_T structure "to" always contains the path to the * current target file. Since fts(3) does not change directories, * this path can be either absolute or dot-relative. * * The basic algorithm is to initialize "to" and use fts(3) to traverse * the file hierarchy rooted in the argument list. A trivial case is the * case of 'cp file1 file2'. The more interesting case is the case of * 'cp file1 file2 ... fileN dir' where the hierarchy is traversed and the * path (relative to the root of the traversal) is appended to dir (stored * in "to") to form the final target path. */ #include #include #include #include #include #include #include #include #include #include #include "extern.h" #define STRIP_TRAILING_SLASH(p) { \ while ((p).p_end > (p).p_path + 1 && (p).p_end[-1] == '/') \ *--(p).p_end = 0; \ } PATH_T to = { to.p_path, "", "" }; int Rflag, iflag, pflag, rflag, fflag, vflag; enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE }; -int copy __P((char *[], enum op, int)); -int mastercmp __P((const FTSENT **, const FTSENT **)); +int copy(char *[], enum op, int); +int mastercmp(const FTSENT **, const FTSENT **); int -main(argc, argv) - int argc; - char *argv[]; +main(int argc, char *argv[]) { struct stat to_stat, tmp_stat; enum op type; int Hflag, Lflag, Pflag, ch, fts_options, r; char *target; Hflag = Lflag = Pflag = 0; while ((ch = getopt(argc, argv, "HLPRfiprv")) != -1) switch (ch) { case 'H': Hflag = 1; Lflag = Pflag = 0; break; case 'L': Lflag = 1; Hflag = Pflag = 0; break; case 'P': Pflag = 1; Hflag = Lflag = 0; break; case 'R': Rflag = 1; break; case 'f': fflag = 1; iflag = 0; break; case 'i': iflag = 1; fflag = 0; break; case 'p': pflag = 1; break; case 'r': rflag = 1; break; case 'v': vflag = 1; break; default: usage(); break; } argc -= optind; argv += optind; if (argc < 2) usage(); fts_options = FTS_NOCHDIR | FTS_PHYSICAL; if (rflag) { if (Rflag) errx(1, "the -R and -r options may not be specified together."); if (Hflag || Lflag || Pflag) errx(1, "the -H, -L, and -P options may not be specified with the -r option."); fts_options &= ~FTS_PHYSICAL; fts_options |= FTS_LOGICAL; } if (Rflag) { if (Hflag) fts_options |= FTS_COMFOLLOW; if (Lflag) { fts_options &= ~FTS_PHYSICAL; fts_options |= FTS_LOGICAL; } } else { fts_options &= ~FTS_PHYSICAL; fts_options |= FTS_LOGICAL; } /* Save the target base in "to". */ target = argv[--argc]; if (strlcpy(to.p_path, target, sizeof(to.p_path)) >= sizeof(to.p_path)) errx(1, "%s: name too long", target); to.p_end = to.p_path + strlen(to.p_path); if (to.p_path == to.p_end) { *to.p_end++ = '.'; *to.p_end = 0; } STRIP_TRAILING_SLASH(to); to.target_end = to.p_end; /* Set end of argument list for fts(3). */ argv[argc] = NULL; /* * Cp has two distinct cases: * * cp [-R] source target * cp [-R] source1 ... sourceN directory * * In both cases, source can be either a file or a directory. * * In (1), the target becomes a copy of the source. That is, if the * source is a file, the target will be a file, and likewise for * directories. * * In (2), the real target is not directory, but "directory/source". */ r = stat(to.p_path, &to_stat); if (r == -1 && errno != ENOENT) err(1, "%s", to.p_path); if (r == -1 || !S_ISDIR(to_stat.st_mode)) { /* * Case (1). Target is not a directory. */ if (argc > 1) { usage(); exit(1); } /* * Need to detect the case: * cp -R dir foo * Where dir is a directory and foo does not exist, where * we want pathname concatenations turned on but not for * the initial mkdir(). */ if (r == -1) { if (rflag || (Rflag && (Lflag || Hflag))) stat(*argv, &tmp_stat); else lstat(*argv, &tmp_stat); if (S_ISDIR(tmp_stat.st_mode) && (Rflag || rflag)) type = DIR_TO_DNE; else type = FILE_TO_FILE; } else type = FILE_TO_FILE; } else /* * Case (2). Target is a directory. */ type = FILE_TO_DIR; exit (copy(argv, type, fts_options)); } int -copy(argv, type, fts_options) - char *argv[]; - enum op type; - int fts_options; +copy(char *argv[], enum op type, int fts_options) { struct stat to_stat; FTS *ftsp; FTSENT *curr; int base = 0, dne, badcp, nlen, rval; char *p, *target_mid; mode_t mask, mode; /* * Keep an inverted copy of the umask, for use in correcting * permissions on created directories when not using -p. */ mask = ~umask(0777); umask(~mask); if ((ftsp = fts_open(argv, fts_options, mastercmp)) == NULL) err(1, NULL); for (badcp = rval = 0; (curr = fts_read(ftsp)) != NULL; badcp = 0) { switch (curr->fts_info) { case FTS_NS: case FTS_DNR: case FTS_ERR: warnx("%s: %s", curr->fts_path, strerror(curr->fts_errno)); badcp = rval = 1; continue; case FTS_DC: /* Warn, continue. */ warnx("%s: directory causes a cycle", curr->fts_path); badcp = rval = 1; continue; } /* * If we are in case (2) or (3) above, we need to append the * source name to the target name. */ if (type != FILE_TO_FILE) { /* * Need to remember the roots of traversals to create * correct pathnames. If there's a directory being * copied to a non-existent directory, e.g. * cp -R a/dir noexist * the resulting path name should be noexist/foo, not * noexist/dir/foo (where foo is a file in dir), which * is the case where the target exists. * * Also, check for "..". This is for correct path * concatenation for paths ending in "..", e.g. * cp -R .. /tmp * Paths ending in ".." are changed to ".". This is * tricky, but seems the easiest way to fix the problem. * * XXX * Since the first level MUST be FTS_ROOTLEVEL, base * is always initialized. */ if (curr->fts_level == FTS_ROOTLEVEL) { if (type != DIR_TO_DNE) { p = strrchr(curr->fts_path, '/'); base = (p == NULL) ? 0 : (int)(p - curr->fts_path + 1); if (!strcmp(&curr->fts_path[base], "..")) base += 1; } else base = curr->fts_pathlen; } p = &curr->fts_path[base]; nlen = curr->fts_pathlen - base; target_mid = to.target_end; if (*p != '/' && target_mid[-1] != '/') *target_mid++ = '/'; *target_mid = 0; if (target_mid - to.p_path + nlen >= PATH_MAX) { warnx("%s%s: name too long (not copied)", to.p_path, p); badcp = rval = 1; continue; } (void)strncat(target_mid, p, nlen); to.p_end = target_mid + nlen; *to.p_end = 0; STRIP_TRAILING_SLASH(to); } if (curr->fts_info == FTS_DP) { /* * We are nearly finished with this directory. If we * didn't actually copy it, or otherwise don't need to * change its attributes, then we are done. */ if (!curr->fts_number) continue; /* * If -p is in effect, set all the attributes. * Otherwise, set the correct permissions, limited * by the umask. Optimise by avoiding a chmod() * if possible (which is usually the case if we * made the directory). Note that mkdir() does not * honour setuid, setgid and sticky bits, but we * normally want to preserve them on directories. */ if (pflag) rval = setfile(curr->fts_statp, 0); else { mode = curr->fts_statp->st_mode; if ((mode & (S_ISUID | S_ISGID | S_ISTXT)) || ((mode | S_IRWXU) & mask) != (mode & mask)) if (chmod(to.p_path, mode & mask) != 0){ warn("chmod: %s", to.p_path); rval = 1; } } continue; } /* Not an error but need to remember it happened */ if (stat(to.p_path, &to_stat) == -1) dne = 1; else { if (to_stat.st_dev == curr->fts_statp->st_dev && to_stat.st_ino == curr->fts_statp->st_ino) { warnx("%s and %s are identical (not copied).", to.p_path, curr->fts_path); badcp = rval = 1; if (S_ISDIR(curr->fts_statp->st_mode)) (void)fts_set(ftsp, curr, FTS_SKIP); continue; } if (!S_ISDIR(curr->fts_statp->st_mode) && S_ISDIR(to_stat.st_mode)) { warnx("cannot overwrite directory %s with non-directory %s", to.p_path, curr->fts_path); badcp = rval = 1; continue; } dne = 0; } switch (curr->fts_statp->st_mode & S_IFMT) { case S_IFLNK: if (copy_link(curr, !dne)) badcp = rval = 1; break; case S_IFDIR: if (!Rflag && !rflag) { warnx("%s is a directory (not copied).", curr->fts_path); (void)fts_set(ftsp, curr, FTS_SKIP); badcp = rval = 1; break; } /* * If the directory doesn't exist, create the new * one with the from file mode plus owner RWX bits, * modified by the umask. Trade-off between being * able to write the directory (if from directory is * 555) and not causing a permissions race. If the * umask blocks owner writes, we fail.. */ if (dne) { if (mkdir(to.p_path, curr->fts_statp->st_mode | S_IRWXU) < 0) err(1, "%s", to.p_path); } else if (!S_ISDIR(to_stat.st_mode)) { errno = ENOTDIR; err(1, "%s", to.p_path); } /* * Arrange to correct directory attributes later * (in the post-order phase) if this is a new * directory, or if the -p flag is in effect. */ curr->fts_number = pflag || dne; break; case S_IFBLK: case S_IFCHR: if (Rflag) { if (copy_special(curr->fts_statp, !dne)) badcp = rval = 1; } else { if (copy_file(curr, dne)) badcp = rval = 1; } break; case S_IFIFO: if (Rflag) { if (copy_fifo(curr->fts_statp, !dne)) badcp = rval = 1; } else { if (copy_file(curr, dne)) badcp = rval = 1; } break; default: if (copy_file(curr, dne)) badcp = rval = 1; break; } if (vflag && !badcp) (void)printf("%s -> %s\n", curr->fts_path, to.p_path); } if (errno) err(1, "fts_read"); return (rval); } /* * mastercmp -- * The comparison function for the copy order. The order is to copy * non-directory files before directory files. The reason for this * is because files tend to be in the same cylinder group as their * parent directory, whereas directories tend not to be. Copying the * files first reduces seeking. */ int -mastercmp(a, b) - const FTSENT **a, **b; +mastercmp(const FTSENT **a, const FTSENT **b) { int a_info, b_info; a_info = (*a)->fts_info; if (a_info == FTS_ERR || a_info == FTS_NS || a_info == FTS_DNR) return (0); b_info = (*b)->fts_info; if (b_info == FTS_ERR || b_info == FTS_NS || b_info == FTS_DNR) return (0); if (a_info == FTS_D) return (-1); if (b_info == FTS_D) return (1); return (0); } diff --git a/bin/cp/extern.h b/bin/cp/extern.h index 4e5f07c8644a..5647b5fa13af 100644 --- a/bin/cp/extern.h +++ b/bin/cp/extern.h @@ -1,55 +1,55 @@ /*- * Copyright (c) 1991, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)extern.h 8.2 (Berkeley) 4/1/94 * $FreeBSD$ */ typedef struct { char *p_end; /* pointer to NULL at end of path */ char *target_end; /* pointer to end of target base */ char p_path[PATH_MAX]; /* pointer to the start of a path */ } PATH_T; extern PATH_T to; extern int iflag, pflag, fflag, vflag; #include __BEGIN_DECLS -int copy_fifo __P((struct stat *, int)); -int copy_file __P((FTSENT *, int)); -int copy_link __P((FTSENT *, int)); -int copy_special __P((struct stat *, int)); -int setfile __P((struct stat *, int)); -void usage __P((void)); +int copy_fifo(struct stat *, int); +int copy_file(FTSENT *, int); +int copy_link(FTSENT *, int); +int copy_special(struct stat *, int); +int setfile(struct stat *, int); +void usage(void); __END_DECLS diff --git a/bin/cp/utils.c b/bin/cp/utils.c index adc04a72770d..d6eb0b11f59e 100644 --- a/bin/cp/utils.c +++ b/bin/cp/utils.c @@ -1,318 +1,308 @@ /*- * Copyright (c) 1991, 1993, 1994 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint #if 0 static char sccsid[] = "@(#)utils.c 8.3 (Berkeley) 4/1/94"; #endif static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED #include #endif #include #include #include #include #include #include #include #include #include #include "extern.h" int -copy_file(entp, dne) - FTSENT *entp; - int dne; +copy_file(FTSENT *entp, int dne) { static char buf[MAXBSIZE]; struct stat *fs; int ch, checkch, from_fd, rcount, rval, to_fd, wcount, wresid; char *bufp; #ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED char *p; #endif if ((from_fd = open(entp->fts_path, O_RDONLY, 0)) == -1) { warn("%s", entp->fts_path); return (1); } fs = entp->fts_statp; /* * If the file exists and we're interactive, verify with the user. * If the file DNE, set the mode to be the from file, minus setuid * bits, modified by the umask; arguably wrong, but it makes copying * executables work right and it's been that way forever. (The * other choice is 666 or'ed with the execute bits on the from file * modified by the umask.) */ if (!dne) { #define YESNO "(y/n [n]) " if (iflag) { (void)fprintf(stderr, "overwrite %s? %s", to.p_path, YESNO); checkch = ch = getchar(); while (ch != '\n' && ch != EOF) ch = getchar(); if (checkch != 'y' && checkch != 'Y') { (void)close(from_fd); (void)fprintf(stderr, "not overwritten\n"); return (1); } } if (fflag) { /* remove existing destination file name, * create a new file */ (void)unlink(to.p_path); to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, fs->st_mode & ~(S_ISUID | S_ISGID)); } else /* overwrite existing destination file name */ to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0); } else to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT, fs->st_mode & ~(S_ISUID | S_ISGID)); if (to_fd == -1) { warn("%s", to.p_path); (void)close(from_fd); return (1);; } rval = 0; /* * Mmap and write if less than 8M (the limit is so we don't totally * trash memory on big files. This is really a minor hack, but it * wins some CPU back. */ #ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED if (S_ISREG(fs->st_mode) && fs->st_size <= 8 * 1048576) { if ((p = mmap(NULL, (size_t)fs->st_size, PROT_READ, MAP_SHARED, from_fd, (off_t)0)) == MAP_FAILED) { warn("%s", entp->fts_path); rval = 1; } else { for (bufp = p, wresid = fs->st_size; ; bufp += wcount, wresid -= wcount) { wcount = write(to_fd, bufp, wresid); if (wcount >= wresid || wcount <= 0) break; } if (wcount != wresid) { warn("%s", to.p_path); rval = 1; } /* Some systems don't unmap on close(2). */ if (munmap(p, fs->st_size) < 0) { warn("%s", entp->fts_path); rval = 1; } } } else #endif { while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) { for (bufp = buf, wresid = rcount; ; bufp += wcount, wresid -= wcount) { wcount = write(to_fd, bufp, wresid); if (wcount >= wresid || wcount <= 0) break; } if (wcount != wresid) { warn("%s", to.p_path); rval = 1; break; } } if (rcount < 0) { warn("%s", entp->fts_path); rval = 1; } } /* * Don't remove the target even after an error. The target might * not be a regular file, or its attributes might be important, * or its contents might be irreplaceable. It would only be safe * to remove it if we created it and its length is 0. */ if (pflag && setfile(fs, to_fd)) rval = 1; (void)close(from_fd); if (close(to_fd)) { warn("%s", to.p_path); rval = 1; } return (rval); } int -copy_link(p, exists) - FTSENT *p; - int exists; +copy_link(FTSENT *p, int exists) { int len; char link[PATH_MAX]; if ((len = readlink(p->fts_path, link, sizeof(link) - 1)) == -1) { warn("readlink: %s", p->fts_path); return (1); } link[len] = '\0'; if (exists && unlink(to.p_path)) { warn("unlink: %s", to.p_path); return (1); } if (symlink(link, to.p_path)) { warn("symlink: %s", link); return (1); } return (0); } int -copy_fifo(from_stat, exists) - struct stat *from_stat; - int exists; +copy_fifo(struct stat *from_stat, int exists) { if (exists && unlink(to.p_path)) { warn("unlink: %s", to.p_path); return (1); } if (mkfifo(to.p_path, from_stat->st_mode)) { warn("mkfifo: %s", to.p_path); return (1); } return (pflag ? setfile(from_stat, 0) : 0); } int -copy_special(from_stat, exists) - struct stat *from_stat; - int exists; +copy_special(struct stat *from_stat, int exists) { if (exists && unlink(to.p_path)) { warn("unlink: %s", to.p_path); return (1); } if (mknod(to.p_path, from_stat->st_mode, from_stat->st_rdev)) { warn("mknod: %s", to.p_path); return (1); } return (pflag ? setfile(from_stat, 0) : 0); } #define RETAINBITS \ (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) int -setfile(fs, fd) - register struct stat *fs; - int fd; +setfile(struct stat *fs, int fd) { static struct timeval tv[2]; struct stat ts; int rval; int gotstat; rval = 0; fs->st_mode &= S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO; TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec); TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec); if (utimes(to.p_path, tv)) { warn("utimes: %s", to.p_path); rval = 1; } if (fd ? fstat(fd, &ts) : stat(to.p_path, &ts)) gotstat = 0; else { gotstat = 1; ts.st_mode &= S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO; } /* * Changing the ownership probably won't succeed, unless we're root * or POSIX_CHOWN_RESTRICTED is not set. Set uid/gid before setting * the mode; current BSD behavior is to remove all setuid bits on * chown. If chown fails, lose setuid/setgid bits. */ if (!gotstat || fs->st_uid != ts.st_uid || fs->st_gid != ts.st_gid) if (fd ? fchown(fd, fs->st_uid, fs->st_gid) : chown(to.p_path, fs->st_uid, fs->st_gid)) { if (errno != EPERM) { warn("chown: %s", to.p_path); rval = 1; } fs->st_mode &= ~(S_ISUID | S_ISGID); } if (!gotstat || fs->st_mode != ts.st_mode) if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode)) { warn("chmod: %s", to.p_path); rval = 1; } if (!gotstat || fs->st_flags != ts.st_flags) if (fd ? fchflags(fd, fs->st_flags) : chflags(to.p_path, fs->st_flags)) { warn("chflags: %s", to.p_path); rval = 1; } return (rval); } void -usage() +usage(void) { (void)fprintf(stderr, "%s\n%s\n", "usage: cp [-R [-H | -L | -P]] [-f | -i] [-pv] src target", " cp [-R [-H | -L | -P]] [-f | -i] [-pv] src1 ... srcN directory"); exit(EX_USAGE); }