1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 24*7c478bd9Sstevel@tonic-gate 25*7c478bd9Sstevel@tonic-gate 26*7c478bd9Sstevel@tonic-gate /* 27*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 28*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 29*7c478bd9Sstevel@tonic-gate */ 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate #include <sys/resource.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 35*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate #include <dirent.h> 38*7c478bd9Sstevel@tonic-gate #include <string.h> 39*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 40*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 41*7c478bd9Sstevel@tonic-gate #include <pwd.h> 42*7c478bd9Sstevel@tonic-gate #include <stdio.h> 43*7c478bd9Sstevel@tonic-gate #include <ctype.h> 44*7c478bd9Sstevel@tonic-gate #include <time.h> 45*7c478bd9Sstevel@tonic-gate #include <signal.h> 46*7c478bd9Sstevel@tonic-gate #include <errno.h> 47*7c478bd9Sstevel@tonic-gate #include <limits.h> 48*7c478bd9Sstevel@tonic-gate #include <ulimit.h> 49*7c478bd9Sstevel@tonic-gate #include <unistd.h> 50*7c478bd9Sstevel@tonic-gate #include <locale.h> 51*7c478bd9Sstevel@tonic-gate #include <libintl.h> 52*7c478bd9Sstevel@tonic-gate #include <tzfile.h> 53*7c478bd9Sstevel@tonic-gate #include <project.h> 54*7c478bd9Sstevel@tonic-gate 55*7c478bd9Sstevel@tonic-gate #include "cron.h" 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate #define TMPFILE "_at" /* prefix for temporary files */ 58*7c478bd9Sstevel@tonic-gate /* 59*7c478bd9Sstevel@tonic-gate * Mode for creating files in ATDIR. 60*7c478bd9Sstevel@tonic-gate * Setuid bit on so that if an owner of a file gives that file 61*7c478bd9Sstevel@tonic-gate * away to someone else, the setuid bit will no longer be set. 62*7c478bd9Sstevel@tonic-gate * If this happens, atrun will not execute the file 63*7c478bd9Sstevel@tonic-gate */ 64*7c478bd9Sstevel@tonic-gate #define ATMODE (S_ISUID | S_IRUSR | S_IRGRP | S_IROTH) 65*7c478bd9Sstevel@tonic-gate #define ROOT 0 /* user-id of super-user */ 66*7c478bd9Sstevel@tonic-gate #define MAXTRYS 100 /* max trys to create at job file */ 67*7c478bd9Sstevel@tonic-gate 68*7c478bd9Sstevel@tonic-gate #define BADTIME "bad time specification" 69*7c478bd9Sstevel@tonic-gate #define BADQUEUE "queue name must be a single character a-z" 70*7c478bd9Sstevel@tonic-gate #define NOTCQUEUE "queue c is reserved for cron entries" 71*7c478bd9Sstevel@tonic-gate #define BADSHELL "because your login shell isn't /usr/bin/sh,"\ 72*7c478bd9Sstevel@tonic-gate "you can't use at" 73*7c478bd9Sstevel@tonic-gate #define WARNSHELL "commands will be executed using %s\n" 74*7c478bd9Sstevel@tonic-gate #define CANTCD "can't change directory to the at directory" 75*7c478bd9Sstevel@tonic-gate #define CANTCHOWN "can't change the owner of your job to you" 76*7c478bd9Sstevel@tonic-gate #define CANTCREATE "can't create a job for you" 77*7c478bd9Sstevel@tonic-gate #define INVALIDUSER "you are not a valid user (no entry in /etc/passwd)" 78*7c478bd9Sstevel@tonic-gate #define NOOPENDIR "can't open the at directory" 79*7c478bd9Sstevel@tonic-gate #define NOTALLOWED "you are not authorized to use at. Sorry." 80*7c478bd9Sstevel@tonic-gate #define USAGE\ 81*7c478bd9Sstevel@tonic-gate "usage: at [-c|-k|-s] [-m] [-f file] [-p project] [-q queuename] "\ 82*7c478bd9Sstevel@tonic-gate "-t time\n"\ 83*7c478bd9Sstevel@tonic-gate " at [-c|-k|-s] [-m] [-f file] [-p project] [-q queuename] "\ 84*7c478bd9Sstevel@tonic-gate "timespec\n"\ 85*7c478bd9Sstevel@tonic-gate " at -l [-p project] [-q queuename] [at_job_id...]\n"\ 86*7c478bd9Sstevel@tonic-gate " at -r at_job_id ...\n" 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate #define FORMAT "%a %b %e %H:%M:%S %Y" 89*7c478bd9Sstevel@tonic-gate 90*7c478bd9Sstevel@tonic-gate /* Macros used in format for fscanf */ 91*7c478bd9Sstevel@tonic-gate #define AQ(x) #x 92*7c478bd9Sstevel@tonic-gate #define BUFFMT(p) AQ(p) 93*7c478bd9Sstevel@tonic-gate 94*7c478bd9Sstevel@tonic-gate static int leap(int); 95*7c478bd9Sstevel@tonic-gate static int atoi_for2(char *); 96*7c478bd9Sstevel@tonic-gate static int check_queue(char *, int); 97*7c478bd9Sstevel@tonic-gate static int list_jobs(int, char **, int, int); 98*7c478bd9Sstevel@tonic-gate static int remove_jobs(int, char **, char *); 99*7c478bd9Sstevel@tonic-gate static void usage(void); 100*7c478bd9Sstevel@tonic-gate static void catch(int); 101*7c478bd9Sstevel@tonic-gate static void copy(char *, FILE *, int); 102*7c478bd9Sstevel@tonic-gate static void atime(struct tm *, struct tm *); 103*7c478bd9Sstevel@tonic-gate static int not_this_project(char *); 104*7c478bd9Sstevel@tonic-gate static char *mkjobname(time_t); 105*7c478bd9Sstevel@tonic-gate static time_t parse_time(char *); 106*7c478bd9Sstevel@tonic-gate static time_t gtime(struct tm *); 107*7c478bd9Sstevel@tonic-gate void atabort(char *); 108*7c478bd9Sstevel@tonic-gate void yyerror(void); 109*7c478bd9Sstevel@tonic-gate extern int yyparse(void); 110*7c478bd9Sstevel@tonic-gate 111*7c478bd9Sstevel@tonic-gate extern void audit_at_delete(char *, char *, int); 112*7c478bd9Sstevel@tonic-gate extern int audit_at_create(char *, int); 113*7c478bd9Sstevel@tonic-gate extern int audit_cron_is_anc_name(char *); 114*7c478bd9Sstevel@tonic-gate extern int audit_cron_delete_anc_file(char *, char *); 115*7c478bd9Sstevel@tonic-gate 116*7c478bd9Sstevel@tonic-gate /* 117*7c478bd9Sstevel@tonic-gate * Error in getdate(3G) 118*7c478bd9Sstevel@tonic-gate */ 119*7c478bd9Sstevel@tonic-gate static char *errlist[] = { 120*7c478bd9Sstevel@tonic-gate /* 0 */ "", 121*7c478bd9Sstevel@tonic-gate /* 1 */ "getdate: The DATEMSK environment variable is not set", 122*7c478bd9Sstevel@tonic-gate /* 2 */ "getdate: Error on \"open\" of the template file", 123*7c478bd9Sstevel@tonic-gate /* 3 */ "getdate: Error on \"stat\" of the template file", 124*7c478bd9Sstevel@tonic-gate /* 4 */ "getdate: The template file is not a regular file", 125*7c478bd9Sstevel@tonic-gate /* 5 */ "getdate: An error is encountered while reading the template", 126*7c478bd9Sstevel@tonic-gate /* 6 */ "getdate: Malloc(3C) failed", 127*7c478bd9Sstevel@tonic-gate /* 7 */ "getdate: There is no line in the template that matches the input", 128*7c478bd9Sstevel@tonic-gate /* 8 */ "getdate: Invalid input specification" 129*7c478bd9Sstevel@tonic-gate }; 130*7c478bd9Sstevel@tonic-gate 131*7c478bd9Sstevel@tonic-gate int gmtflag = 0; 132*7c478bd9Sstevel@tonic-gate int mday[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 133*7c478bd9Sstevel@tonic-gate uid_t user; 134*7c478bd9Sstevel@tonic-gate struct tm *tp, at, rt; 135*7c478bd9Sstevel@tonic-gate static int cshflag = 0; 136*7c478bd9Sstevel@tonic-gate static int kshflag = 0; 137*7c478bd9Sstevel@tonic-gate static int shflag = 0; 138*7c478bd9Sstevel@tonic-gate static int mflag = 0; 139*7c478bd9Sstevel@tonic-gate static int pflag = 0; 140*7c478bd9Sstevel@tonic-gate static char *Shell; 141*7c478bd9Sstevel@tonic-gate static char *tfname; 142*7c478bd9Sstevel@tonic-gate static char pname[80]; 143*7c478bd9Sstevel@tonic-gate static char pname1[80]; 144*7c478bd9Sstevel@tonic-gate static short jobtype = ATEVENT; /* set to 1 if batch job */ 145*7c478bd9Sstevel@tonic-gate extern char *argp; 146*7c478bd9Sstevel@tonic-gate extern int per_errno; 147*7c478bd9Sstevel@tonic-gate static projid_t project; 148*7c478bd9Sstevel@tonic-gate 149*7c478bd9Sstevel@tonic-gate main(argc, argv) 150*7c478bd9Sstevel@tonic-gate int argc; 151*7c478bd9Sstevel@tonic-gate char **argv; 152*7c478bd9Sstevel@tonic-gate { 153*7c478bd9Sstevel@tonic-gate FILE *inputfile; 154*7c478bd9Sstevel@tonic-gate int i, fd; 155*7c478bd9Sstevel@tonic-gate int try = 0; 156*7c478bd9Sstevel@tonic-gate int fflag = 0; 157*7c478bd9Sstevel@tonic-gate int lflag = 0; 158*7c478bd9Sstevel@tonic-gate int qflag = 0; 159*7c478bd9Sstevel@tonic-gate int rflag = 0; 160*7c478bd9Sstevel@tonic-gate int tflag = 0; 161*7c478bd9Sstevel@tonic-gate int c; 162*7c478bd9Sstevel@tonic-gate int tflen; 163*7c478bd9Sstevel@tonic-gate char *file; 164*7c478bd9Sstevel@tonic-gate char *login; 165*7c478bd9Sstevel@tonic-gate char *job; 166*7c478bd9Sstevel@tonic-gate char *jobfile = NULL; /* file containing job to be run */ 167*7c478bd9Sstevel@tonic-gate char argpbuf[LINE_MAX], timebuf[80]; 168*7c478bd9Sstevel@tonic-gate time_t now; 169*7c478bd9Sstevel@tonic-gate time_t when = 0; 170*7c478bd9Sstevel@tonic-gate struct tm *ct; 171*7c478bd9Sstevel@tonic-gate char *proj; 172*7c478bd9Sstevel@tonic-gate struct project prj, *pprj; 173*7c478bd9Sstevel@tonic-gate char mybuf[PROJECT_BUFSZ]; 174*7c478bd9Sstevel@tonic-gate char ipbuf[PROJECT_BUFSZ]; 175*7c478bd9Sstevel@tonic-gate 176*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 177*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 178*7c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 179*7c478bd9Sstevel@tonic-gate #endif 180*7c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 181*7c478bd9Sstevel@tonic-gate 182*7c478bd9Sstevel@tonic-gate user = getuid(); 183*7c478bd9Sstevel@tonic-gate login = getuser(user); 184*7c478bd9Sstevel@tonic-gate if (login == NULL) { 185*7c478bd9Sstevel@tonic-gate if (per_errno == 2) 186*7c478bd9Sstevel@tonic-gate atabort(BADSHELL); 187*7c478bd9Sstevel@tonic-gate else 188*7c478bd9Sstevel@tonic-gate atabort(INVALIDUSER); 189*7c478bd9Sstevel@tonic-gate } 190*7c478bd9Sstevel@tonic-gate 191*7c478bd9Sstevel@tonic-gate if (!allowed(login, ATALLOW, ATDENY)) 192*7c478bd9Sstevel@tonic-gate atabort(NOTALLOWED); 193*7c478bd9Sstevel@tonic-gate 194*7c478bd9Sstevel@tonic-gate while ((c = getopt(argc, argv, "cklmsrf:p:q:t:")) != EOF) 195*7c478bd9Sstevel@tonic-gate switch (c) { 196*7c478bd9Sstevel@tonic-gate case 'c': 197*7c478bd9Sstevel@tonic-gate cshflag++; 198*7c478bd9Sstevel@tonic-gate break; 199*7c478bd9Sstevel@tonic-gate case 'f': 200*7c478bd9Sstevel@tonic-gate fflag++; 201*7c478bd9Sstevel@tonic-gate jobfile = optarg; 202*7c478bd9Sstevel@tonic-gate break; 203*7c478bd9Sstevel@tonic-gate case 'k': 204*7c478bd9Sstevel@tonic-gate kshflag++; 205*7c478bd9Sstevel@tonic-gate break; 206*7c478bd9Sstevel@tonic-gate case 'l': 207*7c478bd9Sstevel@tonic-gate lflag++; 208*7c478bd9Sstevel@tonic-gate break; 209*7c478bd9Sstevel@tonic-gate case 'm': 210*7c478bd9Sstevel@tonic-gate mflag++; 211*7c478bd9Sstevel@tonic-gate break; 212*7c478bd9Sstevel@tonic-gate case 'p': 213*7c478bd9Sstevel@tonic-gate proj = optarg; 214*7c478bd9Sstevel@tonic-gate pprj = &prj; 215*7c478bd9Sstevel@tonic-gate if ((pprj = getprojbyname(proj, pprj, 216*7c478bd9Sstevel@tonic-gate (void *)&mybuf, sizeof (mybuf))) != NULL) { 217*7c478bd9Sstevel@tonic-gate project = pprj->pj_projid; 218*7c478bd9Sstevel@tonic-gate if (inproj(login, pprj->pj_name, 219*7c478bd9Sstevel@tonic-gate (void *)&ipbuf, sizeof (ipbuf))) 220*7c478bd9Sstevel@tonic-gate pflag++; 221*7c478bd9Sstevel@tonic-gate else { 222*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 223*7c478bd9Sstevel@tonic-gate gettext("at: user %s is " 224*7c478bd9Sstevel@tonic-gate "not a member of " 225*7c478bd9Sstevel@tonic-gate "project %s (%d)\n"), 226*7c478bd9Sstevel@tonic-gate login, pprj->pj_name, 227*7c478bd9Sstevel@tonic-gate project); 228*7c478bd9Sstevel@tonic-gate exit(2); 229*7c478bd9Sstevel@tonic-gate } 230*7c478bd9Sstevel@tonic-gate break; 231*7c478bd9Sstevel@tonic-gate } 232*7c478bd9Sstevel@tonic-gate pprj = &prj; 233*7c478bd9Sstevel@tonic-gate if (isdigit(proj[0]) && 234*7c478bd9Sstevel@tonic-gate (pprj = getprojbyid(atoi(proj), pprj, 235*7c478bd9Sstevel@tonic-gate (void *)&mybuf, sizeof (mybuf))) != NULL) { 236*7c478bd9Sstevel@tonic-gate project = pprj->pj_projid; 237*7c478bd9Sstevel@tonic-gate if (inproj(login, pprj->pj_name, 238*7c478bd9Sstevel@tonic-gate (void *)&ipbuf, sizeof (ipbuf))) 239*7c478bd9Sstevel@tonic-gate pflag++; 240*7c478bd9Sstevel@tonic-gate else { 241*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 242*7c478bd9Sstevel@tonic-gate gettext("at: user %s is " 243*7c478bd9Sstevel@tonic-gate "not a member of " 244*7c478bd9Sstevel@tonic-gate "project %s (%d)\n"), 245*7c478bd9Sstevel@tonic-gate login, pprj->pj_name, 246*7c478bd9Sstevel@tonic-gate project); 247*7c478bd9Sstevel@tonic-gate exit(2); 248*7c478bd9Sstevel@tonic-gate } 249*7c478bd9Sstevel@tonic-gate break; 250*7c478bd9Sstevel@tonic-gate } 251*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("at: project " 252*7c478bd9Sstevel@tonic-gate "%s not found.\n"), proj); 253*7c478bd9Sstevel@tonic-gate exit(2); 254*7c478bd9Sstevel@tonic-gate break; 255*7c478bd9Sstevel@tonic-gate case 'q': 256*7c478bd9Sstevel@tonic-gate qflag++; 257*7c478bd9Sstevel@tonic-gate if (optarg[1] != '\0') 258*7c478bd9Sstevel@tonic-gate atabort(BADQUEUE); 259*7c478bd9Sstevel@tonic-gate jobtype = *optarg - 'a'; 260*7c478bd9Sstevel@tonic-gate if ((jobtype < 0) || (jobtype > 25)) 261*7c478bd9Sstevel@tonic-gate atabort(BADQUEUE); 262*7c478bd9Sstevel@tonic-gate if (jobtype == 2) 263*7c478bd9Sstevel@tonic-gate atabort(NOTCQUEUE); 264*7c478bd9Sstevel@tonic-gate break; 265*7c478bd9Sstevel@tonic-gate case 'r': 266*7c478bd9Sstevel@tonic-gate rflag++; 267*7c478bd9Sstevel@tonic-gate break; 268*7c478bd9Sstevel@tonic-gate case 's': 269*7c478bd9Sstevel@tonic-gate shflag++; 270*7c478bd9Sstevel@tonic-gate break; 271*7c478bd9Sstevel@tonic-gate case 't': 272*7c478bd9Sstevel@tonic-gate tflag++; 273*7c478bd9Sstevel@tonic-gate when = parse_time(optarg); 274*7c478bd9Sstevel@tonic-gate break; 275*7c478bd9Sstevel@tonic-gate default: 276*7c478bd9Sstevel@tonic-gate usage(); 277*7c478bd9Sstevel@tonic-gate } 278*7c478bd9Sstevel@tonic-gate 279*7c478bd9Sstevel@tonic-gate argc -= optind; 280*7c478bd9Sstevel@tonic-gate argv += optind; 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate if (lflag + rflag > 1) 283*7c478bd9Sstevel@tonic-gate usage(); 284*7c478bd9Sstevel@tonic-gate 285*7c478bd9Sstevel@tonic-gate if (lflag) { 286*7c478bd9Sstevel@tonic-gate if (cshflag || kshflag || shflag || mflag || 287*7c478bd9Sstevel@tonic-gate fflag || tflag || rflag) 288*7c478bd9Sstevel@tonic-gate usage(); 289*7c478bd9Sstevel@tonic-gate return (list_jobs(argc, argv, qflag, jobtype)); 290*7c478bd9Sstevel@tonic-gate } 291*7c478bd9Sstevel@tonic-gate 292*7c478bd9Sstevel@tonic-gate if (rflag) { 293*7c478bd9Sstevel@tonic-gate if (cshflag || kshflag || shflag || mflag || 294*7c478bd9Sstevel@tonic-gate fflag || tflag || qflag) 295*7c478bd9Sstevel@tonic-gate usage(); 296*7c478bd9Sstevel@tonic-gate return (remove_jobs(argc, argv, login)); 297*7c478bd9Sstevel@tonic-gate } 298*7c478bd9Sstevel@tonic-gate 299*7c478bd9Sstevel@tonic-gate if ((argc + tflag == 0) && (jobtype != BATCHEVENT)) 300*7c478bd9Sstevel@tonic-gate usage(); 301*7c478bd9Sstevel@tonic-gate 302*7c478bd9Sstevel@tonic-gate if (cshflag + kshflag + shflag > 1) 303*7c478bd9Sstevel@tonic-gate atabort("ambiguous shell request"); 304*7c478bd9Sstevel@tonic-gate 305*7c478bd9Sstevel@tonic-gate time(&now); 306*7c478bd9Sstevel@tonic-gate 307*7c478bd9Sstevel@tonic-gate if (jobtype == BATCHEVENT) 308*7c478bd9Sstevel@tonic-gate when = now; 309*7c478bd9Sstevel@tonic-gate 310*7c478bd9Sstevel@tonic-gate if (when == 0) { /* figure out what time to run the job */ 311*7c478bd9Sstevel@tonic-gate int argplen = sizeof (argpbuf) - 1; 312*7c478bd9Sstevel@tonic-gate 313*7c478bd9Sstevel@tonic-gate argpbuf[0] = '\0'; 314*7c478bd9Sstevel@tonic-gate argp = argpbuf; 315*7c478bd9Sstevel@tonic-gate i = 0; 316*7c478bd9Sstevel@tonic-gate while (i < argc) { 317*7c478bd9Sstevel@tonic-gate /* guard against buffer overflow */ 318*7c478bd9Sstevel@tonic-gate argplen -= strlen(argv[i]) + 1; 319*7c478bd9Sstevel@tonic-gate if (argplen < 0) 320*7c478bd9Sstevel@tonic-gate atabort(BADTIME); 321*7c478bd9Sstevel@tonic-gate 322*7c478bd9Sstevel@tonic-gate strcat(argp, argv[i]); 323*7c478bd9Sstevel@tonic-gate strcat(argp, " "); 324*7c478bd9Sstevel@tonic-gate i++; 325*7c478bd9Sstevel@tonic-gate } 326*7c478bd9Sstevel@tonic-gate if ((file = getenv("DATEMSK")) == 0 || file[0] == '\0') { 327*7c478bd9Sstevel@tonic-gate tp = localtime(&now); 328*7c478bd9Sstevel@tonic-gate /* 329*7c478bd9Sstevel@tonic-gate * Fix for 1047182 - we have to let yyparse 330*7c478bd9Sstevel@tonic-gate * check bounds on mday[] first, then fixup 331*7c478bd9Sstevel@tonic-gate * the leap year case. 332*7c478bd9Sstevel@tonic-gate */ 333*7c478bd9Sstevel@tonic-gate yyparse(); 334*7c478bd9Sstevel@tonic-gate 335*7c478bd9Sstevel@tonic-gate mday[1] = 28 + leap(at.tm_year); 336*7c478bd9Sstevel@tonic-gate 337*7c478bd9Sstevel@tonic-gate if (at.tm_mday > mday[at.tm_mon]) 338*7c478bd9Sstevel@tonic-gate atabort("bad date"); 339*7c478bd9Sstevel@tonic-gate 340*7c478bd9Sstevel@tonic-gate atime(&at, &rt); 341*7c478bd9Sstevel@tonic-gate when = gtime(&at); 342*7c478bd9Sstevel@tonic-gate if (!gmtflag) { 343*7c478bd9Sstevel@tonic-gate when += timezone; 344*7c478bd9Sstevel@tonic-gate if (localtime(&when)->tm_isdst) 345*7c478bd9Sstevel@tonic-gate when -= (timezone-altzone); 346*7c478bd9Sstevel@tonic-gate } 347*7c478bd9Sstevel@tonic-gate } else { /* DATEMSK is set */ 348*7c478bd9Sstevel@tonic-gate if ((ct = getdate(argpbuf)) == NULL) 349*7c478bd9Sstevel@tonic-gate atabort(errlist[getdate_err]); 350*7c478bd9Sstevel@tonic-gate else 351*7c478bd9Sstevel@tonic-gate when = mktime(ct); 352*7c478bd9Sstevel@tonic-gate } 353*7c478bd9Sstevel@tonic-gate } 354*7c478bd9Sstevel@tonic-gate 355*7c478bd9Sstevel@tonic-gate if (when < now) /* time has already past */ 356*7c478bd9Sstevel@tonic-gate atabort("too late"); 357*7c478bd9Sstevel@tonic-gate 358*7c478bd9Sstevel@tonic-gate tflen = strlen(ATDIR) + 1 + strlen(TMPFILE) + 359*7c478bd9Sstevel@tonic-gate 10 + 1; /* 10 for an INT_MAX pid */ 360*7c478bd9Sstevel@tonic-gate tfname = xmalloc(tflen); 361*7c478bd9Sstevel@tonic-gate snprintf(tfname, tflen, "%s/%s%d", ATDIR, TMPFILE, getpid()); 362*7c478bd9Sstevel@tonic-gate 363*7c478bd9Sstevel@tonic-gate /* catch INT, HUP, TERM and QUIT signals */ 364*7c478bd9Sstevel@tonic-gate if (signal(SIGINT, catch) == SIG_IGN) 365*7c478bd9Sstevel@tonic-gate signal(SIGINT, SIG_IGN); 366*7c478bd9Sstevel@tonic-gate if (signal(SIGHUP, catch) == SIG_IGN) 367*7c478bd9Sstevel@tonic-gate signal(SIGHUP, SIG_IGN); 368*7c478bd9Sstevel@tonic-gate if (signal(SIGQUIT, catch) == SIG_IGN) 369*7c478bd9Sstevel@tonic-gate signal(SIGQUIT, SIG_IGN); 370*7c478bd9Sstevel@tonic-gate if (signal(SIGTERM, catch) == SIG_IGN) 371*7c478bd9Sstevel@tonic-gate signal(SIGTERM, SIG_IGN); 372*7c478bd9Sstevel@tonic-gate if ((fd = open(tfname, O_CREAT|O_EXCL|O_WRONLY, ATMODE)) < 0) 373*7c478bd9Sstevel@tonic-gate atabort(CANTCREATE); 374*7c478bd9Sstevel@tonic-gate if (chown(tfname, user, getgid()) == -1) { 375*7c478bd9Sstevel@tonic-gate unlink(tfname); 376*7c478bd9Sstevel@tonic-gate atabort(CANTCHOWN); 377*7c478bd9Sstevel@tonic-gate } 378*7c478bd9Sstevel@tonic-gate close(1); 379*7c478bd9Sstevel@tonic-gate dup(fd); 380*7c478bd9Sstevel@tonic-gate close(fd); 381*7c478bd9Sstevel@tonic-gate sprintf(pname, "%s", PROTO); 382*7c478bd9Sstevel@tonic-gate sprintf(pname1, "%s.%c", PROTO, 'a'+jobtype); 383*7c478bd9Sstevel@tonic-gate 384*7c478bd9Sstevel@tonic-gate /* 385*7c478bd9Sstevel@tonic-gate * Open the input file with the user's permissions. 386*7c478bd9Sstevel@tonic-gate */ 387*7c478bd9Sstevel@tonic-gate if (jobfile != NULL) { 388*7c478bd9Sstevel@tonic-gate if ((seteuid(user) < 0) || 389*7c478bd9Sstevel@tonic-gate (inputfile = fopen(jobfile, "r")) == NULL) { 390*7c478bd9Sstevel@tonic-gate unlink(tfname); 391*7c478bd9Sstevel@tonic-gate fprintf(stderr, "at: %s: %s\n", jobfile, errmsg(errno)); 392*7c478bd9Sstevel@tonic-gate exit(1); 393*7c478bd9Sstevel@tonic-gate } 394*7c478bd9Sstevel@tonic-gate else 395*7c478bd9Sstevel@tonic-gate seteuid(0); 396*7c478bd9Sstevel@tonic-gate } else 397*7c478bd9Sstevel@tonic-gate inputfile = stdin; 398*7c478bd9Sstevel@tonic-gate 399*7c478bd9Sstevel@tonic-gate copy(jobfile, inputfile, when); 400*7c478bd9Sstevel@tonic-gate while (rename(tfname, job = mkjobname(when)) == -1) { 401*7c478bd9Sstevel@tonic-gate sleep(1); 402*7c478bd9Sstevel@tonic-gate if (++try > MAXTRYS / 10) { 403*7c478bd9Sstevel@tonic-gate unlink(tfname); 404*7c478bd9Sstevel@tonic-gate atabort(CANTCREATE); 405*7c478bd9Sstevel@tonic-gate } 406*7c478bd9Sstevel@tonic-gate } 407*7c478bd9Sstevel@tonic-gate unlink(tfname); 408*7c478bd9Sstevel@tonic-gate if (audit_at_create(job, 0)) 409*7c478bd9Sstevel@tonic-gate atabort(CANTCREATE); 410*7c478bd9Sstevel@tonic-gate 411*7c478bd9Sstevel@tonic-gate cron_sendmsg(ADD, login, strrchr(job, '/')+1, AT); 412*7c478bd9Sstevel@tonic-gate if (per_errno == 2) 413*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext(WARNSHELL), Shell); 414*7c478bd9Sstevel@tonic-gate cftime(timebuf, FORMAT, &when); 415*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("job %s at %s\n"), 416*7c478bd9Sstevel@tonic-gate strrchr(job, '/')+1, timebuf); 417*7c478bd9Sstevel@tonic-gate if (when - MINUTE < HOUR) 418*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext( 419*7c478bd9Sstevel@tonic-gate "at: this job may not be executed at the proper time.\n")); 420*7c478bd9Sstevel@tonic-gate return (0); 421*7c478bd9Sstevel@tonic-gate } 422*7c478bd9Sstevel@tonic-gate 423*7c478bd9Sstevel@tonic-gate 424*7c478bd9Sstevel@tonic-gate static char * 425*7c478bd9Sstevel@tonic-gate mkjobname(t) 426*7c478bd9Sstevel@tonic-gate time_t t; 427*7c478bd9Sstevel@tonic-gate { 428*7c478bd9Sstevel@tonic-gate int i, fd; 429*7c478bd9Sstevel@tonic-gate char *name; 430*7c478bd9Sstevel@tonic-gate 431*7c478bd9Sstevel@tonic-gate name = xmalloc(200); 432*7c478bd9Sstevel@tonic-gate for (i = 0; i < MAXTRYS; i++) { 433*7c478bd9Sstevel@tonic-gate sprintf(name, "%s/%ld.%c", ATDIR, t, 'a'+jobtype); 434*7c478bd9Sstevel@tonic-gate /* fix for 1099183, 1116833 - create file here, avoid race */ 435*7c478bd9Sstevel@tonic-gate if ((fd = open(name, O_CREAT | O_EXCL, ATMODE)) > 0) { 436*7c478bd9Sstevel@tonic-gate close(fd); 437*7c478bd9Sstevel@tonic-gate return (name); 438*7c478bd9Sstevel@tonic-gate } 439*7c478bd9Sstevel@tonic-gate t += 1; 440*7c478bd9Sstevel@tonic-gate } 441*7c478bd9Sstevel@tonic-gate atabort("queue full"); 442*7c478bd9Sstevel@tonic-gate } 443*7c478bd9Sstevel@tonic-gate 444*7c478bd9Sstevel@tonic-gate 445*7c478bd9Sstevel@tonic-gate static void 446*7c478bd9Sstevel@tonic-gate catch(int x) 447*7c478bd9Sstevel@tonic-gate { 448*7c478bd9Sstevel@tonic-gate unlink(tfname); 449*7c478bd9Sstevel@tonic-gate exit(1); 450*7c478bd9Sstevel@tonic-gate } 451*7c478bd9Sstevel@tonic-gate 452*7c478bd9Sstevel@tonic-gate 453*7c478bd9Sstevel@tonic-gate void 454*7c478bd9Sstevel@tonic-gate atabort(msg) 455*7c478bd9Sstevel@tonic-gate char *msg; 456*7c478bd9Sstevel@tonic-gate { 457*7c478bd9Sstevel@tonic-gate fprintf(stderr, "at: %s\n", gettext(msg)); 458*7c478bd9Sstevel@tonic-gate 459*7c478bd9Sstevel@tonic-gate exit(1); 460*7c478bd9Sstevel@tonic-gate } 461*7c478bd9Sstevel@tonic-gate 462*7c478bd9Sstevel@tonic-gate yywrap(void) 463*7c478bd9Sstevel@tonic-gate { 464*7c478bd9Sstevel@tonic-gate return (1); 465*7c478bd9Sstevel@tonic-gate } 466*7c478bd9Sstevel@tonic-gate 467*7c478bd9Sstevel@tonic-gate void 468*7c478bd9Sstevel@tonic-gate yyerror(void) 469*7c478bd9Sstevel@tonic-gate { 470*7c478bd9Sstevel@tonic-gate atabort(BADTIME); 471*7c478bd9Sstevel@tonic-gate } 472*7c478bd9Sstevel@tonic-gate 473*7c478bd9Sstevel@tonic-gate /* 474*7c478bd9Sstevel@tonic-gate * add time structures logically 475*7c478bd9Sstevel@tonic-gate */ 476*7c478bd9Sstevel@tonic-gate static void 477*7c478bd9Sstevel@tonic-gate atime(struct tm *a, struct tm *b) 478*7c478bd9Sstevel@tonic-gate { 479*7c478bd9Sstevel@tonic-gate if ((a->tm_sec += b->tm_sec) >= 60) { 480*7c478bd9Sstevel@tonic-gate b->tm_min += a->tm_sec / 60; 481*7c478bd9Sstevel@tonic-gate a->tm_sec %= 60; 482*7c478bd9Sstevel@tonic-gate } 483*7c478bd9Sstevel@tonic-gate if ((a->tm_min += b->tm_min) >= 60) { 484*7c478bd9Sstevel@tonic-gate b->tm_hour += a->tm_min / 60; 485*7c478bd9Sstevel@tonic-gate a->tm_min %= 60; 486*7c478bd9Sstevel@tonic-gate } 487*7c478bd9Sstevel@tonic-gate if ((a->tm_hour += b->tm_hour) >= 24) { 488*7c478bd9Sstevel@tonic-gate b->tm_mday += a->tm_hour / 24; 489*7c478bd9Sstevel@tonic-gate a->tm_hour %= 24; 490*7c478bd9Sstevel@tonic-gate } 491*7c478bd9Sstevel@tonic-gate a->tm_year += b->tm_year; 492*7c478bd9Sstevel@tonic-gate if ((a->tm_mon += b->tm_mon) >= 12) { 493*7c478bd9Sstevel@tonic-gate a->tm_year += a->tm_mon / 12; 494*7c478bd9Sstevel@tonic-gate a->tm_mon %= 12; 495*7c478bd9Sstevel@tonic-gate } 496*7c478bd9Sstevel@tonic-gate a->tm_mday += b->tm_mday; 497*7c478bd9Sstevel@tonic-gate mday[1] = 28 + leap(a->tm_year); 498*7c478bd9Sstevel@tonic-gate while (a->tm_mday > mday[a->tm_mon]) { 499*7c478bd9Sstevel@tonic-gate a->tm_mday -= mday[a->tm_mon++]; 500*7c478bd9Sstevel@tonic-gate if (a->tm_mon > 11) { 501*7c478bd9Sstevel@tonic-gate a->tm_mon = 0; 502*7c478bd9Sstevel@tonic-gate mday[1] = 28 + leap(++a->tm_year); 503*7c478bd9Sstevel@tonic-gate } 504*7c478bd9Sstevel@tonic-gate } 505*7c478bd9Sstevel@tonic-gate 506*7c478bd9Sstevel@tonic-gate } 507*7c478bd9Sstevel@tonic-gate 508*7c478bd9Sstevel@tonic-gate static int 509*7c478bd9Sstevel@tonic-gate leap(int year) 510*7c478bd9Sstevel@tonic-gate { 511*7c478bd9Sstevel@tonic-gate return (isleap(year + TM_YEAR_BASE)); 512*7c478bd9Sstevel@tonic-gate } 513*7c478bd9Sstevel@tonic-gate 514*7c478bd9Sstevel@tonic-gate /* 515*7c478bd9Sstevel@tonic-gate * return time from time structure 516*7c478bd9Sstevel@tonic-gate */ 517*7c478bd9Sstevel@tonic-gate static time_t 518*7c478bd9Sstevel@tonic-gate gtime(tptr) 519*7c478bd9Sstevel@tonic-gate struct tm *tptr; 520*7c478bd9Sstevel@tonic-gate { 521*7c478bd9Sstevel@tonic-gate register i; 522*7c478bd9Sstevel@tonic-gate long tv; 523*7c478bd9Sstevel@tonic-gate int dmsize[12] = 524*7c478bd9Sstevel@tonic-gate {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 525*7c478bd9Sstevel@tonic-gate 526*7c478bd9Sstevel@tonic-gate 527*7c478bd9Sstevel@tonic-gate tv = 0; 528*7c478bd9Sstevel@tonic-gate for (i = 1970; i != tptr->tm_year+TM_YEAR_BASE; i++) 529*7c478bd9Sstevel@tonic-gate tv += (365 + isleap(i)); 530*7c478bd9Sstevel@tonic-gate /* 531*7c478bd9Sstevel@tonic-gate * We call isleap since leap() adds 532*7c478bd9Sstevel@tonic-gate * 1900 onto any value passed 533*7c478bd9Sstevel@tonic-gate */ 534*7c478bd9Sstevel@tonic-gate 535*7c478bd9Sstevel@tonic-gate if (!leap(tptr->tm_year) && at.tm_mday == 29 && at.tm_mon == 1) 536*7c478bd9Sstevel@tonic-gate atabort("bad date - not a leap year"); 537*7c478bd9Sstevel@tonic-gate 538*7c478bd9Sstevel@tonic-gate if ((leap(tptr->tm_year)) && tptr->tm_mon >= 2) 539*7c478bd9Sstevel@tonic-gate ++tv; 540*7c478bd9Sstevel@tonic-gate 541*7c478bd9Sstevel@tonic-gate for (i = 0; i < tptr->tm_mon; ++i) 542*7c478bd9Sstevel@tonic-gate tv += dmsize[i]; 543*7c478bd9Sstevel@tonic-gate tv += tptr->tm_mday - 1; 544*7c478bd9Sstevel@tonic-gate tv = 24 * tv + tptr->tm_hour; 545*7c478bd9Sstevel@tonic-gate tv = 60 * tv + tptr->tm_min; 546*7c478bd9Sstevel@tonic-gate tv = 60 * tv + tptr->tm_sec; 547*7c478bd9Sstevel@tonic-gate return (tv); 548*7c478bd9Sstevel@tonic-gate } 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate /* 551*7c478bd9Sstevel@tonic-gate * make job file from proto + stdin 552*7c478bd9Sstevel@tonic-gate */ 553*7c478bd9Sstevel@tonic-gate static void 554*7c478bd9Sstevel@tonic-gate copy(char *jobfile, FILE *inputfile, int when) 555*7c478bd9Sstevel@tonic-gate { 556*7c478bd9Sstevel@tonic-gate register c; 557*7c478bd9Sstevel@tonic-gate register FILE *pfp; 558*7c478bd9Sstevel@tonic-gate register FILE *xfp; 559*7c478bd9Sstevel@tonic-gate char *shell; 560*7c478bd9Sstevel@tonic-gate char dirbuf[PATH_MAX + 1]; 561*7c478bd9Sstevel@tonic-gate char line[LINE_MAX]; 562*7c478bd9Sstevel@tonic-gate register char **ep; 563*7c478bd9Sstevel@tonic-gate mode_t um; 564*7c478bd9Sstevel@tonic-gate char *val; 565*7c478bd9Sstevel@tonic-gate extern char **environ; 566*7c478bd9Sstevel@tonic-gate int pfd[2]; 567*7c478bd9Sstevel@tonic-gate pid_t pid; 568*7c478bd9Sstevel@tonic-gate uid_t realusr; 569*7c478bd9Sstevel@tonic-gate int ttyinput; 570*7c478bd9Sstevel@tonic-gate int ulimit_flag = 0; 571*7c478bd9Sstevel@tonic-gate struct rlimit rlp; 572*7c478bd9Sstevel@tonic-gate struct project prj, *pprj; 573*7c478bd9Sstevel@tonic-gate char pbuf[PROJECT_BUFSZ]; 574*7c478bd9Sstevel@tonic-gate char pbuf2[PROJECT_BUFSZ]; 575*7c478bd9Sstevel@tonic-gate char *user; 576*7c478bd9Sstevel@tonic-gate 577*7c478bd9Sstevel@tonic-gate /* 578*7c478bd9Sstevel@tonic-gate * Fix for 1099381: 579*7c478bd9Sstevel@tonic-gate * If the inputfile is from a tty, then turn on prompting, and 580*7c478bd9Sstevel@tonic-gate * put out a prompt now, instead of waiting for a lot of file 581*7c478bd9Sstevel@tonic-gate * activity to complete. 582*7c478bd9Sstevel@tonic-gate */ 583*7c478bd9Sstevel@tonic-gate ttyinput = isatty(fileno(inputfile)); 584*7c478bd9Sstevel@tonic-gate if (ttyinput) { 585*7c478bd9Sstevel@tonic-gate fputs("at> ", stderr); 586*7c478bd9Sstevel@tonic-gate fflush(stderr); 587*7c478bd9Sstevel@tonic-gate } 588*7c478bd9Sstevel@tonic-gate 589*7c478bd9Sstevel@tonic-gate /* 590*7c478bd9Sstevel@tonic-gate * Fix for 1053807: 591*7c478bd9Sstevel@tonic-gate * Determine what shell we should use to run the job. If the user 592*7c478bd9Sstevel@tonic-gate * didn't explicitly request that his/her current shell be over- 593*7c478bd9Sstevel@tonic-gate * ridden (shflag or cshflag), then we use the current shell. 594*7c478bd9Sstevel@tonic-gate */ 595*7c478bd9Sstevel@tonic-gate if (cshflag) 596*7c478bd9Sstevel@tonic-gate Shell = shell = "/bin/csh"; 597*7c478bd9Sstevel@tonic-gate else if (kshflag) { 598*7c478bd9Sstevel@tonic-gate Shell = shell = "/bin/ksh"; 599*7c478bd9Sstevel@tonic-gate ulimit_flag = 1; 600*7c478bd9Sstevel@tonic-gate } else if (shflag) { 601*7c478bd9Sstevel@tonic-gate Shell = shell = "/bin/sh"; 602*7c478bd9Sstevel@tonic-gate ulimit_flag = 1; 603*7c478bd9Sstevel@tonic-gate } else if (((Shell = val = getenv("SHELL")) != NULL) && 604*7c478bd9Sstevel@tonic-gate (*val != '\0')) { 605*7c478bd9Sstevel@tonic-gate shell = "$SHELL"; 606*7c478bd9Sstevel@tonic-gate if ((strstr(val, "/sh") != NULL) || 607*7c478bd9Sstevel@tonic-gate (strstr(val, "/ksh") != NULL)) 608*7c478bd9Sstevel@tonic-gate ulimit_flag = 1; 609*7c478bd9Sstevel@tonic-gate } else { 610*7c478bd9Sstevel@tonic-gate /* SHELL is NULL or unset, therefore use default */ 611*7c478bd9Sstevel@tonic-gate #ifdef XPG4 612*7c478bd9Sstevel@tonic-gate Shell = shell = "/usr/xpg4/bin/sh"; 613*7c478bd9Sstevel@tonic-gate #else 614*7c478bd9Sstevel@tonic-gate Shell = shell = "/bin/sh"; 615*7c478bd9Sstevel@tonic-gate #endif /* XPG4 */ 616*7c478bd9Sstevel@tonic-gate ulimit_flag = 1; 617*7c478bd9Sstevel@tonic-gate } 618*7c478bd9Sstevel@tonic-gate 619*7c478bd9Sstevel@tonic-gate printf(": %s job\n", jobtype ? "batch" : "at"); 620*7c478bd9Sstevel@tonic-gate printf(": jobname: %.127s\n", (jobfile == NULL) ? "stdin" : jobfile); 621*7c478bd9Sstevel@tonic-gate printf(": notify by mail: %s\n", (mflag) ? "yes" : "no"); 622*7c478bd9Sstevel@tonic-gate 623*7c478bd9Sstevel@tonic-gate if (pflag) { 624*7c478bd9Sstevel@tonic-gate (void) printf(": project: %d\n", project); 625*7c478bd9Sstevel@tonic-gate } else { 626*7c478bd9Sstevel@tonic-gate /* 627*7c478bd9Sstevel@tonic-gate * Check if current user is a member of current project. 628*7c478bd9Sstevel@tonic-gate * This check is done here to avoid setproject() failure 629*7c478bd9Sstevel@tonic-gate * later when the job gets executed. If current user does 630*7c478bd9Sstevel@tonic-gate * not belong to current project, user's default project 631*7c478bd9Sstevel@tonic-gate * will be used instead. This is achieved by not specifying 632*7c478bd9Sstevel@tonic-gate * the project (": project: <project>\n") in the job file. 633*7c478bd9Sstevel@tonic-gate */ 634*7c478bd9Sstevel@tonic-gate if ((user = getuser(getuid())) == NULL) 635*7c478bd9Sstevel@tonic-gate atabort(INVALIDUSER); 636*7c478bd9Sstevel@tonic-gate project = getprojid(); 637*7c478bd9Sstevel@tonic-gate pprj = getprojbyid(project, &prj, pbuf, sizeof (pbuf)); 638*7c478bd9Sstevel@tonic-gate if (pprj != NULL) { 639*7c478bd9Sstevel@tonic-gate if (inproj(user, pprj->pj_name, pbuf2, sizeof (pbuf2))) 640*7c478bd9Sstevel@tonic-gate (void) printf(": project: %d\n", project); 641*7c478bd9Sstevel@tonic-gate } 642*7c478bd9Sstevel@tonic-gate } 643*7c478bd9Sstevel@tonic-gate 644*7c478bd9Sstevel@tonic-gate for (ep = environ; *ep; ep++) { 645*7c478bd9Sstevel@tonic-gate if (strchr(*ep, '\'') != NULL) 646*7c478bd9Sstevel@tonic-gate continue; 647*7c478bd9Sstevel@tonic-gate if ((val = strchr(*ep, '=')) == NULL) 648*7c478bd9Sstevel@tonic-gate continue; 649*7c478bd9Sstevel@tonic-gate *val++ = '\0'; 650*7c478bd9Sstevel@tonic-gate printf("export %s; %s='%s'\n", *ep, *ep, val); 651*7c478bd9Sstevel@tonic-gate *--val = '='; 652*7c478bd9Sstevel@tonic-gate } 653*7c478bd9Sstevel@tonic-gate if ((pfp = fopen(pname1, "r")) == NULL && 654*7c478bd9Sstevel@tonic-gate (pfp = fopen(pname, "r")) == NULL) 655*7c478bd9Sstevel@tonic-gate atabort("no prototype"); 656*7c478bd9Sstevel@tonic-gate /* 657*7c478bd9Sstevel@tonic-gate * Put in a line to run the proper shell using the rest of 658*7c478bd9Sstevel@tonic-gate * the file as input. Note that 'exec'ing the shell will 659*7c478bd9Sstevel@tonic-gate * cause sh() to leave a /tmp/sh### file around. (1053807) 660*7c478bd9Sstevel@tonic-gate */ 661*7c478bd9Sstevel@tonic-gate printf("%s << '...the rest of this file is shell input'\n", shell); 662*7c478bd9Sstevel@tonic-gate 663*7c478bd9Sstevel@tonic-gate um = umask(0); 664*7c478bd9Sstevel@tonic-gate while ((c = getc(pfp)) != EOF) { 665*7c478bd9Sstevel@tonic-gate if (c != '$') 666*7c478bd9Sstevel@tonic-gate putchar(c); 667*7c478bd9Sstevel@tonic-gate else switch (c = getc(pfp)) { 668*7c478bd9Sstevel@tonic-gate case EOF: 669*7c478bd9Sstevel@tonic-gate goto out; 670*7c478bd9Sstevel@tonic-gate case 'd': 671*7c478bd9Sstevel@tonic-gate /* 672*7c478bd9Sstevel@tonic-gate * fork off a child with submitter's permissions, 673*7c478bd9Sstevel@tonic-gate * otherwise, when IFS=/, /usr/bin/pwd would be parsed 674*7c478bd9Sstevel@tonic-gate * by the shell as file "bin". The shell would 675*7c478bd9Sstevel@tonic-gate * then search according to the submitter's PATH 676*7c478bd9Sstevel@tonic-gate * and run the file bin with root permission 677*7c478bd9Sstevel@tonic-gate */ 678*7c478bd9Sstevel@tonic-gate 679*7c478bd9Sstevel@tonic-gate (void) fflush(stdout); 680*7c478bd9Sstevel@tonic-gate dirbuf[0] = NULL; 681*7c478bd9Sstevel@tonic-gate if (pipe(pfd) != 0) 682*7c478bd9Sstevel@tonic-gate atabort("pipe open failed"); 683*7c478bd9Sstevel@tonic-gate realusr = getuid(); /* get realusr before the fork */ 684*7c478bd9Sstevel@tonic-gate if ((pid = fork()) == (pid_t)-1) 685*7c478bd9Sstevel@tonic-gate atabort("fork failed"); 686*7c478bd9Sstevel@tonic-gate if (pid == 0) { /* child process */ 687*7c478bd9Sstevel@tonic-gate (void) close(pfd[0]); 688*7c478bd9Sstevel@tonic-gate /* remove setuid for pwd */ 689*7c478bd9Sstevel@tonic-gate (void) setuid(realusr); 690*7c478bd9Sstevel@tonic-gate if ((xfp = popen("/usr/bin/pwd", "r")) 691*7c478bd9Sstevel@tonic-gate != NULL) { 692*7c478bd9Sstevel@tonic-gate fscanf(xfp, "%" BUFFMT(PATH_MAX) "s", 693*7c478bd9Sstevel@tonic-gate dirbuf); 694*7c478bd9Sstevel@tonic-gate (void) pclose(xfp); 695*7c478bd9Sstevel@tonic-gate xfp = fdopen(pfd[1], "w"); 696*7c478bd9Sstevel@tonic-gate fprintf(xfp, "%s", dirbuf); 697*7c478bd9Sstevel@tonic-gate (void) fclose(xfp); 698*7c478bd9Sstevel@tonic-gate } 699*7c478bd9Sstevel@tonic-gate _exit(0); 700*7c478bd9Sstevel@tonic-gate } 701*7c478bd9Sstevel@tonic-gate (void) close(pfd[1]); /* parent process */ 702*7c478bd9Sstevel@tonic-gate xfp = fdopen(pfd[0], "r"); 703*7c478bd9Sstevel@tonic-gate fscanf(xfp, "%" BUFFMT(PATH_MAX) "s", dirbuf); 704*7c478bd9Sstevel@tonic-gate printf("%s", dirbuf); 705*7c478bd9Sstevel@tonic-gate (void) fclose(xfp); 706*7c478bd9Sstevel@tonic-gate break; 707*7c478bd9Sstevel@tonic-gate case 'm': 708*7c478bd9Sstevel@tonic-gate printf("%o", um); 709*7c478bd9Sstevel@tonic-gate break; 710*7c478bd9Sstevel@tonic-gate case '<': 711*7c478bd9Sstevel@tonic-gate if (ulimit_flag) { 712*7c478bd9Sstevel@tonic-gate if (getrlimit(RLIMIT_FSIZE, &rlp) == 0) { 713*7c478bd9Sstevel@tonic-gate if (rlp.rlim_cur == RLIM_INFINITY) 714*7c478bd9Sstevel@tonic-gate printf("ulimit unlimited\n"); 715*7c478bd9Sstevel@tonic-gate else 716*7c478bd9Sstevel@tonic-gate printf("ulimit %lld\n", 717*7c478bd9Sstevel@tonic-gate rlp.rlim_cur / 512); 718*7c478bd9Sstevel@tonic-gate } 719*7c478bd9Sstevel@tonic-gate } 720*7c478bd9Sstevel@tonic-gate /* 721*7c478bd9Sstevel@tonic-gate * fix for 1113572 - use fputs() so that a 722*7c478bd9Sstevel@tonic-gate * newline isn't appended to the one returned 723*7c478bd9Sstevel@tonic-gate * with fgets(); 1099381 - prompt for input. 724*7c478bd9Sstevel@tonic-gate */ 725*7c478bd9Sstevel@tonic-gate while (fgets(line, LINE_MAX, inputfile) != NULL) { 726*7c478bd9Sstevel@tonic-gate fputs(line, stdout); 727*7c478bd9Sstevel@tonic-gate if (ttyinput) 728*7c478bd9Sstevel@tonic-gate fputs("at> ", stderr); 729*7c478bd9Sstevel@tonic-gate } 730*7c478bd9Sstevel@tonic-gate if (ttyinput) /* clean up the final output */ 731*7c478bd9Sstevel@tonic-gate fputs("<EOT>\n", stderr); 732*7c478bd9Sstevel@tonic-gate break; 733*7c478bd9Sstevel@tonic-gate case 't': 734*7c478bd9Sstevel@tonic-gate printf(":%lu", when); 735*7c478bd9Sstevel@tonic-gate break; 736*7c478bd9Sstevel@tonic-gate default: 737*7c478bd9Sstevel@tonic-gate putchar(c); 738*7c478bd9Sstevel@tonic-gate } 739*7c478bd9Sstevel@tonic-gate } 740*7c478bd9Sstevel@tonic-gate out: 741*7c478bd9Sstevel@tonic-gate fclose(pfp); 742*7c478bd9Sstevel@tonic-gate fflush(NULL); 743*7c478bd9Sstevel@tonic-gate } 744*7c478bd9Sstevel@tonic-gate 745*7c478bd9Sstevel@tonic-gate static int 746*7c478bd9Sstevel@tonic-gate remove_jobs(int argc, char **argv, char *login) 747*7c478bd9Sstevel@tonic-gate /* remove jobs that are specified */ 748*7c478bd9Sstevel@tonic-gate { 749*7c478bd9Sstevel@tonic-gate int i, r; 750*7c478bd9Sstevel@tonic-gate int error = 0; 751*7c478bd9Sstevel@tonic-gate struct stat buf; 752*7c478bd9Sstevel@tonic-gate struct passwd *pw; 753*7c478bd9Sstevel@tonic-gate 754*7c478bd9Sstevel@tonic-gate pw = getpwuid(user); 755*7c478bd9Sstevel@tonic-gate if (pw == NULL) { 756*7c478bd9Sstevel@tonic-gate atabort("Invalid user.\n"); 757*7c478bd9Sstevel@tonic-gate } 758*7c478bd9Sstevel@tonic-gate 759*7c478bd9Sstevel@tonic-gate if (argc == 0) 760*7c478bd9Sstevel@tonic-gate usage(); 761*7c478bd9Sstevel@tonic-gate if (chdir(ATDIR) == -1) 762*7c478bd9Sstevel@tonic-gate atabort(CANTCD); 763*7c478bd9Sstevel@tonic-gate for (i = 0; i < argc; i++) 764*7c478bd9Sstevel@tonic-gate if (strchr(argv[i], '/') != NULL) { 765*7c478bd9Sstevel@tonic-gate fprintf(stderr, "at: %s: not a valid job-id\n", 766*7c478bd9Sstevel@tonic-gate argv[i]); 767*7c478bd9Sstevel@tonic-gate } else if (stat(argv[i], &buf)) { 768*7c478bd9Sstevel@tonic-gate fprintf(stderr, "at: %s: ", argv[i]); 769*7c478bd9Sstevel@tonic-gate perror(""); 770*7c478bd9Sstevel@tonic-gate } else if ((user != buf.st_uid) && 771*7c478bd9Sstevel@tonic-gate (!chkauthattr(CRONADMIN_AUTH, pw->pw_name))) { 772*7c478bd9Sstevel@tonic-gate fprintf(stderr, "at: you don't own %s\n", 773*7c478bd9Sstevel@tonic-gate argv[i]); 774*7c478bd9Sstevel@tonic-gate error = 1; 775*7c478bd9Sstevel@tonic-gate } else { 776*7c478bd9Sstevel@tonic-gate if (chkauthattr(CRONADMIN_AUTH, pw->pw_name)) { 777*7c478bd9Sstevel@tonic-gate login = getuser((uid_t)buf.st_uid); 778*7c478bd9Sstevel@tonic-gate if (login == NULL) { 779*7c478bd9Sstevel@tonic-gate if (per_errno == 2) 780*7c478bd9Sstevel@tonic-gate atabort(BADSHELL); 781*7c478bd9Sstevel@tonic-gate else 782*7c478bd9Sstevel@tonic-gate atabort(INVALIDUSER); 783*7c478bd9Sstevel@tonic-gate } 784*7c478bd9Sstevel@tonic-gate } 785*7c478bd9Sstevel@tonic-gate cron_sendmsg(DELETE, login, argv[i], AT); 786*7c478bd9Sstevel@tonic-gate r = unlink(argv[i]); 787*7c478bd9Sstevel@tonic-gate audit_at_delete(argv[i], ATDIR, r); 788*7c478bd9Sstevel@tonic-gate } 789*7c478bd9Sstevel@tonic-gate return (error); 790*7c478bd9Sstevel@tonic-gate } 791*7c478bd9Sstevel@tonic-gate 792*7c478bd9Sstevel@tonic-gate 793*7c478bd9Sstevel@tonic-gate 794*7c478bd9Sstevel@tonic-gate static int 795*7c478bd9Sstevel@tonic-gate list_jobs(int argc, char **argv, int qflag, int queue) 796*7c478bd9Sstevel@tonic-gate { 797*7c478bd9Sstevel@tonic-gate DIR *dir; 798*7c478bd9Sstevel@tonic-gate int i; 799*7c478bd9Sstevel@tonic-gate int error = 0; 800*7c478bd9Sstevel@tonic-gate char *patdir, *atdir, *ptr; 801*7c478bd9Sstevel@tonic-gate char timebuf[80]; 802*7c478bd9Sstevel@tonic-gate time_t t; 803*7c478bd9Sstevel@tonic-gate struct stat buf, st1, st2; 804*7c478bd9Sstevel@tonic-gate struct dirent *dentry; 805*7c478bd9Sstevel@tonic-gate struct passwd *pw; 806*7c478bd9Sstevel@tonic-gate unsigned int atdirlen; 807*7c478bd9Sstevel@tonic-gate int r; 808*7c478bd9Sstevel@tonic-gate struct passwd *pwd, pwds; 809*7c478bd9Sstevel@tonic-gate char buf_pwd[1024]; 810*7c478bd9Sstevel@tonic-gate char job_file[PATH_MAX]; 811*7c478bd9Sstevel@tonic-gate 812*7c478bd9Sstevel@tonic-gate pwd = getpwuid_r(user, &pwds, buf_pwd, sizeof (buf_pwd)); 813*7c478bd9Sstevel@tonic-gate if (pwd == NULL) { 814*7c478bd9Sstevel@tonic-gate atabort("Invalid user.\n"); 815*7c478bd9Sstevel@tonic-gate } 816*7c478bd9Sstevel@tonic-gate 817*7c478bd9Sstevel@tonic-gate /* list jobs for user */ 818*7c478bd9Sstevel@tonic-gate if (chdir(ATDIR) == -1) 819*7c478bd9Sstevel@tonic-gate atabort(CANTCD); 820*7c478bd9Sstevel@tonic-gate 821*7c478bd9Sstevel@tonic-gate atdirlen = strlen(ATDIR); 822*7c478bd9Sstevel@tonic-gate atdir = xmalloc(atdirlen + 1); 823*7c478bd9Sstevel@tonic-gate strcpy(atdir, ATDIR); 824*7c478bd9Sstevel@tonic-gate patdir = strrchr(atdir, '/'); 825*7c478bd9Sstevel@tonic-gate *patdir = '\0'; 826*7c478bd9Sstevel@tonic-gate if (argc == 0) { 827*7c478bd9Sstevel@tonic-gate /* list all jobs for a user */ 828*7c478bd9Sstevel@tonic-gate if (stat(ATDIR, &st1) != 0 || stat(atdir, &st2) != 0) 829*7c478bd9Sstevel@tonic-gate atabort("Can not get status of spooling" 830*7c478bd9Sstevel@tonic-gate "directory for at"); 831*7c478bd9Sstevel@tonic-gate if ((dir = opendir(ATDIR)) == NULL) 832*7c478bd9Sstevel@tonic-gate atabort(NOOPENDIR); 833*7c478bd9Sstevel@tonic-gate while (1) { 834*7c478bd9Sstevel@tonic-gate if ((dentry = readdir(dir)) == NULL) 835*7c478bd9Sstevel@tonic-gate break; 836*7c478bd9Sstevel@tonic-gate if ((dentry->d_ino == st1.st_ino) || 837*7c478bd9Sstevel@tonic-gate (dentry->d_ino == st2.st_ino)) 838*7c478bd9Sstevel@tonic-gate continue; 839*7c478bd9Sstevel@tonic-gate if ((r = audit_cron_is_anc_name(dentry->d_name)) == 1) 840*7c478bd9Sstevel@tonic-gate continue; 841*7c478bd9Sstevel@tonic-gate if (stat(dentry->d_name, &buf)) { 842*7c478bd9Sstevel@tonic-gate unlink(dentry->d_name); 843*7c478bd9Sstevel@tonic-gate audit_cron_delete_anc_file(dentry->d_name, 844*7c478bd9Sstevel@tonic-gate NULL); 845*7c478bd9Sstevel@tonic-gate continue; 846*7c478bd9Sstevel@tonic-gate } 847*7c478bd9Sstevel@tonic-gate if ((!chkauthattr(CRONADMIN_AUTH, pwd->pw_name)) && 848*7c478bd9Sstevel@tonic-gate (buf.st_uid != user)) 849*7c478bd9Sstevel@tonic-gate continue; 850*7c478bd9Sstevel@tonic-gate ptr = dentry->d_name; 851*7c478bd9Sstevel@tonic-gate if (((t = num(&ptr)) == 0) || (*ptr != '.')) 852*7c478bd9Sstevel@tonic-gate continue; 853*7c478bd9Sstevel@tonic-gate strcpy(job_file, patdir); 854*7c478bd9Sstevel@tonic-gate strcat(job_file, dentry->d_name); 855*7c478bd9Sstevel@tonic-gate if (pflag && not_this_project(job_file)) 856*7c478bd9Sstevel@tonic-gate continue; 857*7c478bd9Sstevel@tonic-gate ascftime(timebuf, FORMAT, localtime(&t)); 858*7c478bd9Sstevel@tonic-gate if ((chkauthattr(CRONADMIN_AUTH, pwd->pw_name)) && 859*7c478bd9Sstevel@tonic-gate ((pw = getpwuid(buf.st_uid)) != NULL)) { 860*7c478bd9Sstevel@tonic-gate if (!qflag || (qflag && 861*7c478bd9Sstevel@tonic-gate check_queue(ptr, queue))) 862*7c478bd9Sstevel@tonic-gate printf("user = %s\t%s\t%s\n", 863*7c478bd9Sstevel@tonic-gate pw->pw_name, dentry->d_name, 864*7c478bd9Sstevel@tonic-gate timebuf); 865*7c478bd9Sstevel@tonic-gate } else 866*7c478bd9Sstevel@tonic-gate if (!qflag || (qflag && 867*7c478bd9Sstevel@tonic-gate check_queue(ptr, queue))) 868*7c478bd9Sstevel@tonic-gate printf("%s\t%s\n", 869*7c478bd9Sstevel@tonic-gate dentry->d_name, timebuf); 870*7c478bd9Sstevel@tonic-gate } 871*7c478bd9Sstevel@tonic-gate (void) closedir(dir); 872*7c478bd9Sstevel@tonic-gate } else /* list particular jobs for user */ 873*7c478bd9Sstevel@tonic-gate for (i = 0; i < argc; i++) { 874*7c478bd9Sstevel@tonic-gate ptr = argv[i]; 875*7c478bd9Sstevel@tonic-gate strlcpy(job_file, patdir, PATH_MAX); 876*7c478bd9Sstevel@tonic-gate strlcat(job_file, ptr, PATH_MAX); 877*7c478bd9Sstevel@tonic-gate if (((t = num(&ptr)) == 0) || (*ptr != '.')) { 878*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext( 879*7c478bd9Sstevel@tonic-gate "at: invalid job name %s\n"), argv[i]); 880*7c478bd9Sstevel@tonic-gate error = 1; 881*7c478bd9Sstevel@tonic-gate } else if (stat(argv[i], &buf)) { 882*7c478bd9Sstevel@tonic-gate fprintf(stderr, "at: %s: ", argv[i]); 883*7c478bd9Sstevel@tonic-gate perror(""); 884*7c478bd9Sstevel@tonic-gate error = 1; 885*7c478bd9Sstevel@tonic-gate } else if ((user != buf.st_uid) && 886*7c478bd9Sstevel@tonic-gate (!chkauthattr(CRONADMIN_AUTH, pwd->pw_name))) { 887*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext( 888*7c478bd9Sstevel@tonic-gate "at: you don't own %s\n"), argv[i]); 889*7c478bd9Sstevel@tonic-gate error = 1; 890*7c478bd9Sstevel@tonic-gate } else if (pflag && not_this_project(job_file)) { 891*7c478bd9Sstevel@tonic-gate continue; 892*7c478bd9Sstevel@tonic-gate } else { 893*7c478bd9Sstevel@tonic-gate if (!qflag || (qflag && 894*7c478bd9Sstevel@tonic-gate check_queue(ptr, queue))) { 895*7c478bd9Sstevel@tonic-gate ascftime(timebuf, FORMAT, 896*7c478bd9Sstevel@tonic-gate localtime(&t)); 897*7c478bd9Sstevel@tonic-gate printf("%s\t%s\n", argv[i], timebuf); 898*7c478bd9Sstevel@tonic-gate } 899*7c478bd9Sstevel@tonic-gate } 900*7c478bd9Sstevel@tonic-gate } 901*7c478bd9Sstevel@tonic-gate return (error); 902*7c478bd9Sstevel@tonic-gate } 903*7c478bd9Sstevel@tonic-gate 904*7c478bd9Sstevel@tonic-gate /* 905*7c478bd9Sstevel@tonic-gate * open the command file and read the project id line 906*7c478bd9Sstevel@tonic-gate * compare to the project number provided via -p on the command line 907*7c478bd9Sstevel@tonic-gate * return 0 if they match, 1 if they don't match or an error occurs. 908*7c478bd9Sstevel@tonic-gate */ 909*7c478bd9Sstevel@tonic-gate #define SKIPCOUNT 3 /* lines to skip to get to project line in file */ 910*7c478bd9Sstevel@tonic-gate 911*7c478bd9Sstevel@tonic-gate static int 912*7c478bd9Sstevel@tonic-gate not_this_project(char *filename) 913*7c478bd9Sstevel@tonic-gate { 914*7c478bd9Sstevel@tonic-gate FILE *fp; 915*7c478bd9Sstevel@tonic-gate projid_t sproj; 916*7c478bd9Sstevel@tonic-gate int i; 917*7c478bd9Sstevel@tonic-gate 918*7c478bd9Sstevel@tonic-gate if ((fp = fopen(filename, "r")) == NULL) 919*7c478bd9Sstevel@tonic-gate return (1); 920*7c478bd9Sstevel@tonic-gate 921*7c478bd9Sstevel@tonic-gate for (i = 0; i < SKIPCOUNT; i++) 922*7c478bd9Sstevel@tonic-gate fscanf(fp, "%*[^\n]\n"); 923*7c478bd9Sstevel@tonic-gate 924*7c478bd9Sstevel@tonic-gate fscanf(fp, ": project: %d\n", &sproj); 925*7c478bd9Sstevel@tonic-gate fclose(fp); 926*7c478bd9Sstevel@tonic-gate 927*7c478bd9Sstevel@tonic-gate return (sproj == project ? 0 : 1); 928*7c478bd9Sstevel@tonic-gate } 929*7c478bd9Sstevel@tonic-gate 930*7c478bd9Sstevel@tonic-gate static int 931*7c478bd9Sstevel@tonic-gate check_queue(char *name, int queue) 932*7c478bd9Sstevel@tonic-gate { 933*7c478bd9Sstevel@tonic-gate if ((name[strlen(name) - 1] - 'a') == queue) 934*7c478bd9Sstevel@tonic-gate return (1); 935*7c478bd9Sstevel@tonic-gate else 936*7c478bd9Sstevel@tonic-gate return (0); 937*7c478bd9Sstevel@tonic-gate } 938*7c478bd9Sstevel@tonic-gate 939*7c478bd9Sstevel@tonic-gate static time_t 940*7c478bd9Sstevel@tonic-gate parse_time(char *t) 941*7c478bd9Sstevel@tonic-gate { 942*7c478bd9Sstevel@tonic-gate int century = 0; 943*7c478bd9Sstevel@tonic-gate int seconds = 0; 944*7c478bd9Sstevel@tonic-gate char *p; 945*7c478bd9Sstevel@tonic-gate time_t when = 0; 946*7c478bd9Sstevel@tonic-gate struct tm tm; 947*7c478bd9Sstevel@tonic-gate 948*7c478bd9Sstevel@tonic-gate /* 949*7c478bd9Sstevel@tonic-gate * time in the following format (defined by the touch(1) spec): 950*7c478bd9Sstevel@tonic-gate * [[CC]YY]MMDDhhmm[.SS] 951*7c478bd9Sstevel@tonic-gate */ 952*7c478bd9Sstevel@tonic-gate if ((p = strchr(t, '.')) != NULL) { 953*7c478bd9Sstevel@tonic-gate if (strchr(p+1, '.') != NULL) 954*7c478bd9Sstevel@tonic-gate atabort(BADTIME); 955*7c478bd9Sstevel@tonic-gate seconds = atoi_for2(p+1); 956*7c478bd9Sstevel@tonic-gate *p = '\0'; 957*7c478bd9Sstevel@tonic-gate } 958*7c478bd9Sstevel@tonic-gate 959*7c478bd9Sstevel@tonic-gate memset(&tm, 0, sizeof (struct tm)); 960*7c478bd9Sstevel@tonic-gate when = time(0); 961*7c478bd9Sstevel@tonic-gate tm.tm_year = localtime(&when)->tm_year; 962*7c478bd9Sstevel@tonic-gate 963*7c478bd9Sstevel@tonic-gate switch (strlen(t)) { 964*7c478bd9Sstevel@tonic-gate case 12: /* CCYYMMDDhhmm */ 965*7c478bd9Sstevel@tonic-gate century = atoi_for2(t); 966*7c478bd9Sstevel@tonic-gate t += 2; 967*7c478bd9Sstevel@tonic-gate case 10: /* YYMMDDhhmm */ 968*7c478bd9Sstevel@tonic-gate tm.tm_year = atoi_for2(t); 969*7c478bd9Sstevel@tonic-gate t += 2; 970*7c478bd9Sstevel@tonic-gate if (century == 0) { 971*7c478bd9Sstevel@tonic-gate if (tm.tm_year < 69) 972*7c478bd9Sstevel@tonic-gate tm.tm_year += 100; 973*7c478bd9Sstevel@tonic-gate } else 974*7c478bd9Sstevel@tonic-gate tm.tm_year += (century - 19) * 100; 975*7c478bd9Sstevel@tonic-gate case 8: /* MMDDhhmm */ 976*7c478bd9Sstevel@tonic-gate tm.tm_mon = atoi_for2(t) - 1; 977*7c478bd9Sstevel@tonic-gate t += 2; 978*7c478bd9Sstevel@tonic-gate tm.tm_mday = atoi_for2(t); 979*7c478bd9Sstevel@tonic-gate t += 2; 980*7c478bd9Sstevel@tonic-gate tm.tm_hour = atoi_for2(t); 981*7c478bd9Sstevel@tonic-gate t += 2; 982*7c478bd9Sstevel@tonic-gate tm.tm_min = atoi_for2(t); 983*7c478bd9Sstevel@tonic-gate t += 2; 984*7c478bd9Sstevel@tonic-gate tm.tm_sec = seconds; 985*7c478bd9Sstevel@tonic-gate break; 986*7c478bd9Sstevel@tonic-gate default: 987*7c478bd9Sstevel@tonic-gate atabort(BADTIME); 988*7c478bd9Sstevel@tonic-gate } 989*7c478bd9Sstevel@tonic-gate 990*7c478bd9Sstevel@tonic-gate if ((when = mktime(&tm)) == -1) 991*7c478bd9Sstevel@tonic-gate atabort(BADTIME); 992*7c478bd9Sstevel@tonic-gate if (tm.tm_isdst) 993*7c478bd9Sstevel@tonic-gate when -= (timezone-altzone); 994*7c478bd9Sstevel@tonic-gate return (when); 995*7c478bd9Sstevel@tonic-gate } 996*7c478bd9Sstevel@tonic-gate 997*7c478bd9Sstevel@tonic-gate static int 998*7c478bd9Sstevel@tonic-gate atoi_for2(char *p) { 999*7c478bd9Sstevel@tonic-gate int value; 1000*7c478bd9Sstevel@tonic-gate 1001*7c478bd9Sstevel@tonic-gate value = (*p - '0') * 10 + *(p+1) - '0'; 1002*7c478bd9Sstevel@tonic-gate if ((value < 0) || (value > 99)) 1003*7c478bd9Sstevel@tonic-gate atabort(BADTIME); 1004*7c478bd9Sstevel@tonic-gate return (value); 1005*7c478bd9Sstevel@tonic-gate } 1006*7c478bd9Sstevel@tonic-gate 1007*7c478bd9Sstevel@tonic-gate static void 1008*7c478bd9Sstevel@tonic-gate usage(void) 1009*7c478bd9Sstevel@tonic-gate { 1010*7c478bd9Sstevel@tonic-gate fprintf(stderr, USAGE); 1011*7c478bd9Sstevel@tonic-gate exit(1); 1012*7c478bd9Sstevel@tonic-gate } 1013