1 /*- 2 * Copyright (c) 1988 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1988 The Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)uuq.c 4.12 (Berkeley) 04/24/91"; 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 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 */ 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> 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 * 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