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