1*55449a4bSflorian /* $OpenBSD: sel_subs.c,v 1.29 2024/04/28 16:43:15 florian Exp $ */
2df930be7Sderaadt /* $NetBSD: sel_subs.c,v 1.5 1995/03/21 09:07:42 cgd Exp $ */
3df930be7Sderaadt
4df930be7Sderaadt /*-
5df930be7Sderaadt * Copyright (c) 1992 Keith Muller.
6df930be7Sderaadt * Copyright (c) 1992, 1993
7df930be7Sderaadt * The Regents of the University of California. All rights reserved.
8df930be7Sderaadt *
9df930be7Sderaadt * This code is derived from software contributed to Berkeley by
10df930be7Sderaadt * Keith Muller of the University of California, San Diego.
11df930be7Sderaadt *
12df930be7Sderaadt * Redistribution and use in source and binary forms, with or without
13df930be7Sderaadt * modification, are permitted provided that the following conditions
14df930be7Sderaadt * are met:
15df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright
16df930be7Sderaadt * notice, this list of conditions and the following disclaimer.
17df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright
18df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the
19df930be7Sderaadt * documentation and/or other materials provided with the distribution.
2029295d1cSmillert * 3. Neither the name of the University nor the names of its contributors
21df930be7Sderaadt * may be used to endorse or promote products derived from this software
22df930be7Sderaadt * without specific prior written permission.
23df930be7Sderaadt *
24df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34df930be7Sderaadt * SUCH DAMAGE.
35df930be7Sderaadt */
36df930be7Sderaadt
37df930be7Sderaadt #include <sys/types.h>
38df930be7Sderaadt #include <sys/stat.h>
39f04e0f38Smillert #include <ctype.h>
40df930be7Sderaadt #include <grp.h>
41f04e0f38Smillert #include <pwd.h>
42df930be7Sderaadt #include <stdio.h>
43df930be7Sderaadt #include <stdlib.h>
44f04e0f38Smillert #include <string.h>
453a135c23Sguenther #include <time.h>
463a135c23Sguenther
47df930be7Sderaadt #include "pax.h"
48df930be7Sderaadt #include "extern.h"
49df930be7Sderaadt
503a135c23Sguenther /*
513a135c23Sguenther * data structure for storing uid/grp selects (-U, -G non standard options)
523a135c23Sguenther */
533a135c23Sguenther
543a135c23Sguenther #define USR_TB_SZ 317 /* user selection table size */
553a135c23Sguenther #define GRP_TB_SZ 317 /* user selection table size */
563a135c23Sguenther
573a135c23Sguenther typedef struct usrt {
583a135c23Sguenther uid_t uid;
593a135c23Sguenther struct usrt *fow; /* next uid */
603a135c23Sguenther } USRT;
613a135c23Sguenther
623a135c23Sguenther typedef struct grpt {
633a135c23Sguenther gid_t gid;
643a135c23Sguenther struct grpt *fow; /* next gid */
653a135c23Sguenther } GRPT;
663a135c23Sguenther
673a135c23Sguenther /*
683a135c23Sguenther * data structure for storing user supplied time ranges (-T option)
693a135c23Sguenther */
703a135c23Sguenther
713a135c23Sguenther #define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2;
723a135c23Sguenther
733a135c23Sguenther typedef struct time_rng {
743a135c23Sguenther time_t low_time; /* lower inclusive time limit */
753a135c23Sguenther time_t high_time; /* higher inclusive time limit */
763a135c23Sguenther int flgs; /* option flags */
773a135c23Sguenther #define HASLOW 0x01 /* has lower time limit */
783a135c23Sguenther #define HASHIGH 0x02 /* has higher time limit */
793a135c23Sguenther #define CMPMTME 0x04 /* compare file modification time */
803a135c23Sguenther #define CMPCTME 0x08 /* compare inode change time */
813a135c23Sguenther #define CMPBOTH (CMPMTME|CMPCTME) /* compare inode and mod time */
823a135c23Sguenther struct time_rng *fow; /* next pattern */
833a135c23Sguenther } TIME_RNG;
843a135c23Sguenther
857097cf92Smillert static int str_sec(const char *, time_t *);
86be87792eSmillert static int usr_match(ARCHD *);
87be87792eSmillert static int grp_match(ARCHD *);
88be87792eSmillert static int trng_match(ARCHD *);
89df930be7Sderaadt
90df930be7Sderaadt static TIME_RNG *trhead = NULL; /* time range list head */
91df930be7Sderaadt static TIME_RNG *trtail = NULL; /* time range list tail */
92df930be7Sderaadt static USRT **usrtb = NULL; /* user selection table */
93df930be7Sderaadt static GRPT **grptb = NULL; /* group selection table */
94df930be7Sderaadt
95df930be7Sderaadt /*
96df930be7Sderaadt * Routines for selection of archive members
97df930be7Sderaadt */
98df930be7Sderaadt
99df930be7Sderaadt /*
100df930be7Sderaadt * sel_chk()
10108cab283Sjmc * check if this file matches a specified uid, gid or time range
102df930be7Sderaadt * Return:
103df930be7Sderaadt * 0 if this archive member should be processed, 1 if it should be skipped
104df930be7Sderaadt */
105df930be7Sderaadt
106df930be7Sderaadt int
sel_chk(ARCHD * arcn)107be87792eSmillert sel_chk(ARCHD *arcn)
108df930be7Sderaadt {
109df930be7Sderaadt if (((usrtb != NULL) && usr_match(arcn)) ||
110df930be7Sderaadt ((grptb != NULL) && grp_match(arcn)) ||
111df930be7Sderaadt ((trhead != NULL) && trng_match(arcn)))
112df930be7Sderaadt return(1);
113df930be7Sderaadt return(0);
114df930be7Sderaadt }
115df930be7Sderaadt
116df930be7Sderaadt /*
117df930be7Sderaadt * User/group selection routines
118df930be7Sderaadt *
119df930be7Sderaadt * Routines to handle user selection of files based on the file uid/gid. To
1204eb0b000Smillert * add an entry, the user supplies either the name or the uid/gid starting with
1214eb0b000Smillert * a # on the command line. A \# will escape the #.
122df930be7Sderaadt */
123df930be7Sderaadt
124df930be7Sderaadt /*
125df930be7Sderaadt * usr_add()
126df930be7Sderaadt * add a user match to the user match hash table
127df930be7Sderaadt * Return:
128df930be7Sderaadt * 0 if added ok, -1 otherwise;
129df930be7Sderaadt */
130df930be7Sderaadt
131df930be7Sderaadt int
usr_add(char * str)132be87792eSmillert usr_add(char *str)
133df930be7Sderaadt {
134be87792eSmillert u_int indx;
135be87792eSmillert USRT *pt;
136be87792eSmillert uid_t uid;
137df930be7Sderaadt
138df930be7Sderaadt /*
139df930be7Sderaadt * create the table if it doesn't exist
140df930be7Sderaadt */
141df930be7Sderaadt if ((str == NULL) || (*str == '\0'))
142df930be7Sderaadt return(-1);
143df930be7Sderaadt if ((usrtb == NULL) &&
144f38a3474Sguenther ((usrtb = calloc(USR_TB_SZ, sizeof(USRT *))) == NULL)) {
14542cf9836Stholo paxwarn(1, "Unable to allocate memory for user selection table");
146df930be7Sderaadt return(-1);
147df930be7Sderaadt }
148df930be7Sderaadt
149df930be7Sderaadt /*
150df930be7Sderaadt * figure out user spec
151df930be7Sderaadt */
152df930be7Sderaadt if (str[0] != '#') {
153df930be7Sderaadt /*
154df930be7Sderaadt * it is a user name, \# escapes # as first char in user name
155df930be7Sderaadt */
156df930be7Sderaadt if ((str[0] == '\\') && (str[1] == '#'))
157df930be7Sderaadt ++str;
1586ed32900Sderaadt if (uid_from_user(str, &uid) == -1) {
15942cf9836Stholo paxwarn(1, "Unable to find uid for user: %s", str);
160df930be7Sderaadt return(-1);
161df930be7Sderaadt }
162df930be7Sderaadt } else
1634bbb0cd1Skstailey uid = (uid_t)strtoul(str+1, NULL, 10);
164df930be7Sderaadt endpwent();
165df930be7Sderaadt
166df930be7Sderaadt /*
167df930be7Sderaadt * hash it and go down the hash chain (if any) looking for it
168df930be7Sderaadt */
169df930be7Sderaadt indx = ((unsigned)uid) % USR_TB_SZ;
170df930be7Sderaadt if ((pt = usrtb[indx]) != NULL) {
171df930be7Sderaadt while (pt != NULL) {
172df930be7Sderaadt if (pt->uid == uid)
173df930be7Sderaadt return(0);
174df930be7Sderaadt pt = pt->fow;
175df930be7Sderaadt }
176df930be7Sderaadt }
177df930be7Sderaadt
178df930be7Sderaadt /*
179df930be7Sderaadt * uid is not yet in the table, add it to the front of the chain
180df930be7Sderaadt */
181f38a3474Sguenther if ((pt = malloc(sizeof(USRT))) != NULL) {
182df930be7Sderaadt pt->uid = uid;
183df930be7Sderaadt pt->fow = usrtb[indx];
184df930be7Sderaadt usrtb[indx] = pt;
185df930be7Sderaadt return(0);
186df930be7Sderaadt }
18742cf9836Stholo paxwarn(1, "User selection table out of memory");
188df930be7Sderaadt return(-1);
189df930be7Sderaadt }
190df930be7Sderaadt
191df930be7Sderaadt /*
192df930be7Sderaadt * usr_match()
193df930be7Sderaadt * check if this files uid matches a selected uid.
194df930be7Sderaadt * Return:
195df930be7Sderaadt * 0 if this archive member should be processed, 1 if it should be skipped
196df930be7Sderaadt */
197df930be7Sderaadt
198df930be7Sderaadt static int
usr_match(ARCHD * arcn)199be87792eSmillert usr_match(ARCHD *arcn)
200df930be7Sderaadt {
201be87792eSmillert USRT *pt;
202df930be7Sderaadt
203df930be7Sderaadt /*
204df930be7Sderaadt * hash and look for it in the table
205df930be7Sderaadt */
206df930be7Sderaadt pt = usrtb[((unsigned)arcn->sb.st_uid) % USR_TB_SZ];
207df930be7Sderaadt while (pt != NULL) {
208df930be7Sderaadt if (pt->uid == arcn->sb.st_uid)
209df930be7Sderaadt return(0);
210df930be7Sderaadt pt = pt->fow;
211df930be7Sderaadt }
212df930be7Sderaadt
213df930be7Sderaadt /*
214df930be7Sderaadt * not found
215df930be7Sderaadt */
216df930be7Sderaadt return(1);
217df930be7Sderaadt }
218df930be7Sderaadt
219df930be7Sderaadt /*
220df930be7Sderaadt * grp_add()
221df930be7Sderaadt * add a group match to the group match hash table
222df930be7Sderaadt * Return:
223df930be7Sderaadt * 0 if added ok, -1 otherwise;
224df930be7Sderaadt */
225df930be7Sderaadt
226df930be7Sderaadt int
grp_add(char * str)227be87792eSmillert grp_add(char *str)
228df930be7Sderaadt {
229be87792eSmillert u_int indx;
230be87792eSmillert GRPT *pt;
231be87792eSmillert gid_t gid;
232df930be7Sderaadt
233df930be7Sderaadt /*
234df930be7Sderaadt * create the table if it doesn't exist
235df930be7Sderaadt */
236df930be7Sderaadt if ((str == NULL) || (*str == '\0'))
237df930be7Sderaadt return(-1);
238df930be7Sderaadt if ((grptb == NULL) &&
239f38a3474Sguenther ((grptb = calloc(GRP_TB_SZ, sizeof(GRPT *))) == NULL)) {
24042cf9836Stholo paxwarn(1, "Unable to allocate memory fo group selection table");
241df930be7Sderaadt return(-1);
242df930be7Sderaadt }
243df930be7Sderaadt
244df930be7Sderaadt /*
245f84583feSmillert * figure out group spec
246df930be7Sderaadt */
247df930be7Sderaadt if (str[0] != '#') {
248df930be7Sderaadt /*
249df930be7Sderaadt * it is a group name, \# escapes # as first char in group name
250df930be7Sderaadt */
251df930be7Sderaadt if ((str[0] == '\\') && (str[1] == '#'))
252df930be7Sderaadt ++str;
2536ed32900Sderaadt if (gid_from_group(str, &gid) == -1) {
25442cf9836Stholo paxwarn(1,"Cannot determine gid for group name: %s", str);
255df930be7Sderaadt return(-1);
256df930be7Sderaadt }
257df930be7Sderaadt } else
2584bbb0cd1Skstailey gid = (gid_t)strtoul(str+1, NULL, 10);
259df930be7Sderaadt endgrent();
260df930be7Sderaadt
261df930be7Sderaadt /*
262df930be7Sderaadt * hash it and go down the hash chain (if any) looking for it
263df930be7Sderaadt */
264df930be7Sderaadt indx = ((unsigned)gid) % GRP_TB_SZ;
265df930be7Sderaadt if ((pt = grptb[indx]) != NULL) {
266df930be7Sderaadt while (pt != NULL) {
267df930be7Sderaadt if (pt->gid == gid)
268df930be7Sderaadt return(0);
269df930be7Sderaadt pt = pt->fow;
270df930be7Sderaadt }
271df930be7Sderaadt }
272df930be7Sderaadt
273df930be7Sderaadt /*
274df930be7Sderaadt * gid not in the table, add it to the front of the chain
275df930be7Sderaadt */
276f38a3474Sguenther if ((pt = malloc(sizeof(GRPT))) != NULL) {
277df930be7Sderaadt pt->gid = gid;
278df930be7Sderaadt pt->fow = grptb[indx];
279df930be7Sderaadt grptb[indx] = pt;
280df930be7Sderaadt return(0);
281df930be7Sderaadt }
28242cf9836Stholo paxwarn(1, "Group selection table out of memory");
283df930be7Sderaadt return(-1);
284df930be7Sderaadt }
285df930be7Sderaadt
286df930be7Sderaadt /*
287df930be7Sderaadt * grp_match()
288df930be7Sderaadt * check if this files gid matches a selected gid.
289df930be7Sderaadt * Return:
290df930be7Sderaadt * 0 if this archive member should be processed, 1 if it should be skipped
291df930be7Sderaadt */
292df930be7Sderaadt
293df930be7Sderaadt static int
grp_match(ARCHD * arcn)294be87792eSmillert grp_match(ARCHD *arcn)
295df930be7Sderaadt {
296be87792eSmillert GRPT *pt;
297df930be7Sderaadt
298df930be7Sderaadt /*
299df930be7Sderaadt * hash and look for it in the table
300df930be7Sderaadt */
301df930be7Sderaadt pt = grptb[((unsigned)arcn->sb.st_gid) % GRP_TB_SZ];
302df930be7Sderaadt while (pt != NULL) {
303df930be7Sderaadt if (pt->gid == arcn->sb.st_gid)
304df930be7Sderaadt return(0);
305df930be7Sderaadt pt = pt->fow;
306df930be7Sderaadt }
307df930be7Sderaadt
308df930be7Sderaadt /*
309df930be7Sderaadt * not found
310df930be7Sderaadt */
311df930be7Sderaadt return(1);
312df930be7Sderaadt }
313df930be7Sderaadt
314df930be7Sderaadt /*
315df930be7Sderaadt * Time range selection routines
316df930be7Sderaadt *
317df930be7Sderaadt * Routines to handle user selection of files based on the modification and/or
318df930be7Sderaadt * inode change time falling within a specified time range (the non-standard
319df930be7Sderaadt * -T flag). The user may specify any number of different file time ranges.
320df930be7Sderaadt * Time ranges are checked one at a time until a match is found (if at all).
321df930be7Sderaadt * If the file has a mtime (and/or ctime) which lies within one of the time
322df930be7Sderaadt * ranges, the file is selected. Time ranges may have a lower and/or a upper
323df930be7Sderaadt * value. These ranges are inclusive. When no time ranges are supplied to pax
324df930be7Sderaadt * with the -T option, all members in the archive will be selected by the time
325df930be7Sderaadt * range routines. When only a lower range is supplied, only files with a
326df930be7Sderaadt * mtime (and/or ctime) equal to or younger are selected. When only a upper
327df930be7Sderaadt * range is supplied, only files with a mtime (and/or ctime) equal to or older
328df930be7Sderaadt * are selected. When the lower time range is equal to the upper time range,
329df930be7Sderaadt * only files with a mtime (or ctime) of exactly that time are selected.
330df930be7Sderaadt */
331df930be7Sderaadt
332df930be7Sderaadt /*
333df930be7Sderaadt * trng_add()
334df930be7Sderaadt * add a time range match to the time range list.
335df930be7Sderaadt * This is a non-standard pax option. Lower and upper ranges are in the
336f04e0f38Smillert * format: [[[[[cc]yy]mm]dd]HH]MM[.SS] and are comma separated.
337df930be7Sderaadt * Time ranges are based on current time, so 1234 would specify a time of
338df930be7Sderaadt * 12:34 today.
339df930be7Sderaadt * Return:
340df930be7Sderaadt * 0 if the time range was added to the list, -1 otherwise
341df930be7Sderaadt */
342df930be7Sderaadt
343df930be7Sderaadt int
trng_add(char * str)344be87792eSmillert trng_add(char *str)
345df930be7Sderaadt {
346be87792eSmillert TIME_RNG *pt;
347be87792eSmillert char *up_pt = NULL;
348be87792eSmillert char *stpt;
349be87792eSmillert char *flgpt;
350be87792eSmillert int dot = 0;
351df930be7Sderaadt
352df930be7Sderaadt /*
353df930be7Sderaadt * throw out the badly formed time ranges
354df930be7Sderaadt */
355df930be7Sderaadt if ((str == NULL) || (*str == '\0')) {
35642cf9836Stholo paxwarn(1, "Empty time range string");
357df930be7Sderaadt return(-1);
358df930be7Sderaadt }
359df930be7Sderaadt
360df930be7Sderaadt /*
361df930be7Sderaadt * locate optional flags suffix /{cm}.
362df930be7Sderaadt */
363df930be7Sderaadt if ((flgpt = strrchr(str, '/')) != NULL)
364df930be7Sderaadt *flgpt++ = '\0';
365df930be7Sderaadt
366df930be7Sderaadt for (stpt = str; *stpt != '\0'; ++stpt) {
367df930be7Sderaadt if ((*stpt >= '0') && (*stpt <= '9'))
368df930be7Sderaadt continue;
369df930be7Sderaadt if ((*stpt == ',') && (up_pt == NULL)) {
370df930be7Sderaadt *stpt = '\0';
371df930be7Sderaadt up_pt = stpt + 1;
372df930be7Sderaadt dot = 0;
373df930be7Sderaadt continue;
374df930be7Sderaadt }
375df930be7Sderaadt
376df930be7Sderaadt /*
377df930be7Sderaadt * allow only one dot per range (secs)
378df930be7Sderaadt */
379df930be7Sderaadt if ((*stpt == '.') && (!dot)) {
380df930be7Sderaadt ++dot;
381df930be7Sderaadt continue;
382df930be7Sderaadt }
38342cf9836Stholo paxwarn(1, "Improperly specified time range: %s", str);
384df930be7Sderaadt goto out;
385df930be7Sderaadt }
386df930be7Sderaadt
387df930be7Sderaadt /*
388df930be7Sderaadt * allocate space for the time range and store the limits
389df930be7Sderaadt */
390f38a3474Sguenther if ((pt = malloc(sizeof(TIME_RNG))) == NULL) {
39142cf9836Stholo paxwarn(1, "Unable to allocate memory for time range");
392df930be7Sderaadt return(-1);
393df930be7Sderaadt }
394df930be7Sderaadt
395df930be7Sderaadt /*
396ec95929aSmillert * by default we only will check file mtime, but user can specify
397df930be7Sderaadt * mtime, ctime (inode change time) or both.
398df930be7Sderaadt */
399df930be7Sderaadt if ((flgpt == NULL) || (*flgpt == '\0'))
400df930be7Sderaadt pt->flgs = CMPMTME;
401df930be7Sderaadt else {
402df930be7Sderaadt pt->flgs = 0;
403df930be7Sderaadt while (*flgpt != '\0') {
404df930be7Sderaadt switch (*flgpt) {
405df930be7Sderaadt case 'M':
406df930be7Sderaadt case 'm':
407df930be7Sderaadt pt->flgs |= CMPMTME;
408df930be7Sderaadt break;
409df930be7Sderaadt case 'C':
410df930be7Sderaadt case 'c':
411df930be7Sderaadt pt->flgs |= CMPCTME;
412df930be7Sderaadt break;
413df930be7Sderaadt default:
41442cf9836Stholo paxwarn(1, "Bad option %c with time range %s",
415df930be7Sderaadt *flgpt, str);
416f38a3474Sguenther free(pt);
417df930be7Sderaadt goto out;
418df930be7Sderaadt }
419df930be7Sderaadt ++flgpt;
420df930be7Sderaadt }
421df930be7Sderaadt }
422df930be7Sderaadt
423df930be7Sderaadt /*
424df930be7Sderaadt * start off with the current time
425df930be7Sderaadt */
4264bbb0cd1Skstailey pt->low_time = pt->high_time = time(NULL);
427df930be7Sderaadt if (*str != '\0') {
428df930be7Sderaadt /*
429df930be7Sderaadt * add lower limit
430df930be7Sderaadt */
431df930be7Sderaadt if (str_sec(str, &(pt->low_time)) < 0) {
43242cf9836Stholo paxwarn(1, "Illegal lower time range %s", str);
433f38a3474Sguenther free(pt);
434df930be7Sderaadt goto out;
435df930be7Sderaadt }
436df930be7Sderaadt pt->flgs |= HASLOW;
437df930be7Sderaadt }
438df930be7Sderaadt
439df930be7Sderaadt if ((up_pt != NULL) && (*up_pt != '\0')) {
440df930be7Sderaadt /*
441df930be7Sderaadt * add upper limit
442df930be7Sderaadt */
443df930be7Sderaadt if (str_sec(up_pt, &(pt->high_time)) < 0) {
44442cf9836Stholo paxwarn(1, "Illegal upper time range %s", up_pt);
445f38a3474Sguenther free(pt);
446df930be7Sderaadt goto out;
447df930be7Sderaadt }
448df930be7Sderaadt pt->flgs |= HASHIGH;
449df930be7Sderaadt
450df930be7Sderaadt /*
451df930be7Sderaadt * check that the upper and lower do not overlap
452df930be7Sderaadt */
453df930be7Sderaadt if (pt->flgs & HASLOW) {
454df930be7Sderaadt if (pt->low_time > pt->high_time) {
45542cf9836Stholo paxwarn(1, "Upper %s and lower %s time overlap",
456df930be7Sderaadt up_pt, str);
457f38a3474Sguenther free(pt);
458df930be7Sderaadt return(-1);
459df930be7Sderaadt }
460df930be7Sderaadt }
461df930be7Sderaadt }
462df930be7Sderaadt
463df930be7Sderaadt pt->fow = NULL;
464df930be7Sderaadt if (trhead == NULL) {
465df930be7Sderaadt trtail = trhead = pt;
466df930be7Sderaadt return(0);
467df930be7Sderaadt }
468df930be7Sderaadt trtail->fow = pt;
469df930be7Sderaadt trtail = pt;
470df930be7Sderaadt return(0);
471df930be7Sderaadt
472df930be7Sderaadt out:
473f04e0f38Smillert paxwarn(1, "Time range format is: [[[[[cc]yy]mm]dd]HH]MM[.SS][/[c][m]]");
474df930be7Sderaadt return(-1);
475df930be7Sderaadt }
476df930be7Sderaadt
477df930be7Sderaadt /*
478df930be7Sderaadt * trng_match()
479df930be7Sderaadt * check if this files mtime/ctime falls within any supplied time range.
480df930be7Sderaadt * Return:
481df930be7Sderaadt * 0 if this archive member should be processed, 1 if it should be skipped
482df930be7Sderaadt */
483df930be7Sderaadt
484df930be7Sderaadt static int
trng_match(ARCHD * arcn)485be87792eSmillert trng_match(ARCHD *arcn)
486df930be7Sderaadt {
487be87792eSmillert TIME_RNG *pt;
488df930be7Sderaadt
489df930be7Sderaadt /*
490df930be7Sderaadt * have to search down the list one at a time looking for a match.
491df930be7Sderaadt * remember time range limits are inclusive.
492df930be7Sderaadt */
493df930be7Sderaadt pt = trhead;
494df930be7Sderaadt while (pt != NULL) {
495df930be7Sderaadt switch (pt->flgs & CMPBOTH) {
496df930be7Sderaadt case CMPBOTH:
497df930be7Sderaadt /*
498df930be7Sderaadt * user wants both mtime and ctime checked for this
499df930be7Sderaadt * time range
500df930be7Sderaadt */
501df930be7Sderaadt if (((pt->flgs & HASLOW) &&
502df930be7Sderaadt (arcn->sb.st_mtime < pt->low_time) &&
503df930be7Sderaadt (arcn->sb.st_ctime < pt->low_time)) ||
504df930be7Sderaadt ((pt->flgs & HASHIGH) &&
505df930be7Sderaadt (arcn->sb.st_mtime > pt->high_time) &&
506df930be7Sderaadt (arcn->sb.st_ctime > pt->high_time))) {
507df930be7Sderaadt pt = pt->fow;
508df930be7Sderaadt continue;
509df930be7Sderaadt }
510df930be7Sderaadt break;
511df930be7Sderaadt case CMPCTME:
512df930be7Sderaadt /*
513df930be7Sderaadt * user wants only ctime checked for this time range
514df930be7Sderaadt */
515df930be7Sderaadt if (((pt->flgs & HASLOW) &&
516df930be7Sderaadt (arcn->sb.st_ctime < pt->low_time)) ||
517df930be7Sderaadt ((pt->flgs & HASHIGH) &&
518df930be7Sderaadt (arcn->sb.st_ctime > pt->high_time))) {
519df930be7Sderaadt pt = pt->fow;
520df930be7Sderaadt continue;
521df930be7Sderaadt }
522df930be7Sderaadt break;
523df930be7Sderaadt case CMPMTME:
524df930be7Sderaadt default:
525df930be7Sderaadt /*
526df930be7Sderaadt * user wants only mtime checked for this time range
527df930be7Sderaadt */
528df930be7Sderaadt if (((pt->flgs & HASLOW) &&
529df930be7Sderaadt (arcn->sb.st_mtime < pt->low_time)) ||
530df930be7Sderaadt ((pt->flgs & HASHIGH) &&
531df930be7Sderaadt (arcn->sb.st_mtime > pt->high_time))) {
532df930be7Sderaadt pt = pt->fow;
533df930be7Sderaadt continue;
534df930be7Sderaadt }
535df930be7Sderaadt break;
536df930be7Sderaadt }
537df930be7Sderaadt break;
538df930be7Sderaadt }
539df930be7Sderaadt
540df930be7Sderaadt if (pt == NULL)
541df930be7Sderaadt return(1);
542df930be7Sderaadt return(0);
543df930be7Sderaadt }
544df930be7Sderaadt
545df930be7Sderaadt /*
546df930be7Sderaadt * str_sec()
547f04e0f38Smillert * Convert a time string in the format of [[[[[cc]yy]mm]dd]HH]MM[.SS] to
5484eb0b000Smillert * seconds UTC. Tval already has current time loaded into it at entry.
549df930be7Sderaadt * Return:
550df930be7Sderaadt * 0 if converted ok, -1 otherwise
551df930be7Sderaadt */
552df930be7Sderaadt
553df930be7Sderaadt static int
str_sec(const char * p,time_t * tval)5547097cf92Smillert str_sec(const char *p, time_t *tval)
555df930be7Sderaadt {
556be87792eSmillert struct tm *lt;
5577097cf92Smillert const char *dot, *t;
5587097cf92Smillert size_t len;
559f04e0f38Smillert int bigyear;
5607097cf92Smillert int yearset;
5617097cf92Smillert
5627097cf92Smillert yearset = 0;
5637097cf92Smillert len = strlen(p);
564f04e0f38Smillert
565f04e0f38Smillert for (t = p, dot = NULL; *t; ++t) {
566cd3e3e8cSderaadt if (isdigit((unsigned char)*t))
567f04e0f38Smillert continue;
568f04e0f38Smillert if (*t == '.' && dot == NULL) {
569f04e0f38Smillert dot = t;
570f04e0f38Smillert continue;
571f04e0f38Smillert }
572f04e0f38Smillert return(-1);
573f04e0f38Smillert }
574df930be7Sderaadt
575*55449a4bSflorian if ((lt = localtime(tval)) == NULL)
576*55449a4bSflorian return (-1);
577f04e0f38Smillert
578f04e0f38Smillert if (dot != NULL) { /* .SS */
5797097cf92Smillert if (strlen(++dot) != 2)
580df930be7Sderaadt return(-1);
581f04e0f38Smillert lt->tm_sec = ATOI2(dot);
582f04e0f38Smillert if (lt->tm_sec > 61)
583df930be7Sderaadt return(-1);
5847097cf92Smillert len -= 3;
585df930be7Sderaadt } else
586df930be7Sderaadt lt->tm_sec = 0;
587df930be7Sderaadt
5887097cf92Smillert switch (len) {
589f04e0f38Smillert case 12: /* cc */
590f04e0f38Smillert bigyear = ATOI2(p);
5910240030dSguenther lt->tm_year = (bigyear * 100) - 1900;
592f04e0f38Smillert yearset = 1;
593df930be7Sderaadt /* FALLTHROUGH */
594f04e0f38Smillert case 10: /* yy */
595f04e0f38Smillert if (yearset) {
596f04e0f38Smillert lt->tm_year += ATOI2(p);
597f04e0f38Smillert } else {
598f04e0f38Smillert lt->tm_year = ATOI2(p);
599f04e0f38Smillert if (lt->tm_year < 69) /* hack for 2000 ;-} */
6000240030dSguenther lt->tm_year += (2000 - 1900);
601f04e0f38Smillert }
602f04e0f38Smillert /* FALLTHROUGH */
603f04e0f38Smillert case 8: /* mm */
604f04e0f38Smillert lt->tm_mon = ATOI2(p);
605f04e0f38Smillert if ((lt->tm_mon > 12) || !lt->tm_mon)
606df930be7Sderaadt return(-1);
607f04e0f38Smillert --lt->tm_mon; /* time struct is 0 - 11 */
608df930be7Sderaadt /* FALLTHROUGH */
609f04e0f38Smillert case 6: /* dd */
610f04e0f38Smillert lt->tm_mday = ATOI2(p);
611f04e0f38Smillert if ((lt->tm_mday > 31) || !lt->tm_mday)
612df930be7Sderaadt return(-1);
613df930be7Sderaadt /* FALLTHROUGH */
614f04e0f38Smillert case 4: /* HH */
615f04e0f38Smillert lt->tm_hour = ATOI2(p);
616f04e0f38Smillert if (lt->tm_hour > 23)
617df930be7Sderaadt return(-1);
618df930be7Sderaadt /* FALLTHROUGH */
619f04e0f38Smillert case 2: /* MM */
620f04e0f38Smillert lt->tm_min = ATOI2(p);
621f04e0f38Smillert if (lt->tm_min > 59)
622df930be7Sderaadt return(-1);
623df930be7Sderaadt break;
624df930be7Sderaadt default:
625df930be7Sderaadt return(-1);
626df930be7Sderaadt }
627f04e0f38Smillert
628f04e0f38Smillert /* convert broken-down time to UTC clock time seconds */
629df930be7Sderaadt if ((*tval = mktime(lt)) == -1)
630df930be7Sderaadt return(-1);
631df930be7Sderaadt return(0);
632df930be7Sderaadt }
633