11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1992 Keith Muller. 31556Srgrimes * Copyright (c) 1992, 1993 41556Srgrimes * The Regents of the University of California. All rights reserved. 51556Srgrimes * 61556Srgrimes * This code is derived from software contributed to Berkeley by 71556Srgrimes * Keith Muller of the University of California, San Diego. 81556Srgrimes * 91556Srgrimes * Redistribution and use in source and binary forms, with or without 101556Srgrimes * modification, are permitted provided that the following conditions 111556Srgrimes * are met: 121556Srgrimes * 1. Redistributions of source code must retain the above copyright 131556Srgrimes * notice, this list of conditions and the following disclaimer. 141556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 151556Srgrimes * notice, this list of conditions and the following disclaimer in the 161556Srgrimes * documentation and/or other materials provided with the distribution. 171556Srgrimes * 4. Neither the name of the University nor the names of its contributors 181556Srgrimes * may be used to endorse or promote products derived from this software 191556Srgrimes * without specific prior written permission. 201556Srgrimes * 211556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311556Srgrimes * SUCH DAMAGE. 321556Srgrimes */ 331556Srgrimes 341556Srgrimes#ifndef lint 3536049Scharnier#if 0 3636049Scharnierstatic char sccsid[] = "@(#)sel_subs.c 8.1 (Berkeley) 5/31/93"; 3736049Scharnier#endif 381556Srgrimes#endif /* not lint */ 3999110Sobrien#include <sys/cdefs.h> 4099110Sobrien__FBSDID("$FreeBSD$"); 411556Srgrimes 421556Srgrimes#include <sys/types.h> 431556Srgrimes#include <sys/time.h> 441556Srgrimes#include <sys/stat.h> 451556Srgrimes#include <pwd.h> 461556Srgrimes#include <grp.h> 471556Srgrimes#include <stdio.h> 481556Srgrimes#include <string.h> 491556Srgrimes#include <strings.h> 501556Srgrimes#include <unistd.h> 511556Srgrimes#include <stdlib.h> 521556Srgrimes#include "pax.h" 531556Srgrimes#include "sel_subs.h" 541556Srgrimes#include "extern.h" 551556Srgrimes 5690113Simpstatic int str_sec(char *, time_t *); 5790113Simpstatic int usr_match(ARCHD *); 5890113Simpstatic int grp_match(ARCHD *); 5990113Simpstatic int trng_match(ARCHD *); 601556Srgrimes 611556Srgrimesstatic TIME_RNG *trhead = NULL; /* time range list head */ 621556Srgrimesstatic TIME_RNG *trtail = NULL; /* time range list tail */ 631556Srgrimesstatic USRT **usrtb = NULL; /* user selection table */ 641556Srgrimesstatic GRPT **grptb = NULL; /* group selection table */ 651556Srgrimes 661556Srgrimes/* 671556Srgrimes * Routines for selection of archive members 681556Srgrimes */ 691556Srgrimes 701556Srgrimes/* 711556Srgrimes * sel_chk() 7246684Skris * check if this file matches a specified uid, gid or time range 731556Srgrimes * Return: 741556Srgrimes * 0 if this archive member should be processed, 1 if it should be skipped 751556Srgrimes */ 761556Srgrimes 771556Srgrimesint 7890113Simpsel_chk(ARCHD *arcn) 791556Srgrimes{ 801556Srgrimes if (((usrtb != NULL) && usr_match(arcn)) || 811556Srgrimes ((grptb != NULL) && grp_match(arcn)) || 821556Srgrimes ((trhead != NULL) && trng_match(arcn))) 831556Srgrimes return(1); 841556Srgrimes return(0); 851556Srgrimes} 861556Srgrimes 871556Srgrimes/* 881556Srgrimes * User/group selection routines 891556Srgrimes * 901556Srgrimes * Routines to handle user selection of files based on the file uid/gid. To 911556Srgrimes * add an entry, the user supplies either then name or the uid/gid starting with 9246684Skris * a # on the command line. A \# will escape the #. 931556Srgrimes */ 941556Srgrimes 951556Srgrimes/* 961556Srgrimes * usr_add() 971556Srgrimes * add a user match to the user match hash table 981556Srgrimes * Return: 991556Srgrimes * 0 if added ok, -1 otherwise; 1001556Srgrimes */ 1011556Srgrimes 1021556Srgrimesint 10390113Simpusr_add(char *str) 1041556Srgrimes{ 10590113Simp u_int indx; 10690113Simp USRT *pt; 10790113Simp struct passwd *pw; 10890113Simp uid_t uid; 1091556Srgrimes 1101556Srgrimes /* 1111556Srgrimes * create the table if it doesn't exist 1121556Srgrimes */ 1131556Srgrimes if ((str == NULL) || (*str == '\0')) 1141556Srgrimes return(-1); 1151556Srgrimes if ((usrtb == NULL) && 1161556Srgrimes ((usrtb = (USRT **)calloc(USR_TB_SZ, sizeof(USRT *))) == NULL)) { 11776019Skris paxwarn(1, "Unable to allocate memory for user selection table"); 11876019Skris return(-1); 1191556Srgrimes } 1201556Srgrimes 1211556Srgrimes /* 1221556Srgrimes * figure out user spec 1231556Srgrimes */ 1241556Srgrimes if (str[0] != '#') { 1251556Srgrimes /* 1261556Srgrimes * it is a user name, \# escapes # as first char in user name 1271556Srgrimes */ 1281556Srgrimes if ((str[0] == '\\') && (str[1] == '#')) 1291556Srgrimes ++str; 1301556Srgrimes if ((pw = getpwnam(str)) == NULL) { 13176019Skris paxwarn(1, "Unable to find uid for user: %s", str); 13276019Skris return(-1); 1331556Srgrimes } 1341556Srgrimes uid = (uid_t)pw->pw_uid; 13576019Skris } else 1361556Srgrimes# ifdef NET2_STAT 1371556Srgrimes uid = (uid_t)atoi(str+1); 1381556Srgrimes# else 13976017Skris uid = (uid_t)strtoul(str+1, NULL, 10); 1401556Srgrimes# endif 1411556Srgrimes endpwent(); 1421556Srgrimes 1431556Srgrimes /* 1441556Srgrimes * hash it and go down the hash chain (if any) looking for it 1451556Srgrimes */ 1461556Srgrimes indx = ((unsigned)uid) % USR_TB_SZ; 1471556Srgrimes if ((pt = usrtb[indx]) != NULL) { 14876019Skris while (pt != NULL) { 14976019Skris if (pt->uid == uid) 1501556Srgrimes return(0); 15176019Skris pt = pt->fow; 15276019Skris } 1531556Srgrimes } 1541556Srgrimes 1551556Srgrimes /* 1561556Srgrimes * uid is not yet in the table, add it to the front of the chain 1571556Srgrimes */ 1581556Srgrimes if ((pt = (USRT *)malloc(sizeof(USRT))) != NULL) { 1591556Srgrimes pt->uid = uid; 1601556Srgrimes pt->fow = usrtb[indx]; 1611556Srgrimes usrtb[indx] = pt; 1621556Srgrimes return(0); 1631556Srgrimes } 16476019Skris paxwarn(1, "User selection table out of memory"); 16576019Skris return(-1); 1661556Srgrimes} 1671556Srgrimes 1681556Srgrimes/* 1691556Srgrimes * usr_match() 1701556Srgrimes * check if this files uid matches a selected uid. 1711556Srgrimes * Return: 1721556Srgrimes * 0 if this archive member should be processed, 1 if it should be skipped 1731556Srgrimes */ 1741556Srgrimes 1751556Srgrimesstatic int 17690113Simpusr_match(ARCHD *arcn) 1771556Srgrimes{ 17890113Simp USRT *pt; 1791556Srgrimes 1801556Srgrimes /* 1811556Srgrimes * hash and look for it in the table 1821556Srgrimes */ 1831556Srgrimes pt = usrtb[((unsigned)arcn->sb.st_uid) % USR_TB_SZ]; 1841556Srgrimes while (pt != NULL) { 1851556Srgrimes if (pt->uid == arcn->sb.st_uid) 1861556Srgrimes return(0); 1871556Srgrimes pt = pt->fow; 1881556Srgrimes } 1891556Srgrimes 1901556Srgrimes /* 1911556Srgrimes * not found 1921556Srgrimes */ 1931556Srgrimes return(1); 1941556Srgrimes} 1951556Srgrimes 1961556Srgrimes/* 1971556Srgrimes * grp_add() 1981556Srgrimes * add a group match to the group match hash table 1991556Srgrimes * Return: 2001556Srgrimes * 0 if added ok, -1 otherwise; 2011556Srgrimes */ 2021556Srgrimes 2031556Srgrimesint 20490113Simpgrp_add(char *str) 2051556Srgrimes{ 20690113Simp u_int indx; 20790113Simp GRPT *pt; 20890113Simp struct group *gr; 20990113Simp gid_t gid; 2101556Srgrimes 2111556Srgrimes /* 2121556Srgrimes * create the table if it doesn't exist 2131556Srgrimes */ 2141556Srgrimes if ((str == NULL) || (*str == '\0')) 2151556Srgrimes return(-1); 2161556Srgrimes if ((grptb == NULL) && 2171556Srgrimes ((grptb = (GRPT **)calloc(GRP_TB_SZ, sizeof(GRPT *))) == NULL)) { 21876019Skris paxwarn(1, "Unable to allocate memory fo group selection table"); 21976019Skris return(-1); 2201556Srgrimes } 2211556Srgrimes 2221556Srgrimes /* 2231556Srgrimes * figure out user spec 2241556Srgrimes */ 2251556Srgrimes if (str[0] != '#') { 2261556Srgrimes /* 2271556Srgrimes * it is a group name, \# escapes # as first char in group name 2281556Srgrimes */ 2291556Srgrimes if ((str[0] == '\\') && (str[1] == '#')) 2301556Srgrimes ++str; 2311556Srgrimes if ((gr = getgrnam(str)) == NULL) { 23276019Skris paxwarn(1,"Cannot determine gid for group name: %s", str); 23376019Skris return(-1); 2341556Srgrimes } 23592956Smarkm gid = gr->gr_gid; 23676019Skris } else 2371556Srgrimes# ifdef NET2_STAT 2381556Srgrimes gid = (gid_t)atoi(str+1); 2391556Srgrimes# else 24076017Skris gid = (gid_t)strtoul(str+1, NULL, 10); 2411556Srgrimes# endif 2421556Srgrimes endgrent(); 2431556Srgrimes 2441556Srgrimes /* 2451556Srgrimes * hash it and go down the hash chain (if any) looking for it 2461556Srgrimes */ 2471556Srgrimes indx = ((unsigned)gid) % GRP_TB_SZ; 2481556Srgrimes if ((pt = grptb[indx]) != NULL) { 24976019Skris while (pt != NULL) { 25076019Skris if (pt->gid == gid) 2511556Srgrimes return(0); 25276019Skris pt = pt->fow; 25376019Skris } 2541556Srgrimes } 2551556Srgrimes 2561556Srgrimes /* 2571556Srgrimes * gid not in the table, add it to the front of the chain 2581556Srgrimes */ 2591556Srgrimes if ((pt = (GRPT *)malloc(sizeof(GRPT))) != NULL) { 2601556Srgrimes pt->gid = gid; 2611556Srgrimes pt->fow = grptb[indx]; 2621556Srgrimes grptb[indx] = pt; 2631556Srgrimes return(0); 2641556Srgrimes } 26576019Skris paxwarn(1, "Group selection table out of memory"); 26676019Skris return(-1); 2671556Srgrimes} 2681556Srgrimes 2691556Srgrimes/* 2701556Srgrimes * grp_match() 2711556Srgrimes * check if this files gid matches a selected gid. 2721556Srgrimes * Return: 2731556Srgrimes * 0 if this archive member should be processed, 1 if it should be skipped 2741556Srgrimes */ 2751556Srgrimes 2761556Srgrimesstatic int 27790113Simpgrp_match(ARCHD *arcn) 2781556Srgrimes{ 27990113Simp GRPT *pt; 2801556Srgrimes 2811556Srgrimes /* 2821556Srgrimes * hash and look for it in the table 2831556Srgrimes */ 2841556Srgrimes pt = grptb[((unsigned)arcn->sb.st_gid) % GRP_TB_SZ]; 2851556Srgrimes while (pt != NULL) { 2861556Srgrimes if (pt->gid == arcn->sb.st_gid) 2871556Srgrimes return(0); 2881556Srgrimes pt = pt->fow; 2891556Srgrimes } 2901556Srgrimes 2911556Srgrimes /* 2921556Srgrimes * not found 2931556Srgrimes */ 2941556Srgrimes return(1); 2951556Srgrimes} 2961556Srgrimes 2971556Srgrimes/* 2981556Srgrimes * Time range selection routines 2991556Srgrimes * 3001556Srgrimes * Routines to handle user selection of files based on the modification and/or 3011556Srgrimes * inode change time falling within a specified time range (the non-standard 3021556Srgrimes * -T flag). The user may specify any number of different file time ranges. 3031556Srgrimes * Time ranges are checked one at a time until a match is found (if at all). 3041556Srgrimes * If the file has a mtime (and/or ctime) which lies within one of the time 305108533Sschweikh * ranges, the file is selected. Time ranges may have a lower and/or an upper 3061556Srgrimes * value. These ranges are inclusive. When no time ranges are supplied to pax 3071556Srgrimes * with the -T option, all members in the archive will be selected by the time 3081556Srgrimes * range routines. When only a lower range is supplied, only files with a 309108533Sschweikh * mtime (and/or ctime) equal to or younger are selected. When only an upper 3101556Srgrimes * range is supplied, only files with a mtime (and/or ctime) equal to or older 3111556Srgrimes * are selected. When the lower time range is equal to the upper time range, 3121556Srgrimes * only files with a mtime (or ctime) of exactly that time are selected. 3131556Srgrimes */ 3141556Srgrimes 3151556Srgrimes/* 3161556Srgrimes * trng_add() 3171556Srgrimes * add a time range match to the time range list. 3181556Srgrimes * This is a non-standard pax option. Lower and upper ranges are in the 3191556Srgrimes * format: [yy[mm[dd[hh]]]]mm[.ss] and are comma separated. 3201556Srgrimes * Time ranges are based on current time, so 1234 would specify a time of 3211556Srgrimes * 12:34 today. 3221556Srgrimes * Return: 3231556Srgrimes * 0 if the time range was added to the list, -1 otherwise 3241556Srgrimes */ 3251556Srgrimes 3261556Srgrimesint 32790113Simptrng_add(char *str) 3281556Srgrimes{ 32990113Simp TIME_RNG *pt; 33090113Simp char *up_pt = NULL; 33190113Simp char *stpt; 33290113Simp char *flgpt; 33390113Simp int dot = 0; 3341556Srgrimes 3351556Srgrimes /* 3361556Srgrimes * throw out the badly formed time ranges 3371556Srgrimes */ 3381556Srgrimes if ((str == NULL) || (*str == '\0')) { 33976017Skris paxwarn(1, "Empty time range string"); 3401556Srgrimes return(-1); 3411556Srgrimes } 3421556Srgrimes 3431556Srgrimes /* 3441556Srgrimes * locate optional flags suffix /{cm}. 3451556Srgrimes */ 34676017Skris if ((flgpt = strrchr(str, '/')) != NULL) 3471556Srgrimes *flgpt++ = '\0'; 3481556Srgrimes 3491556Srgrimes for (stpt = str; *stpt != '\0'; ++stpt) { 3501556Srgrimes if ((*stpt >= '0') && (*stpt <= '9')) 3511556Srgrimes continue; 3521556Srgrimes if ((*stpt == ',') && (up_pt == NULL)) { 3531556Srgrimes *stpt = '\0'; 3541556Srgrimes up_pt = stpt + 1; 3551556Srgrimes dot = 0; 3561556Srgrimes continue; 3571556Srgrimes } 3581556Srgrimes 3591556Srgrimes /* 3601556Srgrimes * allow only one dot per range (secs) 3611556Srgrimes */ 3621556Srgrimes if ((*stpt == '.') && (!dot)) { 3631556Srgrimes ++dot; 3641556Srgrimes continue; 3651556Srgrimes } 36676017Skris paxwarn(1, "Improperly specified time range: %s", str); 3671556Srgrimes goto out; 3681556Srgrimes } 3691556Srgrimes 3701556Srgrimes /* 3711556Srgrimes * allocate space for the time range and store the limits 3721556Srgrimes */ 3731556Srgrimes if ((pt = (TIME_RNG *)malloc(sizeof(TIME_RNG))) == NULL) { 37476017Skris paxwarn(1, "Unable to allocate memory for time range"); 3751556Srgrimes return(-1); 3761556Srgrimes } 3771556Srgrimes 3781556Srgrimes /* 379222177Suqs * by default we only will check file mtime, but the user can specify 3801556Srgrimes * mtime, ctime (inode change time) or both. 3811556Srgrimes */ 3821556Srgrimes if ((flgpt == NULL) || (*flgpt == '\0')) 3831556Srgrimes pt->flgs = CMPMTME; 3841556Srgrimes else { 3851556Srgrimes pt->flgs = 0; 3861556Srgrimes while (*flgpt != '\0') { 3871556Srgrimes switch(*flgpt) { 3881556Srgrimes case 'M': 3891556Srgrimes case 'm': 3901556Srgrimes pt->flgs |= CMPMTME; 3911556Srgrimes break; 3921556Srgrimes case 'C': 3931556Srgrimes case 'c': 3941556Srgrimes pt->flgs |= CMPCTME; 3951556Srgrimes break; 3961556Srgrimes default: 39776017Skris paxwarn(1, "Bad option %c with time range %s", 3981556Srgrimes *flgpt, str); 399200794Sdelphij free(pt); 4001556Srgrimes goto out; 4011556Srgrimes } 4021556Srgrimes ++flgpt; 4031556Srgrimes } 4041556Srgrimes } 4051556Srgrimes 4061556Srgrimes /* 4071556Srgrimes * start off with the current time 4081556Srgrimes */ 40976017Skris pt->low_time = pt->high_time = time(NULL); 4101556Srgrimes if (*str != '\0') { 4111556Srgrimes /* 4121556Srgrimes * add lower limit 4131556Srgrimes */ 4141556Srgrimes if (str_sec(str, &(pt->low_time)) < 0) { 41576017Skris paxwarn(1, "Illegal lower time range %s", str); 416169993Sbrian free(pt); 4171556Srgrimes goto out; 4181556Srgrimes } 4191556Srgrimes pt->flgs |= HASLOW; 4201556Srgrimes } 4211556Srgrimes 4221556Srgrimes if ((up_pt != NULL) && (*up_pt != '\0')) { 4231556Srgrimes /* 4241556Srgrimes * add upper limit 4251556Srgrimes */ 4261556Srgrimes if (str_sec(up_pt, &(pt->high_time)) < 0) { 42776017Skris paxwarn(1, "Illegal upper time range %s", up_pt); 428169993Sbrian free(pt); 4291556Srgrimes goto out; 4301556Srgrimes } 4311556Srgrimes pt->flgs |= HASHIGH; 4321556Srgrimes 4331556Srgrimes /* 4341556Srgrimes * check that the upper and lower do not overlap 4351556Srgrimes */ 4361556Srgrimes if (pt->flgs & HASLOW) { 4371556Srgrimes if (pt->low_time > pt->high_time) { 43876017Skris paxwarn(1, "Upper %s and lower %s time overlap", 4391556Srgrimes up_pt, str); 440169993Sbrian free(pt); 4411556Srgrimes return(-1); 4421556Srgrimes } 4431556Srgrimes } 4441556Srgrimes } 4451556Srgrimes 4461556Srgrimes pt->fow = NULL; 4471556Srgrimes if (trhead == NULL) { 4481556Srgrimes trtail = trhead = pt; 4491556Srgrimes return(0); 4501556Srgrimes } 4511556Srgrimes trtail->fow = pt; 4521556Srgrimes trtail = pt; 4531556Srgrimes return(0); 4541556Srgrimes 4551556Srgrimes out: 45676017Skris paxwarn(1, "Time range format is: [yy[mm[dd[hh]]]]mm[.ss][/[c][m]]"); 4571556Srgrimes return(-1); 4581556Srgrimes} 4591556Srgrimes 4601556Srgrimes/* 4611556Srgrimes * trng_match() 4621556Srgrimes * check if this files mtime/ctime falls within any supplied time range. 4631556Srgrimes * Return: 4641556Srgrimes * 0 if this archive member should be processed, 1 if it should be skipped 4651556Srgrimes */ 4661556Srgrimes 4671556Srgrimesstatic int 46890113Simptrng_match(ARCHD *arcn) 4691556Srgrimes{ 47090113Simp TIME_RNG *pt; 4711556Srgrimes 4721556Srgrimes /* 4731556Srgrimes * have to search down the list one at a time looking for a match. 4741556Srgrimes * remember time range limits are inclusive. 4751556Srgrimes */ 4761556Srgrimes pt = trhead; 4771556Srgrimes while (pt != NULL) { 4781556Srgrimes switch(pt->flgs & CMPBOTH) { 4791556Srgrimes case CMPBOTH: 4801556Srgrimes /* 4811556Srgrimes * user wants both mtime and ctime checked for this 4821556Srgrimes * time range 4831556Srgrimes */ 4841556Srgrimes if (((pt->flgs & HASLOW) && 4851556Srgrimes (arcn->sb.st_mtime < pt->low_time) && 4861556Srgrimes (arcn->sb.st_ctime < pt->low_time)) || 4871556Srgrimes ((pt->flgs & HASHIGH) && 4881556Srgrimes (arcn->sb.st_mtime > pt->high_time) && 4891556Srgrimes (arcn->sb.st_ctime > pt->high_time))) { 4901556Srgrimes pt = pt->fow; 4911556Srgrimes continue; 4921556Srgrimes } 4931556Srgrimes break; 4941556Srgrimes case CMPCTME: 4951556Srgrimes /* 4961556Srgrimes * user wants only ctime checked for this time range 4971556Srgrimes */ 4981556Srgrimes if (((pt->flgs & HASLOW) && 4991556Srgrimes (arcn->sb.st_ctime < pt->low_time)) || 5001556Srgrimes ((pt->flgs & HASHIGH) && 5011556Srgrimes (arcn->sb.st_ctime > pt->high_time))) { 5021556Srgrimes pt = pt->fow; 5031556Srgrimes continue; 5041556Srgrimes } 5051556Srgrimes break; 5061556Srgrimes case CMPMTME: 5071556Srgrimes default: 5081556Srgrimes /* 5091556Srgrimes * user wants only mtime checked for this time range 5101556Srgrimes */ 5111556Srgrimes if (((pt->flgs & HASLOW) && 5121556Srgrimes (arcn->sb.st_mtime < pt->low_time)) || 5131556Srgrimes ((pt->flgs & HASHIGH) && 5141556Srgrimes (arcn->sb.st_mtime > pt->high_time))) { 5151556Srgrimes pt = pt->fow; 5161556Srgrimes continue; 5171556Srgrimes } 5181556Srgrimes break; 5191556Srgrimes } 5201556Srgrimes break; 5211556Srgrimes } 5221556Srgrimes 5231556Srgrimes if (pt == NULL) 5241556Srgrimes return(1); 5251556Srgrimes return(0); 5261556Srgrimes} 5271556Srgrimes 5281556Srgrimes/* 5291556Srgrimes * str_sec() 5301556Srgrimes * Convert a time string in the format of [yy[mm[dd[hh]]]]mm[.ss] to gmt 5311556Srgrimes * seconds. Tval already has current time loaded into it at entry. 5321556Srgrimes * Return: 5331556Srgrimes * 0 if converted ok, -1 otherwise 5341556Srgrimes */ 5351556Srgrimes 5361556Srgrimesstatic int 53790113Simpstr_sec(char *str, time_t *tval) 5381556Srgrimes{ 53990113Simp struct tm *lt; 54090113Simp char *dot = NULL; 5411556Srgrimes 5421556Srgrimes lt = localtime(tval); 54376017Skris if ((dot = strchr(str, '.')) != NULL) { 5441556Srgrimes /* 5451556Srgrimes * seconds (.ss) 5461556Srgrimes */ 5471556Srgrimes *dot++ = '\0'; 5481556Srgrimes if (strlen(dot) != 2) 5491556Srgrimes return(-1); 5501556Srgrimes if ((lt->tm_sec = ATOI2(dot)) > 61) 5511556Srgrimes return(-1); 5521556Srgrimes } else 5531556Srgrimes lt->tm_sec = 0; 5541556Srgrimes 5551556Srgrimes switch (strlen(str)) { 5561556Srgrimes case 10: 5571556Srgrimes /* 5581556Srgrimes * year (yy) 5591556Srgrimes * watch out for year 2000 5601556Srgrimes */ 5611556Srgrimes if ((lt->tm_year = ATOI2(str)) < 69) 5621556Srgrimes lt->tm_year += 100; 5631556Srgrimes str += 2; 5641556Srgrimes /* FALLTHROUGH */ 5651556Srgrimes case 8: 5661556Srgrimes /* 5671556Srgrimes * month (mm) 5681556Srgrimes * watch out months are from 0 - 11 internally 5691556Srgrimes */ 5701556Srgrimes if ((lt->tm_mon = ATOI2(str)) > 12) 5711556Srgrimes return(-1); 5721556Srgrimes --lt->tm_mon; 5731556Srgrimes str += 2; 5741556Srgrimes /* FALLTHROUGH */ 5751556Srgrimes case 6: 5761556Srgrimes /* 5771556Srgrimes * day (dd) 5781556Srgrimes */ 5791556Srgrimes if ((lt->tm_mday = ATOI2(str)) > 31) 5801556Srgrimes return(-1); 5811556Srgrimes str += 2; 5821556Srgrimes /* FALLTHROUGH */ 5831556Srgrimes case 4: 5841556Srgrimes /* 5851556Srgrimes * hour (hh) 5861556Srgrimes */ 5871556Srgrimes if ((lt->tm_hour = ATOI2(str)) > 23) 5881556Srgrimes return(-1); 5891556Srgrimes str += 2; 5901556Srgrimes /* FALLTHROUGH */ 5911556Srgrimes case 2: 5921556Srgrimes /* 5931556Srgrimes * minute (mm) 5941556Srgrimes */ 5951556Srgrimes if ((lt->tm_min = ATOI2(str)) > 59) 5961556Srgrimes return(-1); 5971556Srgrimes break; 5981556Srgrimes default: 5991556Srgrimes return(-1); 6001556Srgrimes } 6011556Srgrimes /* 6021556Srgrimes * convert broken-down time to GMT clock time seconds 6031556Srgrimes */ 6041556Srgrimes if ((*tval = mktime(lt)) == -1) 6051556Srgrimes return(-1); 6061556Srgrimes return(0); 6071556Srgrimes} 608