diff options
author | rgrimes <rgrimes@FreeBSD.org> | 1994-05-26 06:18:55 +0000 |
---|---|---|
committer | rgrimes <rgrimes@FreeBSD.org> | 1994-05-26 06:18:55 +0000 |
commit | e3cfc8ce61f788739c66445d903f8beacb40c93d (patch) | |
tree | ba7beef9ee9289c4383bad976f88710e44c98b4d /bin/pax/sel_subs.c | |
parent | 862fdf11a2ede45dec0da01ed575525d79468981 (diff) | |
download | FreeBSD-src-e3cfc8ce61f788739c66445d903f8beacb40c93d.zip FreeBSD-src-e3cfc8ce61f788739c66445d903f8beacb40c93d.tar.gz |
BSD 4.4 Lite bin Sources
Diffstat (limited to 'bin/pax/sel_subs.c')
-rw-r--r-- | bin/pax/sel_subs.c | 657 |
1 files changed, 657 insertions, 0 deletions
diff --git a/bin/pax/sel_subs.c b/bin/pax/sel_subs.c new file mode 100644 index 0000000..fa7cb85 --- /dev/null +++ b/bin/pax/sel_subs.c @@ -0,0 +1,657 @@ +/*- + * Copyright (c) 1992 Keith Muller. + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Keith Muller of the University of California, San Diego. + * + * 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 sccsid[] = "@(#)sel_subs.c 8.1 (Berkeley) 5/31/93"; +#endif /* not lint */ + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <sys/param.h> +#include <pwd.h> +#include <grp.h> +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <strings.h> +#include <unistd.h> +#include <stdlib.h> +#include "pax.h" +#include "sel_subs.h" +#include "extern.h" + +static int str_sec __P((register char *, time_t *)); +static int usr_match __P((register ARCHD *)); +static int grp_match __P((register ARCHD *)); +static int trng_match __P((register ARCHD *)); + +static TIME_RNG *trhead = NULL; /* time range list head */ +static TIME_RNG *trtail = NULL; /* time range list tail */ +static USRT **usrtb = NULL; /* user selection table */ +static GRPT **grptb = NULL; /* group selection table */ + +/* + * Routines for selection of archive members + */ + +/* + * sel_chk() + * check if this file matches a specfied uid, gid or time range + * Return: + * 0 if this archive member should be processed, 1 if it should be skipped + */ + +#if __STDC__ +int +sel_chk(register ARCHD *arcn) +#else +int +sel_chk(arcn) + register ARCHD *arcn; +#endif +{ + if (((usrtb != NULL) && usr_match(arcn)) || + ((grptb != NULL) && grp_match(arcn)) || + ((trhead != NULL) && trng_match(arcn))) + return(1); + return(0); +} + +/* + * User/group selection routines + * + * Routines to handle user selection of files based on the file uid/gid. To + * add an entry, the user supplies either then name or the uid/gid starting with + * a # on the command line. A \# will eascape the #. + */ + +/* + * usr_add() + * add a user match to the user match hash table + * Return: + * 0 if added ok, -1 otherwise; + */ + +#if __STDC__ +int +usr_add(register char *str) +#else +int +usr_add(str) + register char *str; +#endif +{ + register u_int indx; + register USRT *pt; + register struct passwd *pw; + register uid_t uid; + + /* + * create the table if it doesn't exist + */ + if ((str == NULL) || (*str == '\0')) + return(-1); + if ((usrtb == NULL) && + ((usrtb = (USRT **)calloc(USR_TB_SZ, sizeof(USRT *))) == NULL)) { + warn(1, "Unable to allocate memory for user selection table"); + return(-1); + } + + /* + * figure out user spec + */ + if (str[0] != '#') { + /* + * it is a user name, \# escapes # as first char in user name + */ + if ((str[0] == '\\') && (str[1] == '#')) + ++str; + if ((pw = getpwnam(str)) == NULL) { + warn(1, "Unable to find uid for user: %s", str); + return(-1); + } + uid = (uid_t)pw->pw_uid; + } else +# ifdef NET2_STAT + uid = (uid_t)atoi(str+1); +# else + uid = (uid_t)strtoul(str+1, (char **)NULL, 10); +# endif + endpwent(); + + /* + * hash it and go down the hash chain (if any) looking for it + */ + indx = ((unsigned)uid) % USR_TB_SZ; + if ((pt = usrtb[indx]) != NULL) { + while (pt != NULL) { + if (pt->uid == uid) + return(0); + pt = pt->fow; + } + } + + /* + * uid is not yet in the table, add it to the front of the chain + */ + if ((pt = (USRT *)malloc(sizeof(USRT))) != NULL) { + pt->uid = uid; + pt->fow = usrtb[indx]; + usrtb[indx] = pt; + return(0); + } + warn(1, "User selection table out of memory"); + return(-1); +} + +/* + * usr_match() + * check if this files uid matches a selected uid. + * Return: + * 0 if this archive member should be processed, 1 if it should be skipped + */ + +#if __STDC__ +static int +usr_match(register ARCHD *arcn) +#else +static int +usr_match(arcn) + register ARCHD *arcn; +#endif +{ + register USRT *pt; + + /* + * hash and look for it in the table + */ + pt = usrtb[((unsigned)arcn->sb.st_uid) % USR_TB_SZ]; + while (pt != NULL) { + if (pt->uid == arcn->sb.st_uid) + return(0); + pt = pt->fow; + } + + /* + * not found + */ + return(1); +} + +/* + * grp_add() + * add a group match to the group match hash table + * Return: + * 0 if added ok, -1 otherwise; + */ + +#if __STDC__ +int +grp_add(register char *str) +#else +int +grp_add(str) + register char *str; +#endif +{ + register u_int indx; + register GRPT *pt; + register struct group *gr; + register gid_t gid; + + /* + * create the table if it doesn't exist + */ + if ((str == NULL) || (*str == '\0')) + return(-1); + if ((grptb == NULL) && + ((grptb = (GRPT **)calloc(GRP_TB_SZ, sizeof(GRPT *))) == NULL)) { + warn(1, "Unable to allocate memory fo group selection table"); + return(-1); + } + + /* + * figure out user spec + */ + if (str[0] != '#') { + /* + * it is a group name, \# escapes # as first char in group name + */ + if ((str[0] == '\\') && (str[1] == '#')) + ++str; + if ((gr = getgrnam(str)) == NULL) { + warn(1,"Cannot determine gid for group name: %s", str); + return(-1); + } + gid = (gid_t)gr->gr_gid; + } else +# ifdef NET2_STAT + gid = (gid_t)atoi(str+1); +# else + gid = (gid_t)strtoul(str+1, (char **)NULL, 10); +# endif + endgrent(); + + /* + * hash it and go down the hash chain (if any) looking for it + */ + indx = ((unsigned)gid) % GRP_TB_SZ; + if ((pt = grptb[indx]) != NULL) { + while (pt != NULL) { + if (pt->gid == gid) + return(0); + pt = pt->fow; + } + } + + /* + * gid not in the table, add it to the front of the chain + */ + if ((pt = (GRPT *)malloc(sizeof(GRPT))) != NULL) { + pt->gid = gid; + pt->fow = grptb[indx]; + grptb[indx] = pt; + return(0); + } + warn(1, "Group selection table out of memory"); + return(-1); +} + +/* + * grp_match() + * check if this files gid matches a selected gid. + * Return: + * 0 if this archive member should be processed, 1 if it should be skipped + */ + +#if __STDC__ +static int +grp_match(register ARCHD *arcn) +#else +static int +grp_match(arcn) + register ARCHD *arcn; +#endif +{ + register GRPT *pt; + + /* + * hash and look for it in the table + */ + pt = grptb[((unsigned)arcn->sb.st_gid) % GRP_TB_SZ]; + while (pt != NULL) { + if (pt->gid == arcn->sb.st_gid) + return(0); + pt = pt->fow; + } + + /* + * not found + */ + return(1); +} + +/* + * Time range selection routines + * + * Routines to handle user selection of files based on the modification and/or + * inode change time falling within a specified time range (the non-standard + * -T flag). The user may specify any number of different file time ranges. + * Time ranges are checked one at a time until a match is found (if at all). + * If the file has a mtime (and/or ctime) which lies within one of the time + * ranges, the file is selected. Time ranges may have a lower and/or a upper + * value. These ranges are inclusive. When no time ranges are supplied to pax + * with the -T option, all members in the archive will be selected by the time + * range routines. When only a lower range is supplied, only files with a + * mtime (and/or ctime) equal to or younger are selected. When only a upper + * range is supplied, only files with a mtime (and/or ctime) equal to or older + * are selected. When the lower time range is equal to the upper time range, + * only files with a mtime (or ctime) of exactly that time are selected. + */ + +/* + * trng_add() + * add a time range match to the time range list. + * This is a non-standard pax option. Lower and upper ranges are in the + * format: [yy[mm[dd[hh]]]]mm[.ss] and are comma separated. + * Time ranges are based on current time, so 1234 would specify a time of + * 12:34 today. + * Return: + * 0 if the time range was added to the list, -1 otherwise + */ + +#if __STDC__ +int +trng_add(register char *str) +#else +int +trng_add(str) + register char *str; +#endif +{ + register TIME_RNG *pt; + register char *up_pt = NULL; + register char *stpt; + register char *flgpt; + register int dot = 0; + + /* + * throw out the badly formed time ranges + */ + if ((str == NULL) || (*str == '\0')) { + warn(1, "Empty time range string"); + return(-1); + } + + /* + * locate optional flags suffix /{cm}. + */ + if ((flgpt = rindex(str, '/')) != NULL) + *flgpt++ = '\0'; + + for (stpt = str; *stpt != '\0'; ++stpt) { + if ((*stpt >= '0') && (*stpt <= '9')) + continue; + if ((*stpt == ',') && (up_pt == NULL)) { + *stpt = '\0'; + up_pt = stpt + 1; + dot = 0; + continue; + } + + /* + * allow only one dot per range (secs) + */ + if ((*stpt == '.') && (!dot)) { + ++dot; + continue; + } + warn(1, "Improperly specified time range: %s", str); + goto out; + } + + /* + * allocate space for the time range and store the limits + */ + if ((pt = (TIME_RNG *)malloc(sizeof(TIME_RNG))) == NULL) { + warn(1, "Unable to allocate memory for time range"); + return(-1); + } + + /* + * by default we only will check file mtime, but usee can specify + * mtime, ctime (inode change time) or both. + */ + if ((flgpt == NULL) || (*flgpt == '\0')) + pt->flgs = CMPMTME; + else { + pt->flgs = 0; + while (*flgpt != '\0') { + switch(*flgpt) { + case 'M': + case 'm': + pt->flgs |= CMPMTME; + break; + case 'C': + case 'c': + pt->flgs |= CMPCTME; + break; + default: + warn(1, "Bad option %c with time range %s", + *flgpt, str); + goto out; + } + ++flgpt; + } + } + + /* + * start off with the current time + */ + pt->low_time = pt->high_time = time((time_t *)NULL); + if (*str != '\0') { + /* + * add lower limit + */ + if (str_sec(str, &(pt->low_time)) < 0) { + warn(1, "Illegal lower time range %s", str); + (void)free((char *)pt); + goto out; + } + pt->flgs |= HASLOW; + } + + if ((up_pt != NULL) && (*up_pt != '\0')) { + /* + * add upper limit + */ + if (str_sec(up_pt, &(pt->high_time)) < 0) { + warn(1, "Illegal upper time range %s", up_pt); + (void)free((char *)pt); + goto out; + } + pt->flgs |= HASHIGH; + + /* + * check that the upper and lower do not overlap + */ + if (pt->flgs & HASLOW) { + if (pt->low_time > pt->high_time) { + warn(1, "Upper %s and lower %s time overlap", + up_pt, str); + (void)free((char *)pt); + return(-1); + } + } + } + + pt->fow = NULL; + if (trhead == NULL) { + trtail = trhead = pt; + return(0); + } + trtail->fow = pt; + trtail = pt; + return(0); + + out: + warn(1, "Time range format is: [yy[mm[dd[hh]]]]mm[.ss][/[c][m]]"); + return(-1); +} + +/* + * trng_match() + * check if this files mtime/ctime falls within any supplied time range. + * Return: + * 0 if this archive member should be processed, 1 if it should be skipped + */ + +#if __STDC__ +static int +trng_match(register ARCHD *arcn) +#else +static int +trng_match(arcn) + register ARCHD *arcn; +#endif +{ + register TIME_RNG *pt; + + /* + * have to search down the list one at a time looking for a match. + * remember time range limits are inclusive. + */ + pt = trhead; + while (pt != NULL) { + switch(pt->flgs & CMPBOTH) { + case CMPBOTH: + /* + * user wants both mtime and ctime checked for this + * time range + */ + if (((pt->flgs & HASLOW) && + (arcn->sb.st_mtime < pt->low_time) && + (arcn->sb.st_ctime < pt->low_time)) || + ((pt->flgs & HASHIGH) && + (arcn->sb.st_mtime > pt->high_time) && + (arcn->sb.st_ctime > pt->high_time))) { + pt = pt->fow; + continue; + } + break; + case CMPCTME: + /* + * user wants only ctime checked for this time range + */ + if (((pt->flgs & HASLOW) && + (arcn->sb.st_ctime < pt->low_time)) || + ((pt->flgs & HASHIGH) && + (arcn->sb.st_ctime > pt->high_time))) { + pt = pt->fow; + continue; + } + break; + case CMPMTME: + default: + /* + * user wants only mtime checked for this time range + */ + if (((pt->flgs & HASLOW) && + (arcn->sb.st_mtime < pt->low_time)) || + ((pt->flgs & HASHIGH) && + (arcn->sb.st_mtime > pt->high_time))) { + pt = pt->fow; + continue; + } + break; + } + break; + } + + if (pt == NULL) + return(1); + return(0); +} + +/* + * str_sec() + * Convert a time string in the format of [yy[mm[dd[hh]]]]mm[.ss] to gmt + * seconds. Tval already has current time loaded into it at entry. + * Return: + * 0 if converted ok, -1 otherwise + */ + +#if __STDC__ +static int +str_sec(register char *str, time_t *tval) +#else +static int +str_sec(str, tval) + register char *str; + time_t *tval; +#endif +{ + register struct tm *lt; + register char *dot = NULL; + + lt = localtime(tval); + if ((dot = index(str, '.')) != NULL) { + /* + * seconds (.ss) + */ + *dot++ = '\0'; + if (strlen(dot) != 2) + return(-1); + if ((lt->tm_sec = ATOI2(dot)) > 61) + return(-1); + } else + lt->tm_sec = 0; + + switch (strlen(str)) { + case 10: + /* + * year (yy) + * watch out for year 2000 + */ + if ((lt->tm_year = ATOI2(str)) < 69) + lt->tm_year += 100; + str += 2; + /* FALLTHROUGH */ + case 8: + /* + * month (mm) + * watch out months are from 0 - 11 internally + */ + if ((lt->tm_mon = ATOI2(str)) > 12) + return(-1); + --lt->tm_mon; + str += 2; + /* FALLTHROUGH */ + case 6: + /* + * day (dd) + */ + if ((lt->tm_mday = ATOI2(str)) > 31) + return(-1); + str += 2; + /* FALLTHROUGH */ + case 4: + /* + * hour (hh) + */ + if ((lt->tm_hour = ATOI2(str)) > 23) + return(-1); + str += 2; + /* FALLTHROUGH */ + case 2: + /* + * minute (mm) + */ + if ((lt->tm_min = ATOI2(str)) > 59) + return(-1); + break; + default: + return(-1); + } + /* + * convert broken-down time to GMT clock time seconds + */ + if ((*tval = mktime(lt)) == -1) + return(-1); + return(0); +} |