1*57196Smuller /*- 2*57196Smuller * Copyright (c) 1992 Keith Muller. 3*57196Smuller * Copyright (c) 1992 The Regents of the University of California. 4*57196Smuller * All rights reserved. 5*57196Smuller * 6*57196Smuller * This code is derived from software contributed to Berkeley by 7*57196Smuller * Keith Muller of the University of California, San Diego. 8*57196Smuller * 9*57196Smuller * %sccs.include.redist.c% 10*57196Smuller */ 11*57196Smuller 12*57196Smuller #ifndef lint 13*57196Smuller static char sccsid[] = "@(#)sel_subs.c 1.1 (Berkeley) 12/17/92"; 14*57196Smuller #endif /* not lint */ 15*57196Smuller 16*57196Smuller #include <sys/types.h> 17*57196Smuller #include <sys/time.h> 18*57196Smuller #include <sys/stat.h> 19*57196Smuller #include <sys/param.h> 20*57196Smuller #include <pwd.h> 21*57196Smuller #include <grp.h> 22*57196Smuller #include <stdio.h> 23*57196Smuller #include <ctype.h> 24*57196Smuller #include <string.h> 25*57196Smuller #include <strings.h> 26*57196Smuller #include <unistd.h> 27*57196Smuller #include <stdlib.h> 28*57196Smuller #include "pax.h" 29*57196Smuller #include "sel_subs.h" 30*57196Smuller #include "extern.h" 31*57196Smuller 32*57196Smuller static int str_sec __P((register char *, time_t *)); 33*57196Smuller static int usr_match __P((register ARCHD *)); 34*57196Smuller static int grp_match __P((register ARCHD *)); 35*57196Smuller static int trng_match __P((register ARCHD *)); 36*57196Smuller 37*57196Smuller static TIME_RNG *trhead = NULL; /* time range list head */ 38*57196Smuller static TIME_RNG *trtail = NULL; /* time range list tail */ 39*57196Smuller static USRT **usrtb = NULL; /* user selection table */ 40*57196Smuller static GRPT **grptb = NULL; /* group selection table */ 41*57196Smuller 42*57196Smuller /* 43*57196Smuller * Routines for selection of archive members 44*57196Smuller */ 45*57196Smuller 46*57196Smuller /* 47*57196Smuller * sel_chk() 48*57196Smuller * check if this files matches a specfied uid, gid and time range 49*57196Smuller * Return: 50*57196Smuller * 0 if this archive member should be processed, 1 if it should be skipped 51*57196Smuller */ 52*57196Smuller 53*57196Smuller #if __STDC__ 54*57196Smuller int 55*57196Smuller sel_chk(register ARCHD *arcn) 56*57196Smuller #else 57*57196Smuller int 58*57196Smuller sel_chk(arcn) 59*57196Smuller register ARCHD *arcn; 60*57196Smuller #endif 61*57196Smuller { 62*57196Smuller if (((usrtb != NULL) && usr_match(arcn)) || 63*57196Smuller ((grptb != NULL) && grp_match(arcn)) || 64*57196Smuller ((trhead != NULL) && trng_match(arcn))) 65*57196Smuller return(1); 66*57196Smuller return(0); 67*57196Smuller } 68*57196Smuller 69*57196Smuller /* 70*57196Smuller * User/group selection routines 71*57196Smuller * 72*57196Smuller * Routine that handle user selection of files based on the file uid/gid. To 73*57196Smuller * add an entry the user supplies either then name or the uid/gid starting with 74*57196Smuller * a #. A \# will eascape the #. 75*57196Smuller */ 76*57196Smuller 77*57196Smuller /* 78*57196Smuller * usr_add() 79*57196Smuller * add a user match to the user match hash table 80*57196Smuller * Return: 81*57196Smuller * 0 if added ok, -1 otherwise; 82*57196Smuller */ 83*57196Smuller 84*57196Smuller #if __STDC__ 85*57196Smuller int 86*57196Smuller usr_add(register char *str) 87*57196Smuller #else 88*57196Smuller int 89*57196Smuller usr_add(str) 90*57196Smuller register char *str; 91*57196Smuller #endif 92*57196Smuller { 93*57196Smuller register u_int indx; 94*57196Smuller register USRT *pt; 95*57196Smuller register struct passwd *pw; 96*57196Smuller register uid_t uid; 97*57196Smuller 98*57196Smuller /* 99*57196Smuller * create the table if it doesn't exist 100*57196Smuller */ 101*57196Smuller if ((str == NULL) || (*str == '\0')) 102*57196Smuller return(-1); 103*57196Smuller if ((usrtb == NULL) && 104*57196Smuller ((usrtb = (USRT **)calloc(USR_TB_SZ, sizeof(USRT *))) == NULL)) { 105*57196Smuller warn(1, "Unable to allocate memory for user selection table"); 106*57196Smuller return(-1); 107*57196Smuller } 108*57196Smuller 109*57196Smuller /* 110*57196Smuller * figure out user spec 111*57196Smuller */ 112*57196Smuller if (str[0] != '#') { 113*57196Smuller /* 114*57196Smuller * it is a user name, \# escapes # as first char in user name 115*57196Smuller */ 116*57196Smuller if ((str[0] == '\\') && (str[1] == '#')) 117*57196Smuller ++str; 118*57196Smuller if ((pw = getpwnam(str)) == NULL) { 119*57196Smuller warn(1, "Unable to find uid for user: %s", str); 120*57196Smuller return(-1); 121*57196Smuller } 122*57196Smuller uid = (uid_t)pw->pw_uid; 123*57196Smuller } else 124*57196Smuller # ifdef NET2_STAT 125*57196Smuller uid = (uid_t)atoi(str+1); 126*57196Smuller # else 127*57196Smuller uid = (uid_t)strtoul(str+1, (char **)NULL, 10); 128*57196Smuller # endif 129*57196Smuller endpwent(); 130*57196Smuller 131*57196Smuller /* 132*57196Smuller * hash it and go down the hash chain (if any) looking for it 133*57196Smuller */ 134*57196Smuller indx = ((unsigned)uid) % USR_TB_SZ; 135*57196Smuller if ((pt = usrtb[indx]) != NULL) { 136*57196Smuller while (pt != NULL) { 137*57196Smuller if (pt->uid == uid) 138*57196Smuller return(0); 139*57196Smuller pt = pt->fow; 140*57196Smuller } 141*57196Smuller } 142*57196Smuller 143*57196Smuller /* 144*57196Smuller * uid not already in the table, add it to the front of the chain 145*57196Smuller */ 146*57196Smuller if ((pt = (USRT *)malloc(sizeof(USRT))) != NULL) { 147*57196Smuller pt->uid = uid; 148*57196Smuller pt->fow = usrtb[indx]; 149*57196Smuller usrtb[indx] = pt; 150*57196Smuller return(0); 151*57196Smuller } 152*57196Smuller warn(1, "User selection table out of memory"); 153*57196Smuller return(-1); 154*57196Smuller } 155*57196Smuller 156*57196Smuller /* 157*57196Smuller * usr_match() 158*57196Smuller * check if this files uid matches a selected uid. 159*57196Smuller * Return: 160*57196Smuller * 0 if this archive member should be processed, 1 if it should be skipped 161*57196Smuller */ 162*57196Smuller 163*57196Smuller #if __STDC__ 164*57196Smuller static int 165*57196Smuller usr_match(register ARCHD *arcn) 166*57196Smuller #else 167*57196Smuller static int 168*57196Smuller usr_match(arcn) 169*57196Smuller register ARCHD *arcn; 170*57196Smuller #endif 171*57196Smuller { 172*57196Smuller register USRT *pt; 173*57196Smuller 174*57196Smuller /* 175*57196Smuller * hash and look for it in the table 176*57196Smuller */ 177*57196Smuller pt = usrtb[((unsigned)arcn->sb.st_uid) % USR_TB_SZ]; 178*57196Smuller while (pt != NULL) { 179*57196Smuller if (pt->uid == arcn->sb.st_uid) 180*57196Smuller return(0); 181*57196Smuller pt = pt->fow; 182*57196Smuller } 183*57196Smuller 184*57196Smuller /* 185*57196Smuller * not found 186*57196Smuller */ 187*57196Smuller return(1); 188*57196Smuller } 189*57196Smuller 190*57196Smuller /* 191*57196Smuller * grp_add() 192*57196Smuller * add a group match to the group match hash table 193*57196Smuller * Return: 194*57196Smuller * 0 if added ok, -1 otherwise; 195*57196Smuller */ 196*57196Smuller 197*57196Smuller #if __STDC__ 198*57196Smuller int 199*57196Smuller grp_add(register char *str) 200*57196Smuller #else 201*57196Smuller int 202*57196Smuller grp_add(str) 203*57196Smuller register char *str; 204*57196Smuller #endif 205*57196Smuller { 206*57196Smuller register u_int indx; 207*57196Smuller register GRPT *pt; 208*57196Smuller register struct group *gr; 209*57196Smuller register gid_t gid; 210*57196Smuller 211*57196Smuller /* 212*57196Smuller * create the table if it doesn't exist 213*57196Smuller */ 214*57196Smuller if ((str == NULL) || (*str == '\0')) 215*57196Smuller return(-1); 216*57196Smuller if ((grptb == NULL) && 217*57196Smuller ((grptb = (GRPT **)calloc(GRP_TB_SZ, sizeof(GRPT *))) == NULL)) { 218*57196Smuller warn(1, "Unable to allocate memory fo group selection table"); 219*57196Smuller return(-1); 220*57196Smuller } 221*57196Smuller 222*57196Smuller /* 223*57196Smuller * figure out user spec 224*57196Smuller */ 225*57196Smuller if (str[0] != '#') { 226*57196Smuller /* 227*57196Smuller * it is a group name, \# escapes # as first char in group name 228*57196Smuller */ 229*57196Smuller if ((str[0] == '\\') && (str[1] == '#')) 230*57196Smuller ++str; 231*57196Smuller if ((gr = getgrnam(str)) == NULL) { 232*57196Smuller warn(1,"Cannot determine gid for group name: %s", str); 233*57196Smuller return(-1); 234*57196Smuller } 235*57196Smuller gid = (gid_t)gr->gr_gid; 236*57196Smuller } else 237*57196Smuller # ifdef NET2_STAT 238*57196Smuller gid = (gid_t)atoi(str+1); 239*57196Smuller # else 240*57196Smuller gid = (gid_t)strtoul(str+1, (char **)NULL, 10); 241*57196Smuller # endif 242*57196Smuller endgrent(); 243*57196Smuller 244*57196Smuller /* 245*57196Smuller * hash it and go down the hash chain (if any) looking for it 246*57196Smuller */ 247*57196Smuller indx = ((unsigned)gid) % GRP_TB_SZ; 248*57196Smuller if ((pt = grptb[indx]) != NULL) { 249*57196Smuller while (pt != NULL) { 250*57196Smuller if (pt->gid == gid) 251*57196Smuller return(0); 252*57196Smuller pt = pt->fow; 253*57196Smuller } 254*57196Smuller } 255*57196Smuller 256*57196Smuller /* 257*57196Smuller * gid not already in the table, add it to the front of the chain 258*57196Smuller */ 259*57196Smuller if ((pt = (GRPT *)malloc(sizeof(GRPT))) != NULL) { 260*57196Smuller pt->gid = gid; 261*57196Smuller pt->fow = grptb[indx]; 262*57196Smuller grptb[indx] = pt; 263*57196Smuller return(0); 264*57196Smuller } 265*57196Smuller warn(1, "Group selection table out of memory"); 266*57196Smuller return(-1); 267*57196Smuller } 268*57196Smuller 269*57196Smuller /* 270*57196Smuller * grp_match() 271*57196Smuller * check if this files gid matches a selected gid. 272*57196Smuller * Return: 273*57196Smuller * 0 if this archive member should be processed, 1 if it should be skipped 274*57196Smuller */ 275*57196Smuller 276*57196Smuller #if __STDC__ 277*57196Smuller static int 278*57196Smuller grp_match(register ARCHD *arcn) 279*57196Smuller #else 280*57196Smuller static int 281*57196Smuller grp_match(arcn) 282*57196Smuller register ARCHD *arcn; 283*57196Smuller #endif 284*57196Smuller { 285*57196Smuller register GRPT *pt; 286*57196Smuller 287*57196Smuller /* 288*57196Smuller * hash and look for it in the table 289*57196Smuller */ 290*57196Smuller pt = grptb[((unsigned)arcn->sb.st_gid) % GRP_TB_SZ]; 291*57196Smuller while (pt != NULL) { 292*57196Smuller if (pt->gid == arcn->sb.st_gid) 293*57196Smuller return(0); 294*57196Smuller pt = pt->fow; 295*57196Smuller } 296*57196Smuller 297*57196Smuller /* 298*57196Smuller * not found 299*57196Smuller */ 300*57196Smuller return(1); 301*57196Smuller } 302*57196Smuller 303*57196Smuller /* 304*57196Smuller * Time range selection routines 305*57196Smuller * 306*57196Smuller * Routines to handle user selection of files based on the modification time 307*57196Smuller * being within a specified time range (the non-standard -T flag). The user 308*57196Smuller * may specify any number of different file modification time ranges. The 309*57196Smuller * ranges are checked one at a time until a match is found (if at all). 310*57196Smuller * If the file has a mtime that lies within one of the time ranges, the file 311*57196Smuller * is selected. Time ranges may have a lower and/or a upper value. Ranges are 312*57196Smuller * inclusive. If no time ranges are supplied to pax, all members in the archive 313*57196Smuller * will be selected. If only a lower range is supplied, all files with a mtime 314*57196Smuller * equal to or younger are selected. If only an upper range is supplied, all 315*57196Smuller * files with a mtime equal to or older will be selected. When the lower value 316*57196Smuller * is equal to the upper value, only files with a mtime of exactly that time 317*57196Smuller * will be selected. 318*57196Smuller */ 319*57196Smuller 320*57196Smuller /* 321*57196Smuller * trng_add() 322*57196Smuller * add a time range match to the time range list. 323*57196Smuller * This is a non-standard pax option. Lower and upper ranges are in the 324*57196Smuller * format: [yy[mm[dd[hh]]]]mm[.ss] and are comma separated. 325*57196Smuller * Time ranges are based on current time, so 1234 would specify a time of 326*57196Smuller * 12:34 today. 327*57196Smuller * Return: 328*57196Smuller * 0 if the time range was added to the list, -1 otherwise 329*57196Smuller */ 330*57196Smuller 331*57196Smuller #if __STDC__ 332*57196Smuller int 333*57196Smuller trng_add(register char *str) 334*57196Smuller #else 335*57196Smuller int 336*57196Smuller trng_add(str) 337*57196Smuller register char *str; 338*57196Smuller #endif 339*57196Smuller { 340*57196Smuller register TIME_RNG *pt; 341*57196Smuller register char *up_pt = NULL; 342*57196Smuller register char *stpt; 343*57196Smuller register int dot = 0; 344*57196Smuller 345*57196Smuller /* 346*57196Smuller * throw out the badly formed time ranges 347*57196Smuller */ 348*57196Smuller if ((str == NULL) || (*str == '\0')) { 349*57196Smuller warn(1, "Empty time range string"); 350*57196Smuller return(-1); 351*57196Smuller } 352*57196Smuller 353*57196Smuller for (stpt = str; *stpt != '\0'; ++stpt) { 354*57196Smuller if ((*stpt >= '0') && (*stpt <= '9')) 355*57196Smuller continue; 356*57196Smuller if ((*stpt == ',') && (up_pt == NULL)) { 357*57196Smuller *stpt = '\0'; 358*57196Smuller up_pt = stpt + 1; 359*57196Smuller dot = 0; 360*57196Smuller continue; 361*57196Smuller } 362*57196Smuller 363*57196Smuller /* 364*57196Smuller * allow only one dot per range (secs) 365*57196Smuller */ 366*57196Smuller if ((*stpt == '.') && (!dot)) { 367*57196Smuller ++dot; 368*57196Smuller continue; 369*57196Smuller } 370*57196Smuller warn(1, "Improperly specified time range: %s", str); 371*57196Smuller goto out; 372*57196Smuller } 373*57196Smuller 374*57196Smuller /* 375*57196Smuller * allocate space for the time range and store the limits 376*57196Smuller */ 377*57196Smuller if ((pt = (TIME_RNG *)malloc(sizeof(TIME_RNG))) == NULL) { 378*57196Smuller warn(1, "Unable to allocate memory for time range"); 379*57196Smuller return(-1); 380*57196Smuller } 381*57196Smuller pt->flags = 0; 382*57196Smuller 383*57196Smuller /* 384*57196Smuller * start off with the current time 385*57196Smuller */ 386*57196Smuller pt->low_time = pt->high_time = time((time_t *)NULL); 387*57196Smuller if (*str != '\0') { 388*57196Smuller /* 389*57196Smuller * add lower limit 390*57196Smuller */ 391*57196Smuller if (str_sec(str, &(pt->low_time)) < 0) { 392*57196Smuller warn(1, "Illegal lower time range %s", str); 393*57196Smuller (void)free((char *)pt); 394*57196Smuller goto out; 395*57196Smuller } 396*57196Smuller pt->flags |= HASLOW; 397*57196Smuller } 398*57196Smuller 399*57196Smuller if ((up_pt != NULL) && (*up_pt != '\0')) { 400*57196Smuller /* 401*57196Smuller * add upper limit 402*57196Smuller */ 403*57196Smuller if (str_sec(up_pt, &(pt->high_time)) < 0) { 404*57196Smuller warn(1, "Illegal upper time range %s", up_pt); 405*57196Smuller (void)free((char *)pt); 406*57196Smuller goto out; 407*57196Smuller } 408*57196Smuller pt->flags |= HASHIGH; 409*57196Smuller 410*57196Smuller /* 411*57196Smuller * check that the upper and lower do not overlap 412*57196Smuller */ 413*57196Smuller if (pt->flags & HASLOW) { 414*57196Smuller if (pt->low_time > pt->high_time) { 415*57196Smuller warn(1, "Upper %s and lower %s time overlap", 416*57196Smuller up_pt, str); 417*57196Smuller (void)free((char *)pt); 418*57196Smuller return(-1); 419*57196Smuller } 420*57196Smuller } 421*57196Smuller } 422*57196Smuller 423*57196Smuller pt->fow = NULL; 424*57196Smuller if (trhead == NULL) { 425*57196Smuller trtail = trhead = pt; 426*57196Smuller return(0); 427*57196Smuller } 428*57196Smuller trtail->fow = pt; 429*57196Smuller trtail = pt; 430*57196Smuller return(0); 431*57196Smuller out: 432*57196Smuller warn(0, "Time range format is: [yy[mm[dd[hh]]]]mm[.ss]"); 433*57196Smuller return(-1); 434*57196Smuller } 435*57196Smuller 436*57196Smuller /* 437*57196Smuller * trng_match() 438*57196Smuller * check if this files mtime falls within any supplied time range. 439*57196Smuller * Return: 440*57196Smuller * 0 if this archive member should be processed, 1 if it should be skipped 441*57196Smuller */ 442*57196Smuller 443*57196Smuller #if __STDC__ 444*57196Smuller static int 445*57196Smuller trng_match(register ARCHD *arcn) 446*57196Smuller #else 447*57196Smuller static int 448*57196Smuller trng_match(arcn) 449*57196Smuller register ARCHD *arcn; 450*57196Smuller #endif 451*57196Smuller { 452*57196Smuller register TIME_RNG *pt; 453*57196Smuller 454*57196Smuller /* 455*57196Smuller * have to search down the list one at a time looking for a match. 456*57196Smuller * remember time range limits are inclusive. 457*57196Smuller */ 458*57196Smuller pt = trhead; 459*57196Smuller while (pt != NULL) { 460*57196Smuller if (pt->flags & HASLOW) { 461*57196Smuller if (arcn->sb.st_mtime < pt->low_time) { 462*57196Smuller pt = pt->fow; 463*57196Smuller continue; 464*57196Smuller } 465*57196Smuller } 466*57196Smuller if (pt->flags & HASHIGH) { 467*57196Smuller if (arcn->sb.st_mtime > pt->high_time) { 468*57196Smuller pt = pt->fow; 469*57196Smuller continue; 470*57196Smuller } 471*57196Smuller } 472*57196Smuller break; 473*57196Smuller } 474*57196Smuller 475*57196Smuller if (pt == NULL) 476*57196Smuller return(1); 477*57196Smuller return(0); 478*57196Smuller } 479*57196Smuller 480*57196Smuller /* 481*57196Smuller * str_sec() 482*57196Smuller * Convert a time string in the format of [yy[mm[dd[hh]]]]mm[.ss] to gmt 483*57196Smuller * seconds. Tval already has current time loaded into it at entry. 484*57196Smuller * Return: 485*57196Smuller * 0 if converted ok, -1 otherwise 486*57196Smuller */ 487*57196Smuller 488*57196Smuller #if __STDC__ 489*57196Smuller static int 490*57196Smuller str_sec(register char *str, time_t *tval) 491*57196Smuller #else 492*57196Smuller static int 493*57196Smuller str_sec(str, tval) 494*57196Smuller register char *str; 495*57196Smuller time_t *tval; 496*57196Smuller #endif 497*57196Smuller { 498*57196Smuller register struct tm *lt; 499*57196Smuller register char *dot = NULL; 500*57196Smuller 501*57196Smuller lt = localtime(tval); 502*57196Smuller if ((dot = index(str, '.')) != NULL) { 503*57196Smuller /* 504*57196Smuller * seconds (.ss) 505*57196Smuller */ 506*57196Smuller *dot++ = '\0'; 507*57196Smuller if (strlen(dot) != 2) 508*57196Smuller return(-1); 509*57196Smuller if ((lt->tm_sec = ATOI2(dot)) > 61) 510*57196Smuller return(-1); 511*57196Smuller } else 512*57196Smuller lt->tm_sec = 0; 513*57196Smuller 514*57196Smuller switch (strlen(str)) { 515*57196Smuller case 10: 516*57196Smuller /* 517*57196Smuller * year (yy) 518*57196Smuller * watch out for year 2000 519*57196Smuller */ 520*57196Smuller if ((lt->tm_year = ATOI2(str)) < 69) 521*57196Smuller lt->tm_year += 100; 522*57196Smuller str += 2; 523*57196Smuller /* FALLTHROUGH */ 524*57196Smuller case 8: 525*57196Smuller /* 526*57196Smuller * month (mm) 527*57196Smuller * watch out months are from 0 - 11 internally 528*57196Smuller */ 529*57196Smuller if ((lt->tm_mon = ATOI2(str)) > 12) 530*57196Smuller return(-1); 531*57196Smuller --lt->tm_mon; 532*57196Smuller str += 2; 533*57196Smuller /* FALLTHROUGH */ 534*57196Smuller case 6: 535*57196Smuller /* 536*57196Smuller * day (dd) 537*57196Smuller */ 538*57196Smuller if ((lt->tm_mday = ATOI2(str)) > 31) 539*57196Smuller return(-1); 540*57196Smuller str += 2; 541*57196Smuller /* FALLTHROUGH */ 542*57196Smuller case 4: 543*57196Smuller /* 544*57196Smuller * hour (hh) 545*57196Smuller */ 546*57196Smuller if ((lt->tm_hour = ATOI2(str)) > 23) 547*57196Smuller return(-1); 548*57196Smuller str += 2; 549*57196Smuller /* FALLTHROUGH */ 550*57196Smuller case 2: 551*57196Smuller /* 552*57196Smuller * minute (mm) 553*57196Smuller */ 554*57196Smuller if ((lt->tm_min = ATOI2(str)) > 59) 555*57196Smuller return(-1); 556*57196Smuller break; 557*57196Smuller default: 558*57196Smuller return(-1); 559*57196Smuller } 560*57196Smuller /* 561*57196Smuller * convert broken-down time to GMT clock time seconds 562*57196Smuller */ 563*57196Smuller if ((*tval = mktime(lt)) == -1) 564*57196Smuller return(-1); 565*57196Smuller return(0); 566*57196Smuller } 567