2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 * Copyright (c) 2016 by Delphix. All rights reserved.
7 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
8 /* All Rights Reserved */
12 * Copyright (c) 1983 Regents of the University of California.
13 * All rights reserved. The Berkeley software License Agreement
14 * specifies the terms and conditions for redistribution.
18 * synopsis: atrm [-f] [-i] [-a] [[job #] [user] ...]
27 #include <sys/types.h>
38 #include "getresponse.h"
41 extern char *errmsg();
42 extern void audit_at_delete(char *, char *, int);
44 #define SUPERUSER 0 /* is user super-user? */
45 #define CANTCD "can't change directory to the at directory"
46 #define NOREADDIR "can't read the at directory"
48 uid_t user
; /* person requesting removal */
49 int fflag
= 0; /* suppress announcements? */
50 int iflag
= 0; /* run interactively? */
52 char login
[UNAMESIZE
];
53 char login_authchk
[UNAMESIZE
]; /* used for authorization checks */
55 #define INVALIDUSER "you are not a valid user (no entry in /etc/passwd)"
56 #define NOTALLOWED "you are not authorized to use at. Sorry."
57 #define NAMETOOLONG "login name too long"
59 static void usage(void);
60 static void atabortperror(char *msg
);
61 static void atabort(char *msg
);
62 static void atperror(char *msg
);
63 static void atperror2(char *msg
, char *name
);
64 static void aterror(char *msg
);
65 static void powner(char *file
);
67 int getjoblist(struct dirent
***, struct stat
***, int (*)());
68 int removentry(char *, struct stat
*, uid_t
);
71 main(int argc
, char **argv
)
73 int i
; /* for loop index */
74 int numjobs
; /* # of jobs in spooling area */
75 int allflag
= 0; /* remove all jobs belonging to user? */
76 int jobexists
; /* does a requested job exist? */
78 struct dirent
**namelist
; /* names of jobs in spooling area */
79 struct stat
**statlist
;
83 * If job number, user name, or "-" is not specified, just print
84 * usage info and exit.
86 (void) setlocale(LC_ALL
, "");
87 (void) textdomain(TEXT_DOMAIN
);
93 pp
= getuser((user
= getuid()));
96 if (strlcpy(login
, pp
, sizeof (login
)) >= sizeof (login
))
98 if (strlcpy(login_authchk
, pp
, sizeof (login_authchk
))
99 >= sizeof (NAMETOOLONG
))
100 atabort(INVALIDUSER
);
101 if (!allowed(login
, ATALLOW
, ATDENY
))
105 * Process command line flags.
106 * Special case the "-" option so that others may be grouped.
108 while (argc
> 0 && **argv
== '-') {
111 switch (*(*argv
)++) {
129 * If all jobs are to be removed and extra command line arguments
130 * are given, print usage info and exit.
136 * If only certain jobs are to be removed and no job #'s or user
137 * names are specified, print usage info and exit.
139 if (!allflag
&& !argc
)
143 * If interactive removal and quiet removal are requested, override
144 * quiet removal and run interactively.
151 * Move to spooling directory and get a list of the files in the
154 numjobs
= getjoblist(&namelist
, &statlist
, strcmp
);
156 * If all jobs belonging to the user are to be removed, compare
157 * the user's id to the owner of the file. If they match, remove
158 * the file. If the user is the super-user, don't bother comparing
159 * the id's. After all files are removed, exit (status 0).
162 for (i
= 0; i
< numjobs
; ++i
) {
163 if (cron_admin(login_authchk
) ||
164 user
== statlist
[i
]->st_uid
)
165 (void) removentry(namelist
[i
]->d_name
,
172 * If only certain jobs are to be removed, interpret each command
173 * line argument. A check is done to see if it is a user's name or
174 * a job number (inode #). If it's a user's name, compare the argument
175 * to the files owner. If it's a job number, compare the argument to
176 * the file name. In either case, if a match occurs, try to
182 for (i
= 0; i
< numjobs
; ++i
) {
184 /* if the inode number is 0, this entry was removed */
185 if (statlist
[i
]->st_ino
== 0)
189 * if argv is a username, compare their uid to
190 * the uid of the owner of the file......
192 if (pwd
= getpwnam(*argv
)) {
193 if (statlist
[i
]->st_uid
!= pwd
->pw_uid
)
196 * otherwise, we assume that the argv is a job # and
197 * thus compare argv to the file name.
200 if (strcmp(namelist
[i
]->d_name
, *argv
))
205 * if the entry is ultimately removed, don't
206 * try to remove it again later.
208 if (removentry(namelist
[i
]->d_name
, statlist
[i
],
210 statlist
[i
]->st_ino
= 0;
215 * If a requested argument doesn't exist, print a message.
217 if (!jobexists
&& !fflag
) {
218 fprintf(stderr
, "atrm: %s: no such job number\n",
227 * Print usage info and exit.
232 fprintf(stderr
, "usage: atrm [-f] [-i] [-a] [[job #] [user] ...]\n");
238 * Remove an entry from the queue. The access of the file is checked for
239 * write permission (since all jobs are mode 644). If access is granted,
240 * unlink the file. If the fflag (suppress announcements) is not set,
241 * print the job number that we are removing and the result of the access
242 * check (either "permission denied" or "removed"). If we are running
243 * interactively (iflag), prompt the user before we unlink the file. If
244 * the super-user is removing jobs, inform them who owns each file before
245 * it is removed. Return TRUE if file removed, else FALSE.
248 removentry(char *filename
, struct stat
*statptr
, uid_t user
)
254 if (init_yes() < 0) {
255 (void) fprintf(stderr
, gettext(ERR_MSG_INIT_YES
),
261 printf("%s: ", filename
);
263 if (user
!= statptr
->st_uid
&& !cron_admin(login_authchk
)) {
266 printf("permission denied\n");
272 if (cron_admin(login_authchk
)) {
273 printf("\t(owned by ");
277 printf(gettext("remove it? "));
282 if (cron_admin(login_authchk
)) {
283 pp
= getuser((uid_t
)statptr
->st_uid
);
285 atabort(INVALIDUSER
);
286 if (strlcpy(login
, pp
, sizeof (login
)) >=
288 atabort(NAMETOOLONG
);
290 cron_sendmsg(DELETE
, login
, filename
, AT
);
291 if ((r
= unlink(filename
)) < 0) {
293 fputs("could not remove\n", stdout
);
294 (void) fprintf(stderr
, "atrm: %s: %s\n",
295 filename
, errmsg(errno
));
297 audit_at_delete(filename
, NULL
, r
);
300 audit_at_delete(filename
, NULL
, r
);
301 if (!fflag
&& !iflag
)
308 * Print the owner of the job. This is the owner of the spoolfile.
309 * If we run into trouble getting the name, we'll just print "???".
317 if (stat(file
, &statb
) < 0) {
319 (void) fprintf(stderr
, "atrm: Couldn't stat spoolfile %s: %s\n",
320 file
, errmsg(errno
));
324 printf("%s", getname(statb
.st_uid
));
329 getjoblist(struct dirent
***namelistp
, struct stat
***statlistp
,
333 struct dirent
**namelist
;
335 struct stat
*statptr
; /* pointer to file stat structure */
336 struct stat
**statlist
;
337 extern int filewanted(); /* should a file be listed in queue? */
338 if (chdir(ATDIR
) < 0)
339 atabortperror(CANTCD
);
342 * Get a list of the files in the spooling area.
344 if ((numjobs
= scandir(".", namelistp
, filewanted
, sortfunc
)) < 0)
345 atabortperror(NOREADDIR
);
348 (struct stat
**)malloc(numjobs
* sizeof (struct stat
***)))
350 atabort("Out of memory");
352 namelist
= *namelistp
;
355 * Build an array of pointers to the file stats for all jobs in
358 for (i
= 0; i
< numjobs
; ++i
) {
359 statptr
= (struct stat
*)malloc(sizeof (struct stat
));
361 atabort("Out of memory");
362 if (stat(namelist
[i
]->d_name
, statptr
) < 0) {
363 atperror2("Can't stat", namelist
[i
]->d_name
);
366 statlist
[i
] = statptr
;
369 *statlistp
= statlist
;
374 * Get the full login name of a person using their user id.
379 struct passwd
*pwdinfo
; /* password info structure */
382 if ((pwdinfo
= getpwuid(uid
)) == 0)
384 return (pwdinfo
->pw_name
);
390 fprintf(stderr
, "atrm: %s\n", msg
);
396 fprintf(stderr
, "atrm: %s: %s\n", msg
, errmsg(errno
));
400 atperror2(char *msg
, char *name
)
402 fprintf(stderr
, "atrm: %s %s: %s\n", msg
, name
, errmsg(errno
));
413 atabortperror(char *msg
)