sel_subs.c revision 331722
1163953Srrs/*- 2169382Srrs * Copyright (c) 1992 Keith Muller. 3235828Stuexen * Copyright (c) 1992, 1993 4235828Stuexen * The Regents of the University of California. All rights reserved. 5163953Srrs * 6163953Srrs * This code is derived from software contributed to Berkeley by 7163953Srrs * Keith Muller of the University of California, San Diego. 8163953Srrs * 9163953Srrs * Redistribution and use in source and binary forms, with or without 10228653Stuexen * modification, are permitted provided that the following conditions 11163953Srrs * are met: 12163953Srrs * 1. Redistributions of source code must retain the above copyright 13163953Srrs * notice, this list of conditions and the following disclaimer. 14228653Stuexen * 2. Redistributions in binary form must reproduce the above copyright 15163953Srrs * notice, this list of conditions and the following disclaimer in the 16163953Srrs * documentation and/or other materials provided with the distribution. 17163953Srrs * 4. Neither the name of the University nor the names of its contributors 18163953Srrs * may be used to endorse or promote products derived from this software 19163953Srrs * without specific prior written permission. 20163953Srrs * 21163953Srrs * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22163953Srrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23163953Srrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24163953Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25163953Srrs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26163953Srrs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27163953Srrs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28163953Srrs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29163953Srrs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30163953Srrs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31163953Srrs * SUCH DAMAGE. 32163953Srrs */ 33163953Srrs 34163953Srrs#ifndef lint 35163953Srrs#if 0 36235828Stuexenstatic char sccsid[] = "@(#)sel_subs.c 8.1 (Berkeley) 5/31/93"; 37235828Stuexen#endif 38163953Srrs#endif /* not lint */ 39163953Srrs#include <sys/cdefs.h> 40163953Srrs__FBSDID("$FreeBSD: stable/11/bin/pax/sel_subs.c 331722 2018-03-29 02:50:57Z eadler $"); 41163953Srrs 42163953Srrs#include <sys/types.h> 43179783Srrs#include <sys/time.h> 44170606Srrs#include <sys/stat.h> 45163953Srrs#include <pwd.h> 46163953Srrs#include <grp.h> 47163953Srrs#include <stdio.h> 48163953Srrs#include <string.h> 49163953Srrs#include <strings.h> 50163953Srrs#include <stdlib.h> 51170606Srrs#include "pax.h" 52163953Srrs#include "sel_subs.h" 53167598Srrs#include "extern.h" 54167598Srrs 55167598Srrsstatic int str_sec(char *, time_t *); 56163953Srrsstatic int usr_match(ARCHD *); 57163953Srrsstatic int grp_match(ARCHD *); 58167598Srrsstatic int trng_match(ARCHD *); 59170606Srrs 60163953Srrsstatic TIME_RNG *trhead = NULL; /* time range list head */ 61163953Srrsstatic TIME_RNG *trtail = NULL; /* time range list tail */ 62163953Srrsstatic USRT **usrtb = NULL; /* user selection table */ 63163953Srrsstatic GRPT **grptb = NULL; /* group selection table */ 64163953Srrs 65203847Stuexen/* 66163953Srrs * Routines for selection of archive members 67167598Srrs */ 68163953Srrs 69163953Srrs/* 70163953Srrs * sel_chk() 71167598Srrs * check if this file matches a specified uid, gid or time range 72170606Srrs * Return: 73163953Srrs * 0 if this archive member should be processed, 1 if it should be skipped 74169208Srrs */ 75169208Srrs 76169208Srrsint 77169208Srrssel_chk(ARCHD *arcn) 78169208Srrs{ 79163953Srrs if (((usrtb != NULL) && usr_match(arcn)) || 80163953Srrs ((grptb != NULL) && grp_match(arcn)) || 81163953Srrs ((trhead != NULL) && trng_match(arcn))) 82228031Stuexen return(1); 83170606Srrs return(0); 84163953Srrs} 85163953Srrs 86163953Srrs/* 87163953Srrs * User/group selection routines 88163953Srrs * 89163953Srrs * Routines to handle user selection of files based on the file uid/gid. To 90163953Srrs * add an entry, the user supplies either then name or the uid/gid starting with 91163953Srrs * a # on the command line. A \# will escape the #. 92163953Srrs */ 93163953Srrs 94224641Stuexen/* 95224641Stuexen * usr_add() 96163953Srrs * add a user match to the user match hash table 97170606Srrs * Return: 98163953Srrs * 0 if added ok, -1 otherwise; 99163953Srrs */ 100163953Srrs 101163953Srrsint 102163953Srrsusr_add(char *str) 103163953Srrs{ 104170606Srrs u_int indx; 105163953Srrs USRT *pt; 106163953Srrs struct passwd *pw; 107163953Srrs uid_t uid; 108163953Srrs 109163953Srrs /* 110163953Srrs * create the table if it doesn't exist 111170606Srrs */ 112163953Srrs if ((str == NULL) || (*str == '\0')) 113163953Srrs return(-1); 114163953Srrs if ((usrtb == NULL) && 115163953Srrs ((usrtb = (USRT **)calloc(USR_TB_SZ, sizeof(USRT *))) == NULL)) { 116170606Srrs paxwarn(1, "Unable to allocate memory for user selection table"); 117163953Srrs return(-1); 118185694Srrs } 119185694Srrs 120185694Srrs /* 121185694Srrs * figure out user spec 122185694Srrs */ 123185694Srrs if (str[0] != '#') { 124185694Srrs /* 125185694Srrs * it is a user name, \# escapes # as first char in user name 126163953Srrs */ 127163953Srrs if ((str[0] == '\\') && (str[1] == '#')) 128163953Srrs ++str; 129170606Srrs if ((pw = getpwnam(str)) == NULL) { 130163953Srrs paxwarn(1, "Unable to find uid for user: %s", str); 131169208Srrs return(-1); 132169208Srrs } 133163953Srrs uid = (uid_t)pw->pw_uid; 134163953Srrs } else 135202782Stuexen# ifdef NET2_STAT 136170606Srrs uid = (uid_t)atoi(str+1); 137163953Srrs# else 138163953Srrs uid = (uid_t)strtoul(str+1, NULL, 10); 139163953Srrs# endif 140163953Srrs endpwent(); 141163953Srrs 142163953Srrs /* 143163953Srrs * hash it and go down the hash chain (if any) looking for it 144163953Srrs */ 145163953Srrs indx = ((unsigned)uid) % USR_TB_SZ; 146163953Srrs if ((pt = usrtb[indx]) != NULL) { 147163953Srrs while (pt != NULL) { 148170606Srrs if (pt->uid == uid) 149163953Srrs return(0); 150163953Srrs pt = pt->fow; 151163953Srrs } 152163953Srrs } 153170606Srrs 154163953Srrs /* 155297662Srrs * uid is not yet in the table, add it to the front of the chain 156297662Srrs */ 157297662Srrs if ((pt = (USRT *)malloc(sizeof(USRT))) != NULL) { 158297662Srrs pt->uid = uid; 159297662Srrs pt->fow = usrtb[indx]; 160297662Srrs usrtb[indx] = pt; 161297662Srrs return(0); 162297662Srrs } 163298187Stuexen paxwarn(1, "User selection table out of memory"); 164297662Srrs return(-1); 165297662Srrs} 166297662Srrs 167297662Srrs/* 168297662Srrs * usr_match() 169297662Srrs * check if this files uid matches a selected uid. 170297662Srrs * Return: 171297662Srrs * 0 if this archive member should be processed, 1 if it should be skipped 172163953Srrs */ 173163953Srrs 174163953Srrsstatic int 175163953Srrsusr_match(ARCHD *arcn) 176163953Srrs{ 177163953Srrs USRT *pt; 178163953Srrs 179163953Srrs /* 180163953Srrs * hash and look for it in the table 181163953Srrs */ 182163953Srrs pt = usrtb[((unsigned)arcn->sb.st_uid) % USR_TB_SZ]; 183163953Srrs while (pt != NULL) { 184170606Srrs if (pt->uid == arcn->sb.st_uid) 185163953Srrs return(0); 186167598Srrs pt = pt->fow; 187167598Srrs } 188170606Srrs 189163953Srrs /* 190163953Srrs * not found 191167598Srrs */ 192170606Srrs return(1); 193163953Srrs} 194163953Srrs 195170606Srrs/* 196163953Srrs * grp_add() 197163953Srrs * add a group match to the group match hash table 198170606Srrs * Return: 199163953Srrs * 0 if added ok, -1 otherwise; 200167598Srrs */ 201163953Srrs 202167598Srrsint 203163953Srrsgrp_add(char *str) 204163953Srrs{ 205170606Srrs u_int indx; 206163953Srrs GRPT *pt; 207163953Srrs struct group *gr; 208163953Srrs gid_t gid; 209163953Srrs 210163953Srrs /* 211163953Srrs * create the table if it doesn't exist 212170606Srrs */ 213163953Srrs if ((str == NULL) || (*str == '\0')) 214163953Srrs return(-1); 215170606Srrs if ((grptb == NULL) && 216163953Srrs ((grptb = (GRPT **)calloc(GRP_TB_SZ, sizeof(GRPT *))) == NULL)) { 217163953Srrs paxwarn(1, "Unable to allocate memory fo group selection table"); 218163953Srrs return(-1); 219163953Srrs } 220170606Srrs 221163953Srrs /* 222163953Srrs * figure out user spec 223163953Srrs */ 224163953Srrs if (str[0] != '#') { 225163953Srrs /* 226170606Srrs * it is a group name, \# escapes # as first char in group name 227163953Srrs */ 228163953Srrs if ((str[0] == '\\') && (str[1] == '#')) 229163953Srrs ++str; 230163953Srrs if ((gr = getgrnam(str)) == NULL) { 231170606Srrs paxwarn(1,"Cannot determine gid for group name: %s", str); 232163953Srrs return(-1); 233163953Srrs } 234163953Srrs gid = gr->gr_gid; 235163953Srrs } else 236170606Srrs# ifdef NET2_STAT 237163953Srrs gid = (gid_t)atoi(str+1); 238163953Srrs# else 239163953Srrs gid = (gid_t)strtoul(str+1, NULL, 10); 240163953Srrs# endif 241163953Srrs endgrent(); 242163953Srrs 243163953Srrs /* 244163953Srrs * hash it and go down the hash chain (if any) looking for it 245163953Srrs */ 246163953Srrs indx = ((unsigned)gid) % GRP_TB_SZ; 247163953Srrs if ((pt = grptb[indx]) != NULL) { 248170606Srrs while (pt != NULL) { 249163953Srrs if (pt->gid == gid) 250163953Srrs return(0); 251163953Srrs pt = pt->fow; 252163953Srrs } 253163953Srrs } 254163953Srrs 255163953Srrs /* 256163953Srrs * gid not in the table, add it to the front of the chain 257170606Srrs */ 258163953Srrs if ((pt = (GRPT *)malloc(sizeof(GRPT))) != NULL) { 259163953Srrs pt->gid = gid; 260163953Srrs pt->fow = grptb[indx]; 261163953Srrs grptb[indx] = pt; 262170606Srrs return(0); 263163953Srrs } 264185694Srrs paxwarn(1, "Group selection table out of memory"); 265185694Srrs return(-1); 266185694Srrs} 267185694Srrs 268185694Srrs/* 269185694Srrs * grp_match() 270185694Srrs * check if this files gid matches a selected gid. 271185694Srrs * Return: 272185694Srrs * 0 if this archive member should be processed, 1 if it should be skipped 273185694Srrs */ 274185694Srrs 275185694Srrsstatic int 276185694Srrsgrp_match(ARCHD *arcn) 277185694Srrs{ 278185694Srrs GRPT *pt; 279185694Srrs 280185694Srrs /* 281163953Srrs * hash and look for it in the table 282163953Srrs */ 283163953Srrs pt = grptb[((unsigned)arcn->sb.st_gid) % GRP_TB_SZ]; 284170606Srrs while (pt != NULL) { 285163953Srrs if (pt->gid == arcn->sb.st_gid) 286163953Srrs return(0); 287163953Srrs pt = pt->fow; 288163953Srrs } 289170606Srrs 290163953Srrs /* 291163953Srrs * not found 292163953Srrs */ 293163953Srrs return(1); 294163953Srrs} 295163953Srrs 296163953Srrs/* 297163953Srrs * Time range selection routines 298163953Srrs * 299163953Srrs * Routines to handle user selection of files based on the modification and/or 300170606Srrs * inode change time falling within a specified time range (the non-standard 301163953Srrs * -T flag). The user may specify any number of different file time ranges. 302163953Srrs * Time ranges are checked one at a time until a match is found (if at all). 303163953Srrs * If the file has a mtime (and/or ctime) which lies within one of the time 304163953Srrs * ranges, the file is selected. Time ranges may have a lower and/or an upper 305170606Srrs * value. These ranges are inclusive. When no time ranges are supplied to pax 306163953Srrs * with the -T option, all members in the archive will be selected by the time 307163953Srrs * range routines. When only a lower range is supplied, only files with a 308163953Srrs * mtime (and/or ctime) equal to or younger are selected. When only an upper 309163953Srrs * range is supplied, only files with a mtime (and/or ctime) equal to or older 310163953Srrs * are selected. When the lower time range is equal to the upper time range, 311163953Srrs * only files with a mtime (or ctime) of exactly that time are selected. 312170606Srrs */ 313163953Srrs 314163953Srrs/* 315163953Srrs * trng_add() 316163953Srrs * add a time range match to the time range list. 317163953Srrs * This is a non-standard pax option. Lower and upper ranges are in the 318170606Srrs * format: [yy[mm[dd[hh]]]]mm[.ss] and are comma separated. 319163953Srrs * Time ranges are based on current time, so 1234 would specify a time of 320163953Srrs * 12:34 today. 321163953Srrs * Return: 322163953Srrs * 0 if the time range was added to the list, -1 otherwise 323163953Srrs */ 324163953Srrs 325170606Srrsint 326163953Srrstrng_add(char *str) 327163953Srrs{ 328163953Srrs TIME_RNG *pt; 329163953Srrs char *up_pt = NULL; 330163953Srrs char *stpt; 331163953Srrs char *flgpt; 332170606Srrs int dot = 0; 333163953Srrs 334163953Srrs /* 335163953Srrs * throw out the badly formed time ranges 336163953Srrs */ 337170606Srrs if ((str == NULL) || (*str == '\0')) { 338163953Srrs paxwarn(1, "Empty time range string"); 339163953Srrs return(-1); 340218072Srrs } 341218072Srrs 342218072Srrs /* 343218072Srrs * locate optional flags suffix /{cm}. 344218072Srrs */ 345163953Srrs if ((flgpt = strrchr(str, '/')) != NULL) 346163953Srrs *flgpt++ = '\0'; 347163953Srrs 348218072Srrs for (stpt = str; *stpt != '\0'; ++stpt) { 349170606Srrs if ((*stpt >= '0') && (*stpt <= '9')) 350163953Srrs continue; 351163953Srrs if ((*stpt == ',') && (up_pt == NULL)) { 352163953Srrs *stpt = '\0'; 353163953Srrs up_pt = stpt + 1; 354163953Srrs dot = 0; 355170606Srrs continue; 356163953Srrs } 357163953Srrs 358163953Srrs /* 359163953Srrs * allow only one dot per range (secs) 360170606Srrs */ 361163953Srrs if ((*stpt == '.') && (!dot)) { 362163953Srrs ++dot; 363163953Srrs continue; 364163953Srrs } 365170606Srrs paxwarn(1, "Improperly specified time range: %s", str); 366163953Srrs goto out; 367163953Srrs } 368163953Srrs 369163953Srrs /* 370163953Srrs * allocate space for the time range and store the limits 371163953Srrs */ 372163953Srrs if ((pt = (TIME_RNG *)malloc(sizeof(TIME_RNG))) == NULL) { 373163953Srrs paxwarn(1, "Unable to allocate memory for time range"); 374163953Srrs return(-1); 375163953Srrs } 376170606Srrs 377163953Srrs /* 378163953Srrs * by default we only will check file mtime, but the user can specify 379163953Srrs * mtime, ctime (inode change time) or both. 380163953Srrs */ 381163953Srrs if ((flgpt == NULL) || (*flgpt == '\0')) 382163953Srrs pt->flgs = CMPMTME; 383170606Srrs else { 384163953Srrs pt->flgs = 0; 385163953Srrs while (*flgpt != '\0') { 386163953Srrs switch(*flgpt) { 387163953Srrs case 'M': 388163953Srrs case 'm': 389163953Srrs pt->flgs |= CMPMTME; 390163953Srrs break; 391170606Srrs case 'C': 392163953Srrs case 'c': 393163953Srrs pt->flgs |= CMPCTME; 394163953Srrs break; 395163953Srrs default: 396170606Srrs paxwarn(1, "Bad option %c with time range %s", 397163953Srrs *flgpt, str); 398297662Srrs free(pt); 399297662Srrs goto out; 400297662Srrs } 401297662Srrs ++flgpt; 402297662Srrs } 403297662Srrs } 404163953Srrs 405163953Srrs /* 406163953Srrs * start off with the current time 407170606Srrs */ 408163953Srrs pt->low_time = pt->high_time = time(NULL); 409163953Srrs if (*str != '\0') { 410163953Srrs /* 411163953Srrs * add lower limit 412163953Srrs */ 413163953Srrs if (str_sec(str, &(pt->low_time)) < 0) { 414163953Srrs paxwarn(1, "Illegal lower time range %s", str); 415163953Srrs free(pt); 416163953Srrs goto out; 417170606Srrs } 418163953Srrs pt->flgs |= HASLOW; 419163953Srrs } 420163953Srrs 421163953Srrs if ((up_pt != NULL) && (*up_pt != '\0')) { 422163953Srrs /* 423163953Srrs * add upper limit 424163953Srrs */ 425163953Srrs if (str_sec(up_pt, &(pt->high_time)) < 0) { 426202782Stuexen paxwarn(1, "Illegal upper time range %s", up_pt); 427170606Srrs free(pt); 428163953Srrs goto out; 429163953Srrs } 430163953Srrs pt->flgs |= HASHIGH; 431273168Stuexen 432273168Stuexen /* 433273168Stuexen * check that the upper and lower do not overlap 434273168Stuexen */ 435273168Stuexen if (pt->flgs & HASLOW) { 436163953Srrs if (pt->low_time > pt->high_time) { 437163953Srrs paxwarn(1, "Upper %s and lower %s time overlap", 438163953Srrs up_pt, str); 439163953Srrs free(pt); 440163953Srrs return(-1); 441202782Stuexen } 442170606Srrs } 443163953Srrs } 444163953Srrs 445163953Srrs pt->fow = NULL; 446163953Srrs if (trhead == NULL) { 447202782Stuexen trtail = trhead = pt; 448170606Srrs return(0); 449163953Srrs } 450163953Srrs trtail->fow = pt; 451163953Srrs trtail = pt; 452163953Srrs return(0); 453170606Srrs 454163953Srrs out: 455163953Srrs paxwarn(1, "Time range format is: [yy[mm[dd[hh]]]]mm[.ss][/[c][m]]"); 456163953Srrs return(-1); 457163953Srrs} 458163953Srrs 459170606Srrs/* 460163953Srrs * trng_match() 461163953Srrs * check if this files mtime/ctime falls within any supplied time range. 462163953Srrs * Return: 463163953Srrs * 0 if this archive member should be processed, 1 if it should be skipped 464163953Srrs */ 465163953Srrs 466163953Srrsstatic int 467170606Srrstrng_match(ARCHD *arcn) 468163953Srrs{ 469188854Srrs TIME_RNG *pt; 470188854Srrs 471188854Srrs /* 472188854Srrs * have to search down the list one at a time looking for a match. 473188854Srrs * remember time range limits are inclusive. 474203847Stuexen */ 475163953Srrs pt = trhead; 476235064Stuexen while (pt != NULL) { 477235064Stuexen switch(pt->flgs & CMPBOTH) { 478235064Stuexen case CMPBOTH: 479235064Stuexen /* 480235064Stuexen * user wants both mtime and ctime checked for this 481235064Stuexen * time range 482235064Stuexen */ 483163953Srrs if (((pt->flgs & HASLOW) && 484163953Srrs (arcn->sb.st_mtime < pt->low_time) && 485163953Srrs (arcn->sb.st_ctime < pt->low_time)) || 486163953Srrs ((pt->flgs & HASHIGH) && 487163953Srrs (arcn->sb.st_mtime > pt->high_time) && 488163953Srrs (arcn->sb.st_ctime > pt->high_time))) { 489163953Srrs pt = pt->fow; 490163953Srrs continue; 491163953Srrs } 492170606Srrs break; 493163953Srrs case CMPCTME: 494163953Srrs /* 495163953Srrs * user wants only ctime checked for this time range 496163953Srrs */ 497170606Srrs if (((pt->flgs & HASLOW) && 498163953Srrs (arcn->sb.st_ctime < pt->low_time)) || 499163953Srrs ((pt->flgs & HASHIGH) && 500163953Srrs (arcn->sb.st_ctime > pt->high_time))) { 501163953Srrs pt = pt->fow; 502163953Srrs continue; 503170606Srrs } 504163953Srrs break; 505163953Srrs case CMPMTME: 506163953Srrs default: 507163953Srrs /* 508163953Srrs * user wants only mtime checked for this time range 509163953Srrs */ 510169208Srrs if (((pt->flgs & HASLOW) && 511169208Srrs (arcn->sb.st_mtime < pt->low_time)) || 512169208Srrs ((pt->flgs & HASHIGH) && 513163953Srrs (arcn->sb.st_mtime > pt->high_time))) { 514163953Srrs pt = pt->fow; 515202782Stuexen continue; 516170606Srrs } 517163953Srrs break; 518163953Srrs } 519163953Srrs break; 520202782Stuexen } 521170606Srrs 522163953Srrs if (pt == NULL) 523163953Srrs return(1); 524163953Srrs return(0); 525202782Stuexen} 526170606Srrs 527163953Srrs/* 528163953Srrs * str_sec() 529163953Srrs * Convert a time string in the format of [yy[mm[dd[hh]]]]mm[.ss] to gmt 530163953Srrs * seconds. Tval already has current time loaded into it at entry. 531163953Srrs * Return: 532202782Stuexen * 0 if converted ok, -1 otherwise 533170606Srrs */ 534163953Srrs 535163953Srrsstatic int 536163953Srrsstr_sec(char *str, time_t *tval) 537163953Srrs{ 538163953Srrs struct tm *lt; 539163953Srrs char *dot = NULL; 540163953Srrs 541163953Srrs lt = localtime(tval); 542163953Srrs if ((dot = strchr(str, '.')) != NULL) { 543163953Srrs /* 544167598Srrs * seconds (.ss) 545163953Srrs */ 546163953Srrs *dot++ = '\0'; 547163953Srrs if (strlen(dot) != 2) 548163953Srrs return(-1); 549163953Srrs if ((lt->tm_sec = ATOI2(dot)) > 61) 550163953Srrs return(-1); 551163953Srrs } else 552163953Srrs lt->tm_sec = 0; 553163953Srrs 554163953Srrs switch (strlen(str)) { 555163953Srrs case 10: 556163953Srrs /* 557163953Srrs * year (yy) 558163953Srrs * watch out for year 2000 559163953Srrs */ 560163953Srrs if ((lt->tm_year = ATOI2(str)) < 69) 561163953Srrs lt->tm_year += 100; 562163953Srrs str += 2; 563163953Srrs /* FALLTHROUGH */ 564163953Srrs case 8: 565163953Srrs /* 566163953Srrs * month (mm) 567163953Srrs * watch out months are from 0 - 11 internally 568163953Srrs */ 569163953Srrs if ((lt->tm_mon = ATOI2(str)) > 12) 570163953Srrs return(-1); 571163953Srrs --lt->tm_mon; 572163953Srrs str += 2; 573163953Srrs /* FALLTHROUGH */ 574167598Srrs case 6: 575163953Srrs /* 576163953Srrs * day (dd) 577163953Srrs */ 578163953Srrs if ((lt->tm_mday = ATOI2(str)) > 31) 579163953Srrs return(-1); 580163953Srrs str += 2; 581163953Srrs /* FALLTHROUGH */ 582163953Srrs case 4: 583163953Srrs /* 584179783Srrs * hour (hh) 585163953Srrs */ 586 if ((lt->tm_hour = ATOI2(str)) > 23) 587 return(-1); 588 str += 2; 589 /* FALLTHROUGH */ 590 case 2: 591 /* 592 * minute (mm) 593 */ 594 if ((lt->tm_min = ATOI2(str)) > 59) 595 return(-1); 596 break; 597 default: 598 return(-1); 599 } 600 /* 601 * convert broken-down time to GMT clock time seconds 602 */ 603 if ((*tval = mktime(lt)) == -1) 604 return(-1); 605 return(0); 606} 607