157196Smuller /*- 257196Smuller * Copyright (c) 1992 Keith Muller. 357196Smuller * Copyright (c) 1992 The Regents of the University of California. 457196Smuller * All rights reserved. 557196Smuller * 657196Smuller * This code is derived from software contributed to Berkeley by 757196Smuller * Keith Muller of the University of California, San Diego. 857196Smuller * 957196Smuller * %sccs.include.redist.c% 1057196Smuller */ 1157196Smuller 1257196Smuller #ifndef lint 13*57576Smuller static char sccsid[] = "@(#)sel_subs.c 1.3 (Berkeley) 01/16/93"; 1457196Smuller #endif /* not lint */ 1557196Smuller 1657196Smuller #include <sys/types.h> 1757196Smuller #include <sys/time.h> 1857196Smuller #include <sys/stat.h> 1957196Smuller #include <sys/param.h> 2057196Smuller #include <pwd.h> 2157196Smuller #include <grp.h> 2257196Smuller #include <stdio.h> 2357196Smuller #include <ctype.h> 2457196Smuller #include <string.h> 2557196Smuller #include <strings.h> 2657196Smuller #include <unistd.h> 2757196Smuller #include <stdlib.h> 2857196Smuller #include "pax.h" 2957196Smuller #include "sel_subs.h" 3057196Smuller #include "extern.h" 3157196Smuller 3257196Smuller static int str_sec __P((register char *, time_t *)); 3357196Smuller static int usr_match __P((register ARCHD *)); 3457196Smuller static int grp_match __P((register ARCHD *)); 3557196Smuller static int trng_match __P((register ARCHD *)); 3657196Smuller 3757196Smuller static TIME_RNG *trhead = NULL; /* time range list head */ 3857196Smuller static TIME_RNG *trtail = NULL; /* time range list tail */ 3957196Smuller static USRT **usrtb = NULL; /* user selection table */ 4057196Smuller static GRPT **grptb = NULL; /* group selection table */ 4157196Smuller 4257196Smuller /* 4357196Smuller * Routines for selection of archive members 4457196Smuller */ 4557196Smuller 4657196Smuller /* 4757196Smuller * sel_chk() 4857501Smuller * check if this file matches a specfied uid, gid or time range 4957196Smuller * Return: 5057196Smuller * 0 if this archive member should be processed, 1 if it should be skipped 5157196Smuller */ 5257196Smuller 5357196Smuller #if __STDC__ 5457196Smuller int 5557196Smuller sel_chk(register ARCHD *arcn) 5657196Smuller #else 5757196Smuller int 5857196Smuller sel_chk(arcn) 5957196Smuller register ARCHD *arcn; 6057196Smuller #endif 6157196Smuller { 6257196Smuller if (((usrtb != NULL) && usr_match(arcn)) || 6357196Smuller ((grptb != NULL) && grp_match(arcn)) || 6457196Smuller ((trhead != NULL) && trng_match(arcn))) 6557196Smuller return(1); 6657196Smuller return(0); 6757196Smuller } 6857196Smuller 6957196Smuller /* 7057196Smuller * User/group selection routines 7157196Smuller * 7257501Smuller * Routines to handle user selection of files based on the file uid/gid. To 7357501Smuller * add an entry, the user supplies either then name or the uid/gid starting with 7457501Smuller * a # on the command line. A \# will eascape the #. 7557196Smuller */ 7657196Smuller 7757196Smuller /* 7857196Smuller * usr_add() 7957196Smuller * add a user match to the user match hash table 8057196Smuller * Return: 8157196Smuller * 0 if added ok, -1 otherwise; 8257196Smuller */ 8357196Smuller 8457196Smuller #if __STDC__ 8557196Smuller int 8657196Smuller usr_add(register char *str) 8757196Smuller #else 8857196Smuller int 8957196Smuller usr_add(str) 9057196Smuller register char *str; 9157196Smuller #endif 9257196Smuller { 9357196Smuller register u_int indx; 9457196Smuller register USRT *pt; 9557196Smuller register struct passwd *pw; 9657196Smuller register uid_t uid; 9757196Smuller 9857196Smuller /* 9957196Smuller * create the table if it doesn't exist 10057196Smuller */ 10157196Smuller if ((str == NULL) || (*str == '\0')) 10257196Smuller return(-1); 10357196Smuller if ((usrtb == NULL) && 10457196Smuller ((usrtb = (USRT **)calloc(USR_TB_SZ, sizeof(USRT *))) == NULL)) { 10557196Smuller warn(1, "Unable to allocate memory for user selection table"); 10657196Smuller return(-1); 10757196Smuller } 10857196Smuller 10957196Smuller /* 11057196Smuller * figure out user spec 11157196Smuller */ 11257196Smuller if (str[0] != '#') { 11357196Smuller /* 11457196Smuller * it is a user name, \# escapes # as first char in user name 11557196Smuller */ 11657196Smuller if ((str[0] == '\\') && (str[1] == '#')) 11757196Smuller ++str; 11857196Smuller if ((pw = getpwnam(str)) == NULL) { 11957196Smuller warn(1, "Unable to find uid for user: %s", str); 12057196Smuller return(-1); 12157196Smuller } 12257196Smuller uid = (uid_t)pw->pw_uid; 12357196Smuller } else 12457196Smuller # ifdef NET2_STAT 12557196Smuller uid = (uid_t)atoi(str+1); 12657196Smuller # else 12757196Smuller uid = (uid_t)strtoul(str+1, (char **)NULL, 10); 12857196Smuller # endif 12957196Smuller endpwent(); 13057196Smuller 13157196Smuller /* 13257196Smuller * hash it and go down the hash chain (if any) looking for it 13357196Smuller */ 13457196Smuller indx = ((unsigned)uid) % USR_TB_SZ; 13557196Smuller if ((pt = usrtb[indx]) != NULL) { 13657196Smuller while (pt != NULL) { 13757196Smuller if (pt->uid == uid) 13857196Smuller return(0); 13957196Smuller pt = pt->fow; 14057196Smuller } 14157196Smuller } 14257196Smuller 14357196Smuller /* 14457501Smuller * uid is not yet in the table, add it to the front of the chain 14557196Smuller */ 14657196Smuller if ((pt = (USRT *)malloc(sizeof(USRT))) != NULL) { 14757196Smuller pt->uid = uid; 14857196Smuller pt->fow = usrtb[indx]; 14957196Smuller usrtb[indx] = pt; 15057196Smuller return(0); 15157196Smuller } 15257196Smuller warn(1, "User selection table out of memory"); 15357196Smuller return(-1); 15457196Smuller } 15557196Smuller 15657196Smuller /* 15757196Smuller * usr_match() 15857196Smuller * check if this files uid matches a selected uid. 15957196Smuller * Return: 16057196Smuller * 0 if this archive member should be processed, 1 if it should be skipped 16157196Smuller */ 16257196Smuller 16357196Smuller #if __STDC__ 16457196Smuller static int 16557196Smuller usr_match(register ARCHD *arcn) 16657196Smuller #else 16757196Smuller static int 16857196Smuller usr_match(arcn) 16957196Smuller register ARCHD *arcn; 17057196Smuller #endif 17157196Smuller { 17257196Smuller register USRT *pt; 17357196Smuller 17457196Smuller /* 17557196Smuller * hash and look for it in the table 17657196Smuller */ 17757196Smuller pt = usrtb[((unsigned)arcn->sb.st_uid) % USR_TB_SZ]; 17857196Smuller while (pt != NULL) { 17957196Smuller if (pt->uid == arcn->sb.st_uid) 18057196Smuller return(0); 18157196Smuller pt = pt->fow; 18257196Smuller } 18357196Smuller 18457196Smuller /* 18557196Smuller * not found 18657196Smuller */ 18757196Smuller return(1); 18857196Smuller } 18957196Smuller 19057196Smuller /* 19157196Smuller * grp_add() 19257196Smuller * add a group match to the group match hash table 19357196Smuller * Return: 19457196Smuller * 0 if added ok, -1 otherwise; 19557196Smuller */ 19657196Smuller 19757196Smuller #if __STDC__ 19857196Smuller int 19957196Smuller grp_add(register char *str) 20057196Smuller #else 20157196Smuller int 20257196Smuller grp_add(str) 20357196Smuller register char *str; 20457196Smuller #endif 20557196Smuller { 20657196Smuller register u_int indx; 20757196Smuller register GRPT *pt; 20857196Smuller register struct group *gr; 20957196Smuller register gid_t gid; 21057196Smuller 21157196Smuller /* 21257196Smuller * create the table if it doesn't exist 21357196Smuller */ 21457196Smuller if ((str == NULL) || (*str == '\0')) 21557196Smuller return(-1); 21657196Smuller if ((grptb == NULL) && 21757196Smuller ((grptb = (GRPT **)calloc(GRP_TB_SZ, sizeof(GRPT *))) == NULL)) { 21857196Smuller warn(1, "Unable to allocate memory fo group selection table"); 21957196Smuller return(-1); 22057196Smuller } 22157196Smuller 22257196Smuller /* 22357196Smuller * figure out user spec 22457196Smuller */ 22557196Smuller if (str[0] != '#') { 22657196Smuller /* 22757196Smuller * it is a group name, \# escapes # as first char in group name 22857196Smuller */ 22957196Smuller if ((str[0] == '\\') && (str[1] == '#')) 23057196Smuller ++str; 23157196Smuller if ((gr = getgrnam(str)) == NULL) { 23257196Smuller warn(1,"Cannot determine gid for group name: %s", str); 23357196Smuller return(-1); 23457196Smuller } 23557196Smuller gid = (gid_t)gr->gr_gid; 23657196Smuller } else 23757196Smuller # ifdef NET2_STAT 23857196Smuller gid = (gid_t)atoi(str+1); 23957196Smuller # else 24057196Smuller gid = (gid_t)strtoul(str+1, (char **)NULL, 10); 24157196Smuller # endif 24257196Smuller endgrent(); 24357196Smuller 24457196Smuller /* 24557196Smuller * hash it and go down the hash chain (if any) looking for it 24657196Smuller */ 24757196Smuller indx = ((unsigned)gid) % GRP_TB_SZ; 24857196Smuller if ((pt = grptb[indx]) != NULL) { 24957196Smuller while (pt != NULL) { 25057196Smuller if (pt->gid == gid) 25157196Smuller return(0); 25257196Smuller pt = pt->fow; 25357196Smuller } 25457196Smuller } 25557196Smuller 25657196Smuller /* 25757501Smuller * gid not in the table, add it to the front of the chain 25857196Smuller */ 25957196Smuller if ((pt = (GRPT *)malloc(sizeof(GRPT))) != NULL) { 26057196Smuller pt->gid = gid; 26157196Smuller pt->fow = grptb[indx]; 26257196Smuller grptb[indx] = pt; 26357196Smuller return(0); 26457196Smuller } 26557196Smuller warn(1, "Group selection table out of memory"); 26657196Smuller return(-1); 26757196Smuller } 26857196Smuller 26957196Smuller /* 27057196Smuller * grp_match() 27157196Smuller * check if this files gid matches a selected gid. 27257196Smuller * Return: 27357196Smuller * 0 if this archive member should be processed, 1 if it should be skipped 27457196Smuller */ 27557196Smuller 27657196Smuller #if __STDC__ 27757196Smuller static int 27857196Smuller grp_match(register ARCHD *arcn) 27957196Smuller #else 28057196Smuller static int 28157196Smuller grp_match(arcn) 28257196Smuller register ARCHD *arcn; 28357196Smuller #endif 28457196Smuller { 28557196Smuller register GRPT *pt; 28657196Smuller 28757196Smuller /* 28857196Smuller * hash and look for it in the table 28957196Smuller */ 29057196Smuller pt = grptb[((unsigned)arcn->sb.st_gid) % GRP_TB_SZ]; 29157196Smuller while (pt != NULL) { 29257196Smuller if (pt->gid == arcn->sb.st_gid) 29357196Smuller return(0); 29457196Smuller pt = pt->fow; 29557196Smuller } 29657196Smuller 29757196Smuller /* 29857196Smuller * not found 29957196Smuller */ 30057196Smuller return(1); 30157196Smuller } 30257196Smuller 30357196Smuller /* 30457196Smuller * Time range selection routines 30557196Smuller * 30657501Smuller * Routines to handle user selection of files based on the modification and/or 30757501Smuller * inode change time falling within a specified time range (the non-standard 30857501Smuller * -T flag). The user may specify any number of different file time ranges. 30957501Smuller * Time ranges are checked one at a time until a match is found (if at all). 31057501Smuller * If the file has a mtime (and/or ctime) which lies within one of the time 31157501Smuller * ranges, the file is selected. Time ranges may have a lower and/or a upper 31257501Smuller * value. These ranges are inclusive. When no time ranges are supplied to pax 31357501Smuller * with the -T option, all members in the archive will be selected by the time 31457501Smuller * range routines. When only a lower range is supplied, only files with a 31557501Smuller * mtime (and/or ctime) equal to or younger are selected. When only a upper 31657501Smuller * range is supplied, only files with a mtime (and/or ctime) equal to or older 31757501Smuller * are selected. When the lower time range is equal to the upper time range, 31857501Smuller * only files with a mtime (or ctime) of exactly that time are selected. 31957196Smuller */ 32057196Smuller 32157196Smuller /* 32257196Smuller * trng_add() 32357196Smuller * add a time range match to the time range list. 32457196Smuller * This is a non-standard pax option. Lower and upper ranges are in the 32557196Smuller * format: [yy[mm[dd[hh]]]]mm[.ss] and are comma separated. 32657196Smuller * Time ranges are based on current time, so 1234 would specify a time of 32757196Smuller * 12:34 today. 32857196Smuller * Return: 32957196Smuller * 0 if the time range was added to the list, -1 otherwise 33057196Smuller */ 33157196Smuller 33257196Smuller #if __STDC__ 33357196Smuller int 33457196Smuller trng_add(register char *str) 33557196Smuller #else 33657196Smuller int 33757196Smuller trng_add(str) 33857196Smuller register char *str; 33957196Smuller #endif 34057196Smuller { 34157196Smuller register TIME_RNG *pt; 34257196Smuller register char *up_pt = NULL; 34357196Smuller register char *stpt; 34457501Smuller register char *flgpt; 34557196Smuller register int dot = 0; 34657196Smuller 34757196Smuller /* 34857196Smuller * throw out the badly formed time ranges 34957196Smuller */ 35057196Smuller if ((str == NULL) || (*str == '\0')) { 35157196Smuller warn(1, "Empty time range string"); 35257196Smuller return(-1); 35357196Smuller } 35457196Smuller 35557501Smuller /* 356*57576Smuller * locate optional flags suffix /{cm}. 35757501Smuller */ 358*57576Smuller if ((flgpt = rindex(str, '/')) != NULL) 35957501Smuller *flgpt++ = '\0'; 36057501Smuller 36157196Smuller for (stpt = str; *stpt != '\0'; ++stpt) { 36257196Smuller if ((*stpt >= '0') && (*stpt <= '9')) 36357196Smuller continue; 36457196Smuller if ((*stpt == ',') && (up_pt == NULL)) { 36557196Smuller *stpt = '\0'; 36657196Smuller up_pt = stpt + 1; 36757196Smuller dot = 0; 36857196Smuller continue; 36957196Smuller } 37057196Smuller 37157196Smuller /* 37257196Smuller * allow only one dot per range (secs) 37357196Smuller */ 37457196Smuller if ((*stpt == '.') && (!dot)) { 37557196Smuller ++dot; 37657196Smuller continue; 37757196Smuller } 37857196Smuller warn(1, "Improperly specified time range: %s", str); 37957196Smuller goto out; 38057196Smuller } 38157196Smuller 38257196Smuller /* 38357196Smuller * allocate space for the time range and store the limits 38457196Smuller */ 38557196Smuller if ((pt = (TIME_RNG *)malloc(sizeof(TIME_RNG))) == NULL) { 38657196Smuller warn(1, "Unable to allocate memory for time range"); 38757196Smuller return(-1); 38857196Smuller } 38957196Smuller 39057196Smuller /* 39157501Smuller * by default we only will check file mtime, but usee can specify 39257501Smuller * mtime, ctime (inode change time) or both. 39357501Smuller */ 39457501Smuller if ((flgpt == NULL) || (*flgpt == '\0')) 39557501Smuller pt->flgs = CMPMTME; 39657501Smuller else { 39757501Smuller pt->flgs = 0; 39857501Smuller while (*flgpt != '\0') { 39957501Smuller switch(*flgpt) { 40057501Smuller case 'M': 40157501Smuller case 'm': 40257501Smuller pt->flgs |= CMPMTME; 40357501Smuller break; 40457501Smuller case 'C': 40557501Smuller case 'c': 40657501Smuller pt->flgs |= CMPCTME; 40757501Smuller break; 40857501Smuller default: 40957501Smuller warn(1, "Bad option %c with time range %s", 41057501Smuller *flgpt, str); 41157501Smuller goto out; 41257501Smuller } 41357501Smuller ++flgpt; 41457501Smuller } 41557501Smuller } 41657501Smuller 41757501Smuller /* 41857196Smuller * start off with the current time 41957196Smuller */ 42057196Smuller pt->low_time = pt->high_time = time((time_t *)NULL); 42157196Smuller if (*str != '\0') { 42257196Smuller /* 42357196Smuller * add lower limit 42457196Smuller */ 42557196Smuller if (str_sec(str, &(pt->low_time)) < 0) { 42657196Smuller warn(1, "Illegal lower time range %s", str); 42757196Smuller (void)free((char *)pt); 42857196Smuller goto out; 42957196Smuller } 43057501Smuller pt->flgs |= HASLOW; 43157196Smuller } 43257196Smuller 43357196Smuller if ((up_pt != NULL) && (*up_pt != '\0')) { 43457196Smuller /* 43557196Smuller * add upper limit 43657196Smuller */ 43757196Smuller if (str_sec(up_pt, &(pt->high_time)) < 0) { 43857196Smuller warn(1, "Illegal upper time range %s", up_pt); 43957196Smuller (void)free((char *)pt); 44057196Smuller goto out; 44157196Smuller } 44257501Smuller pt->flgs |= HASHIGH; 44357196Smuller 44457196Smuller /* 44557196Smuller * check that the upper and lower do not overlap 44657196Smuller */ 44757501Smuller if (pt->flgs & HASLOW) { 44857196Smuller if (pt->low_time > pt->high_time) { 44957196Smuller warn(1, "Upper %s and lower %s time overlap", 45057196Smuller up_pt, str); 45157196Smuller (void)free((char *)pt); 45257196Smuller return(-1); 45357196Smuller } 45457196Smuller } 45557196Smuller } 45657196Smuller 45757196Smuller pt->fow = NULL; 45857196Smuller if (trhead == NULL) { 45957196Smuller trtail = trhead = pt; 46057196Smuller return(0); 46157196Smuller } 46257196Smuller trtail->fow = pt; 46357196Smuller trtail = pt; 46457196Smuller return(0); 46557501Smuller 46657196Smuller out: 46757501Smuller warn(1, "Time range format is: [yy[mm[dd[hh]]]]mm[.ss][/[c][m]]"); 46857196Smuller return(-1); 46957196Smuller } 47057196Smuller 47157196Smuller /* 47257196Smuller * trng_match() 47357501Smuller * check if this files mtime/ctime falls within any supplied time range. 47457196Smuller * Return: 47557196Smuller * 0 if this archive member should be processed, 1 if it should be skipped 47657196Smuller */ 47757196Smuller 47857196Smuller #if __STDC__ 47957196Smuller static int 48057196Smuller trng_match(register ARCHD *arcn) 48157196Smuller #else 48257196Smuller static int 48357196Smuller trng_match(arcn) 48457196Smuller register ARCHD *arcn; 48557196Smuller #endif 48657196Smuller { 48757196Smuller register TIME_RNG *pt; 48857196Smuller 48957196Smuller /* 49057196Smuller * have to search down the list one at a time looking for a match. 49157196Smuller * remember time range limits are inclusive. 49257196Smuller */ 49357196Smuller pt = trhead; 49457196Smuller while (pt != NULL) { 49557501Smuller switch(pt->flgs & CMPBOTH) { 49657501Smuller case CMPBOTH: 49757501Smuller /* 49857501Smuller * user wants both mtime and ctime checked for this 49957501Smuller * time range 50057501Smuller */ 50157501Smuller if (((pt->flgs & HASLOW) && 50257501Smuller (arcn->sb.st_mtime < pt->low_time) && 50357501Smuller (arcn->sb.st_ctime < pt->low_time)) || 50457501Smuller ((pt->flgs & HASHIGH) && 50557501Smuller (arcn->sb.st_mtime > pt->high_time) && 50657501Smuller (arcn->sb.st_ctime > pt->high_time))) { 50757196Smuller pt = pt->fow; 50857196Smuller continue; 50957196Smuller } 51057501Smuller break; 51157501Smuller case CMPCTME: 51257501Smuller /* 51357501Smuller * user wants only ctime checked for this time range 51457501Smuller */ 51557501Smuller if (((pt->flgs & HASLOW) && 51657501Smuller (arcn->sb.st_ctime < pt->low_time)) || 51757501Smuller ((pt->flgs & HASHIGH) && 51857501Smuller (arcn->sb.st_ctime > pt->high_time))) { 51957196Smuller pt = pt->fow; 52057196Smuller continue; 52157196Smuller } 52257501Smuller break; 52357501Smuller case CMPMTME: 52457501Smuller default: 52557501Smuller /* 52657501Smuller * user wants only mtime checked for this time range 52757501Smuller */ 52857501Smuller if (((pt->flgs & HASLOW) && 52957501Smuller (arcn->sb.st_mtime < pt->low_time)) || 53057501Smuller ((pt->flgs & HASHIGH) && 53157501Smuller (arcn->sb.st_mtime > pt->high_time))) { 53257501Smuller pt = pt->fow; 53357501Smuller continue; 53457501Smuller } 53557501Smuller break; 53657196Smuller } 53757196Smuller break; 53857196Smuller } 53957196Smuller 54057196Smuller if (pt == NULL) 54157196Smuller return(1); 54257196Smuller return(0); 54357196Smuller } 54457196Smuller 54557196Smuller /* 54657196Smuller * str_sec() 54757196Smuller * Convert a time string in the format of [yy[mm[dd[hh]]]]mm[.ss] to gmt 54857196Smuller * seconds. Tval already has current time loaded into it at entry. 54957196Smuller * Return: 55057196Smuller * 0 if converted ok, -1 otherwise 55157196Smuller */ 55257196Smuller 55357196Smuller #if __STDC__ 55457196Smuller static int 55557196Smuller str_sec(register char *str, time_t *tval) 55657196Smuller #else 55757196Smuller static int 55857196Smuller str_sec(str, tval) 55957196Smuller register char *str; 56057196Smuller time_t *tval; 56157196Smuller #endif 56257196Smuller { 56357196Smuller register struct tm *lt; 56457196Smuller register char *dot = NULL; 56557196Smuller 56657196Smuller lt = localtime(tval); 56757196Smuller if ((dot = index(str, '.')) != NULL) { 56857196Smuller /* 56957196Smuller * seconds (.ss) 57057196Smuller */ 57157196Smuller *dot++ = '\0'; 57257196Smuller if (strlen(dot) != 2) 57357196Smuller return(-1); 57457196Smuller if ((lt->tm_sec = ATOI2(dot)) > 61) 57557196Smuller return(-1); 57657196Smuller } else 57757196Smuller lt->tm_sec = 0; 57857196Smuller 57957196Smuller switch (strlen(str)) { 58057196Smuller case 10: 58157196Smuller /* 58257196Smuller * year (yy) 58357196Smuller * watch out for year 2000 58457196Smuller */ 58557196Smuller if ((lt->tm_year = ATOI2(str)) < 69) 58657196Smuller lt->tm_year += 100; 58757196Smuller str += 2; 58857196Smuller /* FALLTHROUGH */ 58957196Smuller case 8: 59057196Smuller /* 59157196Smuller * month (mm) 59257196Smuller * watch out months are from 0 - 11 internally 59357196Smuller */ 59457196Smuller if ((lt->tm_mon = ATOI2(str)) > 12) 59557196Smuller return(-1); 59657196Smuller --lt->tm_mon; 59757196Smuller str += 2; 59857196Smuller /* FALLTHROUGH */ 59957196Smuller case 6: 60057196Smuller /* 60157196Smuller * day (dd) 60257196Smuller */ 60357196Smuller if ((lt->tm_mday = ATOI2(str)) > 31) 60457196Smuller return(-1); 60557196Smuller str += 2; 60657196Smuller /* FALLTHROUGH */ 60757196Smuller case 4: 60857196Smuller /* 60957196Smuller * hour (hh) 61057196Smuller */ 61157196Smuller if ((lt->tm_hour = ATOI2(str)) > 23) 61257196Smuller return(-1); 61357196Smuller str += 2; 61457196Smuller /* FALLTHROUGH */ 61557196Smuller case 2: 61657196Smuller /* 61757196Smuller * minute (mm) 61857196Smuller */ 61957196Smuller if ((lt->tm_min = ATOI2(str)) > 59) 62057196Smuller return(-1); 62157196Smuller break; 62257196Smuller default: 62357196Smuller return(-1); 62457196Smuller } 62557196Smuller /* 62657196Smuller * convert broken-down time to GMT clock time seconds 62757196Smuller */ 62857196Smuller if ((*tval = mktime(lt)) == -1) 62957196Smuller return(-1); 63057196Smuller return(0); 63157196Smuller } 632