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