BSD 4_3_Tahoe release
[unix-history] / usr / src / usr.bin / at / atq.c
/*
* Copyright (c) 1983 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*/
#ifndef lint
char copyright[] =
"@(#) Copyright (c) 1983 Regents of the University of California.\n\
All rights reserved.\n";
#endif not lint
#ifndef lint
static char sccsid[] = "@(#)atq.c 5.1 (Berkeley) 6/6/85";
#endif not lint
/*
*
* Synopsis: atq [ -c ] [ -n ] [ name ... ]
*
*
* Print the queue of files waiting to be executed. These files
* were created by using the "at" command and are located in the
* directory "/usr/spool/at".
*
*
* Author: Steve Wall
* Computer Systems Research Group
* University of California @ Berkeley
*
*/
# include <stdio.h>
# include <sys/types.h>
# include <sys/file.h>
# include <sys/dir.h>
# include <sys/stat.h>
# include <sys/time.h>
# include <pwd.h>
# include <ctype.h>
# define ATDIR "/usr/spool/at" /* spooling area */
# define LASTFILE "/usr/spool/at/lasttimedone" /* update time record
file */
/*
* Months of the year
*/
static char *mthnames[12] = {
"Jan","Feb","Mar","Apr","May","Jun","Jul",
"Aug","Sep","Oct","Nov","Dec",
};
int numentries; /* number of entries in spooling area */
int namewanted = 0; /* only print jobs belonging to a
certain person */
struct direct **queue; /* the queue itself */
main(argc,argv)
int argc;
char **argv;
{
int cflag = 0; /* print in order of creation time */
int nflag = 0; /* just print the number of jobs in
queue */
int usage(); /* print usage info and exit */
int creation(); /* sort jobs by date of creation */
int alphasort(); /* sort jobs by date of execution */
int filewanted(); /* should a file be included in queue?*/
int printqueue(); /* print the queue */
int countfiles(); /* count the number of files in queue
for a given person */
char **namelist; /* array of specific name(s) requested*/
--argc, ++argv;
/*
* Interpret command line flags if they exist.
*/
while (argc > 0 && **argv == '-') {
(*argv)++;
while (**argv) switch (*(*argv)++) {
case 'c' : cflag++;
break;
case 'n' : nflag++;
break;
default : usage();
}
--argc, ++argv;
}
/*
* If a certain name (or names) is requested, set a pointer to the
* beginning of the list.
*/
if (**argv) {
++namewanted;
namelist = argv;
}
/*
* Move to the spooling area and scan the directory, placing the
* files in the queue structure. The queue comes back sorted by
* execution time or creation time.
*/
if (chdir(ATDIR) == -1) {
perror(ATDIR);
exit(1);
}
if ((numentries = scandir(".",&queue,filewanted, (cflag) ? creation :
alphasort)) < 0) {
perror(ATDIR);
exit(1);
}
/*
* Either print a message stating:
*
* 1) that the spooling area is empty.
* 2) the number of jobs in the spooling area.
* 3) the number of jobs in the spooling area belonging to
* a certain person.
* 4) that the person requested doesn't have any files in the
* spooling area.
*
* or send the queue off to "printqueue" for printing.
*
* This whole process might seem a bit elaborate, but it's worthwhile
* to print some informative messages for the user.
*
*/
if ((numentries == 0) && (!nflag)) {
printf("no files in queue.\n");
exit(0);
}
if (nflag) {
printf("%d\n",(namewanted) ? countfiles(namelist) : numentries);
exit(0);
}
if ((namewanted) && (countfiles(namelist) == 0)) {
printf("no files for %s.\n", (argc == 1) ?
*argv : "specified users");
exit(0);
}
printqueue(namelist);
exit(0);
}
/*
* Count the number of jobs in the spooling area owned by a certain person(s).
*/
countfiles(namelist)
char **namelist;
{
int i; /* for loop index */
int entryfound; /* found file owned by user(s)*/
int numfiles = 0; /* number of files owned by a
certain person(s) */
char **ptr; /* scratch pointer */
/*
* For each file in the queue, see if the user(s) own the file. We
* have to use "entryfound" (rather than simply incrementing "numfiles")
* so that if a person's name appears twice on the command line we
* don't double the number of files owned by him/her.
*/
for (i = 0; i < numentries ; i++) {
ptr = namelist;
entryfound = 0;
while (*ptr) {
if (isowner(*ptr,queue[i]->d_name))
++entryfound;
++ptr;
}
if (entryfound)
++numfiles;
}
return(numfiles);
}
/*
* Print the queue. If only jobs belonging to a certain person(s) are requested,
* only print jobs that belong to that person(s).
*/
printqueue(namelist)
char **namelist;
{
int i; /* for loop index */
int rank = 1; /* rank of a job */
int entryfound; /* found file owned by user(s)*/
int printrank(); /* print the rank of a job */
int plastrun(); /* print the last time the
spooling area was updated */
int powner(); /* print the name of the owner
of the job */
int getid(); /* get uid of a person */
char **ptr; /* scratch pointer */
struct stat stbuf; /* buffer for file stats */
/*
* Print the time the spooling area was last modified and the header
* for the queue.
*/
plastrun();
printf(" Rank Execution Date Owner Job # Job Name\n");
/*
* Print the queue. If a certain name(s) was requested, print only jobs
* belonging to that person(s), otherwise print the entire queue.
* Once again, we have to use "entryfound" (rather than simply
* comparing each command line argument) so that if a person's name
* appears twice we don't print each file owned by him/her twice.
*
*
* "printrank", "printdate", and "printjobname" all take existing
* data and display it in a friendly manner.
*
*/
for (i = 0; i < numentries; i++) {
if ((stat(queue[i]->d_name, &stbuf)) < 0) {
continue;
}
if (namewanted) {
ptr = namelist;
entryfound = 0;
while (*ptr) {
if (isowner(*ptr,queue[i]->d_name))
++entryfound;
++ptr;
}
if (!entryfound)
continue;
}
printrank(rank++);
printdate(queue[i]->d_name);
powner(queue[i]->d_name);
printf("%5d",stbuf.st_ino);
printjobname(queue[i]->d_name);
}
++ptr;
}
/*
* See if "name" owns "job".
*/
isowner(name,job)
char *name;
char *job;
{
char buf[30]; /* buffer for 1st line of spoolfile
header */
FILE *infile; /* I/O stream to spoolfile */
if ((infile = fopen(job,"r")) == NULL) {
fprintf(stderr,"Couldn't open spoolfile");
perror(job);
return(0);
}
if (fscanf(infile,"# owner: %s\n",buf) != 1) {
fclose(infile);
return(0);
}
fclose(infile);
return((strcmp(name,buf) == 0) ? 1 : 0);
}
/*
* Print the owner of the job. This is stored on the first line of the
* spoolfile. If we run into trouble getting the name, we'll just print "???".
*/
powner(file)
char *file;
{
char owner[80]; /* the owner */
FILE *infile; /* I/O stream to spoolfile */
/*
* Open the job file and grab the first line.
*/
if ((infile = fopen(file,"r")) == NULL) {
printf("%-10.9s","???");
return;
}
if (fscanf(infile,"# owner: %s",owner) != 1) {
printf("%-10.9s","???");
fclose(infile);
return;
}
fclose(infile);
printf("%-10.9s",owner);
}
/*
* Get the uid of a person using his/her login name. Return -1 if no
* such account name exists.
*/
getid(name)
char *name;
{
struct passwd *pwdinfo; /* password info structure */
if ((pwdinfo = getpwnam(name)) == 0)
return(-1);
return(pwdinfo->pw_uid);
}
/*
* Print the time the spooling area was updated.
*/
plastrun()
{
struct timeval now; /* time it is right now */
struct timezone zone; /* NOT USED */
struct tm *loc; /* detail of time it is right */
u_long lasttime; /* last update time in seconds
since 1/1/70 */
FILE *last; /* file where last update hour
is stored */
/*
* Open the file where the last update time is stored, and grab the
* last update hour. The update time is measured in seconds since
* 1/1/70.
*/
if ((last = fopen(LASTFILE,"r")) == NULL) {
perror(LASTFILE);
exit(1);
}
fscanf(last,"%d",(u_long) &lasttime);
fclose(last);
/*
* Get a broken down representation of the last update time.
*/
loc = localtime(&lasttime);
/*
* Print the time that the spooling area was last updated.
*/
printf("\n LAST EXECUTION TIME: %s ",mthnames[loc->tm_mon]);
printf("%d, 19%d ",loc->tm_mday,loc->tm_year);
printf("at %d:%02d\n\n",loc->tm_hour,loc->tm_min);
}
/*
* Print the rank of a job. (I've got to admit it, I stole it from "lpq")
*/
static
printrank(n)
{
static char *r[] = {
"th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
};
if ((n/10) == 1)
printf("%3d%-5s", n,"th");
else
printf("%3d%-5s", n, r[n%10]);
}
/*
* Print the date that a job is to be executed. This takes some manipulation
* of the file name.
*/
printdate(filename)
char *filename;
{
int yday = 0; /* day of year file will be
executed */
int min = 0; /* min. file will be executed */
int hour = 0; /* hour file will be executed */
int day = 0; /* day file will be executed */
int month = 0; /* month file will be executed*/
int year = 0; /* year file will be executed */
int get_mth_day(); /* convert a day of year to a
month and day of month */
char date[18]; /* reformatted execution date */
/*
* Pick off the necessary info from the file name and convert the day
* of year to a month and day of month.
*/
sscanf(filename,"%2d.%3d.%2d%2d",&year,&yday,&hour,&min);
get_mth_day(year,yday,&month,&day);
/*
* Format the execution date of a job.
*/
sprintf(date,"%3s %2d, 19%2d %02d:%02d",mthnames[month],
day, year,hour,min);
/*
* Print the date the job will be executed.
*/
printf("%-21.18s",date);
}
/*
* Given a day of the year, calculate the month and day of month.
*/
get_mth_day(year,dayofyear,month,day)
int year, dayofyear, *month, *day;
{
int i = 1; /* for loop index */
int leap; /* are we dealing with a leap
year? */
/* Table of the number of days
in each month of the year.
dofy_tab[1] -- regular year
dofy_tab[2] -- leap year
*/
static int dofy_tab[2][13] = {
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{ 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
};
/*
* Are we dealing with a leap year?
*/
leap = ((year%4 == 0 && year%100 != 0) || year%100 == 0);
/*
* Calculate the month of the year and day of the month.
*/
while (dayofyear >= dofy_tab[leap][i]) {
dayofyear -= dofy_tab[leap][i++];
++(*month);
}
*day = (dayofyear + 1);
}
/*
* Print a job name. If the old "at" has been used to create the spoolfile,
* the three line header that the new version of "at" puts in the spoolfile.
* Thus, we just print "???".
*/
printjobname(file)
char *file;
{
char *ptr; /* scratch pointer */
char jobname[80]; /* the job name */
FILE *filename; /* job file in spooling area */
/*
* Open the job file and grab the second line.
*/
printf(" ");
if ((filename = fopen(file,"r")) == NULL) {
printf("%.27s\n", "???");
return;
}
/*
* We'll yank the first line into the buffer temporarily.
*/
fgets(jobname,80,filename);
/*
* Now get the job name.
*/
if (fscanf(filename,"# jobname: %s",jobname) != 1) {
printf("%.27s\n", "???");
fclose(filename);
return;
}
fclose(filename);
/*
* Put a pointer at the begining of the line and remove the basename
* from the job file.
*/
ptr = jobname;
if ((ptr = (char *)rindex(jobname,'/')) != 0)
++ptr;
else
ptr = jobname;
if (strlen(ptr) > 23)
printf("%.23s ...\n",ptr);
else
printf("%.27s\n",ptr);
}
/*
* Do we want to include a file in the queue? (used by "scandir") We are looking
* for files with following syntax: yy.ddd.hhhh. so the test is made to see if
* the file name has three dots in it. This test will suffice since the only
* other files in /usr/spool/at don't have any dots in their name.
*/
filewanted(direntry)
struct direct *direntry;
{
int numdot = 0;
char *filename;
filename = direntry->d_name;
while (*filename)
numdot += (*(filename++) == '.');
return(numdot == 3);
}
/*
* Sort files by time of creation. (used by "scandir")
*/
creation(d1, d2)
struct direct **d1, **d2;
{
struct stat stbuf1, stbuf2;
if (stat((*d1)->d_name,&stbuf1) < 0)
return(1);
if (stat((*d2)->d_name,&stbuf2) < 0)
return(1);
return(stbuf1.st_ctime < stbuf2.st_ctime);
}
/*
* Print usage info and exit.
*/
usage()
{
fprintf(stderr,"usage: atq [-c] [-n] [name ...]\n");
exit(1);
}