/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2011 Gary Mills
*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
#include <sys/resource.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <pwd.h>
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include <signal.h>
#include <errno.h>
#include <limits.h>
#include <ulimit.h>
#include <unistd.h>
#include <locale.h>
#include <libintl.h>
#include <tzfile.h>
#include <project.h>
#include <paths.h>
#include "cron.h"
/*
* Mode for creating files in ATDIR.
* Setuid bit on so that if an owner of a file gives that file
* away to someone else, the setuid bit will no longer be set.
* If this happens, atrun will not execute the file
*/
"you can't use at"
#define USAGE\
"usage: at [-c|-k|-s] [-m] [-f file] [-p project] [-q queuename] "\
"-t time\n"\
" at [-c|-k|-s] [-m] [-f file] [-p project] [-q queuename] "\
"timespec\n"\
" at -l [-p project] [-q queuename] [at_job_id...]\n"\
" at -r at_job_id ...\n"
static int leap(int);
static int atoi_for2(char *);
static int check_queue(char *, int);
static int list_jobs(int, char **, int, int);
static int remove_jobs(int, char **, char *);
static void usage(void);
static void catch(int);
static int not_this_project(char *);
static time_t parse_time(char *);
static void escapestr(const char *);
void atabort(char *)__NORETURN;
void yyerror(void);
extern int yyparse(void);
extern void audit_at_delete(char *, char *, int);
extern int audit_at_create(char *, int);
extern int audit_cron_is_anc_name(char *);
extern int audit_cron_delete_anc_file(char *, char *);
/*
* Error in getdate(3G)
*/
static char *errlist[] = {
/* 0 */ "",
/* 1 */ "getdate: The DATEMSK environment variable is not set",
/* 2 */ "getdate: Error on \"open\" of the template file",
/* 3 */ "getdate: Error on \"stat\" of the template file",
/* 4 */ "getdate: The template file is not a regular file",
/* 5 */ "getdate: An error is encountered while reading the template",
/* 6 */ "getdate: Malloc(3C) failed",
/* 7 */ "getdate: There is no line in the template that matches the input",
/* 8 */ "getdate: Invalid input specification"
};
int gmtflag = 0;
static int cshflag = 0;
static int kshflag = 0;
static int shflag = 0;
static int mflag = 0;
static int pflag = 0;
static char *Shell;
static char *tfname;
extern char *argp;
extern int per_errno;
int
{
int i, fd;
int try = 0;
int fflag = 0;
int lflag = 0;
int qflag = 0;
int rflag = 0;
int tflag = 0;
int c;
int tflen;
char *file;
char *login;
char *job;
char *proj;
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#endif
(void) textdomain(TEXT_DOMAIN);
if (per_errno == 2)
else
}
switch (c) {
case 'c':
cshflag++;
break;
case 'f':
fflag++;
break;
case 'k':
kshflag++;
break;
case 'l':
lflag++;
break;
case 'm':
mflag++;
break;
case 'p':
pflag++;
else {
gettext("at: user %s is "
"not a member of "
"project %s (%d)\n"),
project);
exit(2);
}
break;
}
pflag++;
else {
gettext("at: user %s is "
"not a member of "
"project %s (%d)\n"),
project);
exit(2);
}
break;
}
"%s not found.\n"), proj);
exit(2);
break;
case 'q':
qflag++;
if (jobtype == 2)
break;
case 'r':
rflag++;
break;
case 's':
shflag++;
break;
case 't':
tflag++;
break;
default:
usage();
}
usage();
if (lflag) {
usage();
}
if (rflag) {
usage();
}
usage();
atabort("ambiguous shell request");
if (jobtype == BATCHEVENT)
if (when == 0) { /* figure out what time to run the job */
argpbuf[0] = '\0';
i = 0;
while (i < argc) {
/* guard against buffer overflow */
if (argplen < 0)
i++;
}
/*
* Fix for 1047182 - we have to let yyparse
* check bounds on mday[] first, then fixup
* the leap year case.
*/
yyparse();
atabort("bad date");
if (!gmtflag) {
}
} else { /* DATEMSK is set */
else
}
}
atabort("too late");
10 + 1; /* 10 for an INT_MAX pid */
/* catch INT, HUP, TERM and QUIT signals */
}
close(1);
/*
* Open the input file with the user's permissions.
*/
exit(1);
}
else
seteuid(0);
} else
sleep(1);
}
}
if (audit_at_create(job, 0))
if (per_errno == 2)
"at: this job may not be executed at the proper time.\n"));
return (0);
}
static char *
mkjobname(t)
time_t t;
{
int i, fd;
char *name;
for (i = 0; i < MAXTRYS; i++) {
/* fix for 1099183, 1116833 - create file here, avoid race */
return (name);
}
t += 1;
}
atabort("queue full");
/* NOTREACHED */
}
static void
catch(int x)
{
exit(1);
}
void
char *msg;
{
exit(1);
}
int
yywrap(void)
{
return (1);
}
void
yyerror(void)
{
}
/*
* add time structures logically
*/
static void
{
a->tm_sec %= 60;
}
a->tm_min %= 60;
}
a->tm_hour %= 24;
}
a->tm_mon %= 12;
}
if (a->tm_mon > 11) {
a->tm_mon = 0;
}
}
}
static int
{
}
/*
* return time from time structure
*/
static time_t
{
int i;
long tv;
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
tv = 0;
/*
* We call isleap since leap() adds
* 1900 onto any value passed
*/
atabort("bad date - not a leap year");
++tv;
return (tv);
}
/*
* Escape a string to be used inside the job shell script.
*/
static void
{
char c;
(void) putchar('\'');
while ((c = *str++) != '\0') {
if (c != '\'')
(void) putchar(c);
else
}
(void) putchar('\'');
}
/*
* make job file from proto + stdin
*/
static void
{
int c;
char *shell;
char **ep;
char *val;
extern char **environ;
int ttyinput;
int ulimit_flag = 0;
char *user;
/*
* Fix for 1099381:
* If the inputfile is from a tty, then turn on prompting, and
* put out a prompt now, instead of waiting for a lot of file
* activity to complete.
*/
if (ttyinput) {
}
/*
* Fix for 1053807:
* Determine what shell we should use to run the job. If the user
* ridden (shflag or cshflag), then we use the current shell.
*/
if (cshflag)
else if (kshflag) {
ulimit_flag = 1;
} else if (shflag) {
ulimit_flag = 1;
(*val != '\0')) {
shell = "$SHELL";
ulimit_flag = 1;
} else {
/* SHELL is NULL or unset, therefore use default */
ulimit_flag = 1;
}
if (pflag) {
} else {
/*
* Check if current user is a member of current project.
* This check is done here to avoid setproject() failure
* later when the job gets executed. If current user does
* not belong to current project, user's default project
* will be used instead. This is achieved by not specifying
* the project (": project: <project>\n") in the job file.
*/
}
}
continue;
*val++ = '\0';
(void) putchar('\n');
*--val = '=';
}
atabort("no prototype");
/*
* Put in a line to run the proper shell using the rest of
* the file as input. Note that 'exec'ing the shell will
*/
if (c != '$')
putchar(c);
case EOF:
goto out;
case 'd':
/*
* Must obtain current working directory as the user
*/
dirbuf[0] = '\0';
/* change euid for getcwd */
}
"can't obtain current working directory");
}
/* change back afterwards */
}
break;
case 'm':
break;
case '<':
if (ulimit_flag) {
printf("ulimit unlimited\n");
else
printf("ulimit %lld\n",
}
}
/*
* fix for 1113572 - use fputs() so that a
* newline isn't appended to the one returned
* with fgets(); 1099381 - prompt for input.
*/
if (ttyinput)
}
if (ttyinput) /* clean up the final output */
break;
case 't':
break;
default:
putchar(c);
}
}
out:
}
static int
/* remove jobs that are specified */
{
int i, r;
int error = 0;
atabort("Invalid user.\n");
}
if (argc == 0)
usage();
for (i = 0; i < argc; i++)
argv[i]);
perror("");
argv[i]);
error = 1;
} else {
if (per_errno == 2)
else
}
}
}
return (error);
}
static int
{
int i;
int error = 0;
time_t t;
unsigned int atdirlen;
int r;
atabort("Invalid user.\n");
}
/* list jobs for user */
*patdir = '\0';
if (argc == 0) {
/* list all jobs for a user */
atabort("Can not get status of spooling"
"directory for at");
while (1) {
break;
continue;
continue;
NULL);
continue;
}
continue;
continue;
continue;
printf("user = %s\t%s\t%s\n",
timebuf);
} else
printf("%s\t%s\n",
}
} else /* list particular jobs for user */
for (i = 0; i < argc; i++) {
"at: invalid job name %s\n"), argv[i]);
error = 1;
perror("");
error = 1;
"at: you don't own %s\n"), argv[i]);
error = 1;
continue;
} else {
localtime(&t));
}
}
}
return (error);
}
/*
* open the command file and read the project id line
* compare to the project number provided via -p on the command line
* return 0 if they match, 1 if they don't match or an error occurs.
*/
static int
{
int i;
return (1);
for (i = 0; i < SKIPCOUNT; i++)
}
static int
{
return (1);
else
return (0);
}
static time_t
parse_time(char *t)
{
int century = 0;
int seconds = 0;
char *p;
/*
* time in the following format (defined by the touch(1) spec):
* [[CC]YY]MMDDhhmm[.SS]
*/
*p = '\0';
}
switch (strlen(t)) {
case 12: /* CCYYMMDDhhmm */
t += 2;
case 10: /* YYMMDDhhmm */
t += 2;
if (century == 0) {
} else
case 8: /* MMDDhhmm */
t += 2;
t += 2;
t += 2;
t += 2;
break;
default:
}
return (when);
}
static int
atoi_for2(char *p) {
int value;
return (value);
}
static void
usage(void)
{
exit(1);
}