1 /*-
2 * Copyright (c) 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1988, 1993\n\
11 The Regents of the University of California. All rights reserved.\n";
12 #endif /* not lint */
13
14 #ifndef lint
15 static char sccsid[] = "@(#)uuq.c 8.1 (Berkeley) 06/06/93";
16 #endif /* not lint */
17
18 /*
19 * uuq - looks at uucp queues
20 *
21 * Lou Salkind
22 * New York University
23 *
24 */
25
26 #include "uucp.h"
27 #include <stdio.h>
28
29 #ifdef NDIR
30 #include "libndir/ndir.h"
31 #else !NDIR
32 #include <sys/dir.h>
33 #endif !NDIR
34 #include <sys/stat.h>
35
36 #define NOSYS (struct sys *)0
37
38 #define W_TYPE wrkvec[0]
39 #define W_FILE1 wrkvec[1]
40 #define W_FILE2 wrkvec[2]
41 #define W_USER wrkvec[3]
42 #define W_OPTNS wrkvec[4]
43 #define W_DFILE wrkvec[5]
44 #define W_MODE wrkvec[6]
45 #define WSUFSIZE 5 /* work file name suffix size */
46
47 struct sys {
48 char s_name[8];
49 int s_njobs;
50 off_t s_bytes;
51 struct job *s_jobp;
52 struct sys *s_sysp;
53 };
54
55 struct job {
56 int j_files;
57 int j_flags;
58 char j_jobno[WSUFSIZE];
59 char j_user[22];
60 char j_fname[128];
61 char j_grade;
62 off_t j_bytes;
63 time_t j_date;
64 struct job *j_jobp;
65 };
66
67 struct sys *syshead;
68 struct sys *getsys();
69 int jcompare();
70 char *sysname;
71 char *user;
72 char *rmjob;
73 int hflag;
74 int lflag;
75
76 char *malloc(), *calloc();
77 double atof();
78 float baudrate = 2400.;
79 char Username[BUFSIZ];
80 char Filename[BUFSIZ];
81 int Maxulen = 0;
82 struct timeb Now;
83
main(argc,argv)84 main(argc, argv)
85 int argc;
86 char **argv;
87 {
88 register int i;
89 register struct sys *sp;
90 register struct job *jp;
91 struct job **sortjob;
92 int nsys;
93 extern char *optarg;
94 extern int optind;
95
96 strcpy(Progname, "uuq");
97 uucpname(Myname);
98
99 while ((i = getopt(argc, argv, "r:S:s:u:d:b:hl")) != EOF)
100 switch (i) {
101 case 'r':
102 case 'S':
103 Spool = optarg;
104 break;
105 case 's':
106 sysname = optarg;
107 if (strlen(sysname) > SYSNSIZE)
108 sysname[SYSNSIZE] = '\0';
109 break;
110 case 'u':
111 user = optarg;
112 break;
113 case 'd':
114 rmjob = optarg;
115 break;
116 case 'b':
117 baudrate = atof(optarg);
118 break;
119 case 'h':
120 hflag++;
121 break;
122 case 'l':
123 lflag++;
124 break;
125 default:
126 fprintf(stderr,
127 "usage: uuq [-l] [-h] [-ssystem] [-uuser] [-djobno] [-rspool] [-bbaudrate]\n");
128 exit(0);
129 }
130
131 subchdir(Spool);
132 baudrate *= 0.7; /* reduce speed because of protocol overhead */
133 baudrate *= 7.5; /* convert to chars/minute (60/8) */
134 gather();
135 nsys = 0;
136 for (sp = syshead; sp; sp = sp->s_sysp) {
137 if (sp->s_njobs == 0)
138 continue;
139 if (!hflag && nsys++ > 0)
140 putchar('\n');
141 printf("%s: %d %s", sp->s_name,
142 sp->s_njobs, sp->s_njobs > 1 ? "jobs" : "job");
143 if (lflag) {
144 float minutes;
145 int hours;
146 /* The 80 * njobs is because of the uucp handshaking */
147 minutes = (float)(sp->s_bytes + 80 * sp->s_njobs)/baudrate;
148 hours = minutes/60;
149 printf(", %ld bytes, ", sp->s_bytes);
150 if (minutes > 60){
151 printf("%d hour%s, ",hours,
152 hours > 1 ? "s": "");
153 minutes -= 60 * hours;
154 }
155 printf("%3.1f minutes (@ effective baudrate of %d)",
156 minutes,(int)(baudrate/6));
157 }
158 putchar('\n');
159 if (hflag)
160 continue;
161 /* sort them babies! */
162 sortjob = (struct job **)calloc(sp->s_njobs, sizeof (struct job *));
163 for (i=0, jp=sp->s_jobp; i < sp->s_njobs; i++, jp=jp->j_jobp)
164 sortjob[i] = jp;
165 qsort(sortjob, sp->s_njobs, sizeof (struct job *), jcompare);
166 for (i = 0; i < sp->s_njobs; i++) {
167 jp = sortjob[i];
168 if (lflag) {
169 printf("%s %2d %-*s%7ld%5.1f %-12.12s %c %.*s\n",
170 jp->j_jobno, jp->j_files, Maxulen, jp->j_user, jp->j_bytes, jp->j_bytes/baudrate,
171 ctime(&jp->j_date) + 4, jp->j_flags, sizeof (jp->j_fname), jp->j_fname
172 );
173 } else {
174 printf("%s", jp->j_jobno);
175 putchar((i+1)%10 ? '\t' : '\n');
176 }
177 /* There's no need to keep the force poll if jobs > 1*/
178 if (sp->s_njobs > 1 && strcmp("POLL", jp->j_jobno)==0) {
179 char pbuf[BUFSIZ];
180 sprintf(pbuf,"%s/%c.%s%cPOLL",
181 subdir(Spool, CMDPRE), CMDPRE,
182 sp->s_name, jp->j_grade);
183 (void) unlink(pbuf);
184 }
185 }
186 if (!lflag && (sp->s_njobs%10))
187 putchar('\n');
188 }
189 exit(0);
190 }
191
192 jcompare(j1, j2)
193 struct job **j1, **j2;
194 {
195 int delta;
196
197 delta = (*j1)->j_grade - (*j2)->j_grade;
198 if (delta)
199 return delta;
200 return(strcmp((*j1)->j_jobno,(*j2)->j_jobno));
201 }
202
203 /*
204 * Get all the command file names
205 */
gather()206 gather()
207 {
208 struct direct *d;
209 DIR *df;
210
211 /*
212 * Find all the spool files in the spooling directory
213 */
214 if ((df = opendir(subdir(Spool, CMDPRE))) == NULL) {
215 fprintf(stderr, "can't examine spooling area\n");
216 exit(1);
217 }
218 for (;;) {
219 if ((d = readdir(df)) == NULL)
220 break;
221 if (d->d_namlen <= 2 || d->d_name[0] != CMDPRE ||
222 d->d_name[1] != '.')
223 continue;
224 if (analjob(d->d_name) < 0) {
225 fprintf(stderr, "out of memory\n");
226 break;
227 }
228 }
229 closedir(df);
230 }
231
232 /*
233 * analjob does the grunge work of verifying jobs
234 */
235 #include <pwd.h>
analjob(filename)236 analjob(filename)
237 char *filename;
238 {
239 struct job *jp;
240 struct sys *sp;
241 char sbuf[MAXNAMLEN+1], str[256], nbuf[256];
242 char *jptr, *wrkvec[20];
243 char grade;
244 FILE *fp, *df;
245 struct stat statb;
246 int files, gotname, i;
247 off_t bytes;
248
249 strncpy(sbuf, filename, MAXNAMLEN);
250 sbuf[MAXNAMLEN] = '\0';
251 jptr = sbuf + strlen(sbuf) - WSUFSIZE;
252 grade = *jptr;
253 *jptr++ = 0;
254 /*
255 * sbuf+2 now points to sysname name (null terminated)
256 * jptr now points to job number (null terminated)
257 */
258 if (rmjob) {
259 if (strcmp(rmjob, jptr))
260 return(0);
261 } else {
262 if ((sp = getsys(sbuf+2)) == NOSYS)
263 return(0);
264 if (!lflag) {
265 /* SHOULD USE A SMALLER STRUCTURE HERE */
266 jp = (struct job *)malloc(sizeof(struct job));
267 if (jp == (struct job *)0)
268 return(-1);
269 strcpy(jp->j_jobno, jptr);
270 jp->j_jobp = sp->s_jobp;
271 jp->j_grade = grade;
272 sp->s_jobp = jp;
273 sp->s_njobs++;
274 return(1);
275 }
276 }
277 if ((fp = fopen(subfile(filename), "r")) == NULL) {
278 perror(subfile(filename));
279 return(0);
280 }
281 files = 0;
282 bytes = 0;
283 gotname = 0;
284 while (fgets(str, sizeof str, fp)) {
285 if (getargs(str, wrkvec, 20) <= 0)
286 continue;
287 if (rmjob) {
288 int myuid;
289 struct passwd *pw;
290 /*
291 * Make sure person who is removing data files is
292 * the person who created it or root.
293 */
294 myuid = getuid();
295 pw = getpwnam(W_USER);
296 if (myuid && (pw == NULL || myuid != pw->pw_uid)) {
297 fprintf(stderr, "Permission denied.\n");
298 exit(1);
299 }
300 if (W_TYPE[0] == 'S' && !index(W_OPTNS, 'c')) {
301 unlink(subfile(W_DFILE));
302 fprintf(stderr, "Removing data file %s\n", W_DFILE);
303 }
304 continue;
305 }
306 if (user && (W_TYPE[0] == 'X' || !prefix(user, W_USER))) {
307 fclose(fp);
308 return(0);
309 }
310 files++;
311 if (W_TYPE[0] == 'S') {
312 if (strcmp(W_DFILE, "D.0") &&
313 stat(subfile(W_DFILE), &statb) >= 0)
314 bytes += statb.st_size;
315 else if (stat(subfile(W_FILE1), &statb) >= 0)
316 bytes += statb.st_size;
317 }
318 /* amusing heuristic */
319 #define isXfile(s) (s[0]=='D' && s[strlen(s)-WSUFSIZE]=='X')
320 if (gotname == 0 && isXfile(W_FILE1)) {
321 if ((df = fopen(subfile(W_FILE1), "r")) == NULL)
322 continue;
323 while (fgets(nbuf, sizeof nbuf, df)) {
324 nbuf[strlen(nbuf) - 1] = '\0';
325 if (nbuf[0] == 'C' && nbuf[1] == ' ') {
326 strcpy(Filename, nbuf+2);
327 gotname++;
328 } else if (nbuf[0] == 'R' && nbuf[1] == ' ') {
329 register char *p, *q, *r;
330 r = q = p = nbuf+2;
331 do {
332 if (*p == '!' || *p == '@'){
333 r = q;
334 q = p+1;
335 }
336 } while (*p++);
337
338 strcpy(Username, r);
339 W_USER = Username;
340 }
341 }
342 fclose(df);
343 }
344 }
345 fclose(fp);
346 if (rmjob) {
347 unlink(subfile(filename));
348 fprintf(stderr, "Removing command file %s\n", filename);
349 exit(0);
350 }
351 if (files == 0) {
352 static char *wtype = "X";
353 static char *wfile = "forced poll";
354 if (strcmp("POLL", &filename[strlen(filename)-4])) {
355 fprintf(stderr, "%.14s: empty command file\n", filename);
356 return(0);
357 }
358 W_TYPE = wtype;
359 W_FILE1 = wfile;
360 }
361 jp = (struct job *)malloc(sizeof(struct job));
362 if (jp == (struct job *)0)
363 return(-1);
364 strcpy(jp->j_jobno, jptr);
365 jp->j_files = files;
366 jp->j_bytes = bytes;
367 jp->j_grade = grade;
368 jp->j_flags = W_TYPE[0];
369 strncpy(jp->j_user, W_TYPE[0]=='X' ? "---" : W_USER, 20 );
370 jp->j_user[20] = '\0';
371 i = strlen(jp->j_user);
372 if (i > Maxulen)
373 Maxulen = i;
374 /* SHOULD ADD ALL INFORMATION IN THE WHILE LOOP */
375 if (gotname)
376 strncpy(jp->j_fname, Filename, sizeof jp->j_fname);
377 else
378 strncpy(jp->j_fname, W_FILE1, sizeof jp->j_fname);
379 stat(subfile(filename), &statb);
380 jp->j_date = statb.st_mtime;
381 jp->j_jobp = sp->s_jobp;
382 sp->s_jobp = jp;
383 sp->s_njobs++;
384 sp->s_bytes += jp->j_bytes;
385 return(1);
386 }
387
388 struct sys *
getsys(s)389 getsys(s)
390 register char *s;
391 {
392 register struct sys *sp;
393
394 for (sp = syshead; sp; sp = sp->s_sysp)
395 if (strcmp(s, sp->s_name) == 0)
396 return(sp);
397 if (sysname && !prefix(sysname, s))
398 return(NOSYS);
399 sp = (struct sys *)malloc(sizeof(struct sys));
400 if (sp == NOSYS)
401 return(NOSYS);
402 strcpy(sp->s_name, s);
403 sp->s_njobs = 0;
404 sp->s_jobp = (struct job *)0;
405 sp->s_sysp = syshead;
406 sp->s_bytes = 0;
407 syshead = sp;
408 return(sp);
409 }
410