1 /* sys7.unx 2 System dependent routines for uustat. 3 4 Copyright (C) 1992 Ian Lance Taylor 5 6 This file is part of the Taylor UUCP package. 7 8 This program is free software; you can redistribute it and/or 9 modify it under the terms of the GNU General Public License as 10 published by the Free Software Foundation; either version 2 of the 11 License, or (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, but 14 WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 22 The author of the program may be contacted at ian@airs.com or 23 c/o AIRS, P.O. Box 520, Waltham, MA 02254. 24 25 $Log: sys7.unx,v $ 26 Revision 1.11 1992/03/28 04:19:39 ian 27 Niels Baggesen, Gerben Wierda: minor patches 28 29 Revision 1.10 1992/03/16 22:22:35 ian 30 Adjusted external declarations 31 32 Revision 1.9 1992/03/15 01:54:46 ian 33 All execs are now done in isspawn, all waits are done in iswait 34 35 Revision 1.8 1992/03/12 19:54:43 ian 36 Debugging based on types rather than number 37 38 Revision 1.7 1992/03/11 22:21:19 ian 39 Permit uucp user to delete jobs 40 41 Revision 1.6 1992/02/27 19:53:26 ian 42 Added some extern definitions 43 44 Revision 1.5 1992/02/24 20:07:43 ian 45 John Theus: some systems don't have <fcntl.h> 46 47 Revision 1.4 1992/02/23 16:21:26 ian 48 Handle systems on which NULL second argument to utime fails 49 50 Revision 1.3 1992/02/23 03:26:51 ian 51 Overhaul to use automatic configure shell script 52 53 Revision 1.2 1992/02/20 04:40:07 ian 54 Make sure only the submitter or the superuser can cancel a request 55 56 Revision 1.1 1992/02/20 04:18:59 ian 57 Initial revision 58 59 */ 60 61 #include "uucp.h" 62 63 #if USE_RCS_ID 64 char sys7_unx_rcsid[] = "$Id: sys7.unx,v 1.11 1992/03/28 04:19:39 ian Rel $"; 65 #endif 66 67 #include <errno.h> 68 69 #if USE_STDIO && HAVE_UNISTD_H 70 #include <unistd.h> 71 #endif 72 73 #include "system.h" 74 #include "sysdep.h" 75 76 #if HAVE_FCNTL_H 77 #include <fcntl.h> 78 #else 79 #if HAVE_SYS_FILE_H 80 #include <sys/file.h> 81 #endif 82 #endif 83 84 #ifndef O_RDONLY 85 #define O_RDONLY 0 86 #define O_WRONLY 1 87 #define O_RDWR 2 88 #endif 89 90 #if HAVE_OPENDIR 91 #if HAVE_DIRENT_H 92 #include <dirent.h> 93 #else /* ! HAVE_DIRENT_H */ 94 #include <sys/dir.h> 95 #define dirent direct 96 #endif /* ! HAVE_DIRENT_H */ 97 #endif /* HAVE_OPENDIR */ 98 99 #ifdef UTIME_NULL_MISSING 100 #if HAVE_TIME_H 101 #include <time.h> 102 #endif 103 #endif 104 105 #if HAVE_UTIME_H 106 #include <utime.h> 107 #endif 108 109 /* External functions. */ 110 extern int fclose (), fflush (); 111 extern int read (), close (), utime (), stat (); 112 extern uid_t getuid (), geteuid (); 113 114 /* Local functions. */ 115 116 static boolean fskill_or_rejuv P((const char *zid, boolean fkill)); 117 118 /* Set file access time to the present. On most systems this can be a 119 macro, but some apparently do not support utime correctly. */ 120 121 #ifndef UTIME_NULL_MISSING 122 123 #define ussettime(z) utime((z), (struct utimbuf *) NULL) 124 125 #else /* defined (UTIME_NULL_MISSING) */ 126 127 static int 128 ussettime(z) 129 const char *z; 130 { 131 time_t inow; 132 133 inow = time ((time_t *) NULL); 134 135 { 136 #if HAVE_UTIME_H 137 struct utimbuf s; 138 139 s.actime = inow; 140 s.modtime = inow; 141 return utime (z, &s); 142 #else 143 time_t ai[2]; 144 145 ai[0] = inow; 146 ai[1] = inow; 147 return utime (z, ai); 148 #endif 149 } 150 } 151 152 #endif /* defined (UTIME_NULL_MISSING) */ 153 154 /* Kill a job, given the jobid. */ 155 156 boolean 157 fsysdep_kill_job (zid) 158 const char *zid; 159 { 160 return fskill_or_rejuv (zid, TRUE); 161 } 162 163 /* Rejuvenate a job, given the jobid. */ 164 165 boolean 166 fsysdep_rejuvenate_job (zid) 167 const char *zid; 168 { 169 return fskill_or_rejuv (zid, FALSE); 170 } 171 172 /* Kill or rejuvenate a job, given the jobid. */ 173 174 static boolean 175 fskill_or_rejuv (zid, fkill) 176 const char *zid; 177 boolean fkill; 178 { 179 const char *zfile; 180 const char *zsys; 181 char *zcopy; 182 struct ssysteminfo ssys; 183 const struct ssysteminfo *qsys; 184 FILE *e; 185 boolean fret; 186 char *zline; 187 int isys; 188 189 zfile = zsjobid_to_file (zid, &zsys); 190 zcopy = (char *) alloca (strlen (zfile) + 1); 191 strcpy (zcopy, zfile); 192 zfile = zcopy; 193 zcopy = (char *) alloca (strlen (zsys) + 1); 194 strcpy (zcopy, zsys); 195 zsys = zcopy; 196 197 if (fread_system_info (zsys, &ssys)) 198 qsys = &ssys; 199 else 200 { 201 if (! fUnknown_ok) 202 { 203 ulog (LOG_ERROR, "%s: Bad job id", zid); 204 return FALSE; 205 } 206 sUnknown.zname = zsys; 207 qsys = &sUnknown; 208 } 209 210 e = fopen (zfile, "r"); 211 if (e == NULL) 212 { 213 if (errno == ENOENT) 214 ulog (LOG_ERROR, "%s: Job not found", zid); 215 else 216 ulog (LOG_ERROR, "fopen (%s): %s", zfile, strerror (errno)); 217 return FALSE; 218 } 219 220 /* Now we have to read through the file to identify any temporary 221 files. */ 222 223 fret = TRUE; 224 while ((zline = zfgets (e, FALSE)) != NULL) 225 { 226 struct scmd s; 227 228 if (! fparse_cmd (zline, &s)) 229 { 230 ulog (LOG_ERROR, "Bad line in command file %s", zfile); 231 fret = FALSE; 232 xfree ((pointer) zline); 233 continue; 234 } 235 236 /* You are only permitted to delete a job if you submitted it or 237 if you are root or uucp. We check for uucp by seeing if the 238 real user ID and the effective user ID are the same; this 239 works because we should be suid to uucp, so our effective 240 user ID will always be uucp while our real user ID will be 241 whoever ran the program. */ 242 if (strcmp (s.zuser, zsysdep_login_name ()) != 0 243 && getuid () != 0 244 && getuid () != geteuid ()) 245 { 246 ulog (LOG_ERROR, "%s: Not submitted by you", zid); 247 xfree ((pointer) zline); 248 return FALSE; 249 } 250 251 if (s.bcmd == 'S') 252 { 253 const char *ztemp; 254 255 ztemp = zsysdep_spool_file_name (qsys, s.ztemp); 256 if (ztemp == NULL) 257 fret = FALSE; 258 else 259 { 260 if (fkill) 261 isys = remove (ztemp); 262 else 263 isys = ussettime (ztemp); 264 265 if (isys != 0 && errno != ENOENT) 266 { 267 ulog (LOG_ERROR, "%s (%s): %s", 268 fkill ? "remove" : "utime", ztemp, 269 strerror (errno)); 270 fret = FALSE; 271 } 272 } 273 } 274 275 xfree ((pointer) zline); 276 } 277 278 (void) fclose (e); 279 280 if (fkill) 281 isys = remove (zfile); 282 else 283 isys = ussettime (zfile); 284 285 if (isys != 0 && errno != ENOENT) 286 { 287 ulog (LOG_ERROR, "%s (%s): %s", fkill ? "remove" : "utime", 288 zfile, strerror (errno)); 289 fret = FALSE; 290 } 291 292 return fret; 293 } 294 295 /* Get the time a work job was queued. */ 296 297 long 298 isysdep_work_time (qsys, pseq) 299 const struct ssysteminfo *qsys; 300 pointer pseq; 301 { 302 return isysdep_file_time (zsjobid_to_file (zsysdep_jobid (qsys, pseq), 303 (const char **) NULL)); 304 } 305 306 /* Get the time a file was created (actually, the time it was last 307 modified). */ 308 309 long 310 isysdep_file_time (zfile) 311 const char *zfile; 312 { 313 struct stat s; 314 315 if (stat (zfile, &s) < 0) 316 { 317 if (errno != ENOENT) 318 ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno)); 319 return isysdep_time ((long *) NULL); 320 } 321 322 return (long) s.st_mtime; 323 } 324 325 /* Get the size in bytes of a file. */ 326 327 long 328 csysdep_size (zfile) 329 const char *zfile; 330 { 331 struct stat s; 332 333 if (stat (zfile, &s) < 0) 334 { 335 if (errno != ENOENT) 336 ulog (LOG_ERROR, "stat (%s): %s", zfile, strerror (errno)); 337 return 0; 338 } 339 340 return s.st_size; 341 } 342 343 /* Start getting the status files. */ 344 345 boolean 346 fsysdep_all_status_init (phold) 347 pointer *phold; 348 { 349 DIR *qdir; 350 351 qdir = opendir ((char *) ".Status"); 352 if (qdir == NULL) 353 { 354 ulog (LOG_ERROR, "opendir (.Status): %s", strerror (errno)); 355 return FALSE; 356 } 357 358 *phold = (pointer) qdir; 359 return TRUE; 360 } 361 362 /* Get the next status file. */ 363 364 const char * 365 zsysdep_all_status (phold, pferr, qstat) 366 pointer phold; 367 boolean *pferr; 368 struct sstatus *qstat; 369 { 370 DIR *qdir = (DIR *) phold; 371 struct dirent *qentry; 372 373 while (TRUE) 374 { 375 errno = 0; 376 qentry = readdir (qdir); 377 if (qentry == NULL) 378 { 379 if (errno == 0) 380 *pferr = FALSE; 381 else 382 { 383 ulog (LOG_ERROR, "readdir: %s", strerror (errno)); 384 *pferr = TRUE; 385 } 386 return NULL; 387 } 388 389 if (qentry->d_name[0] != '.') 390 { 391 struct ssysteminfo ssys; 392 393 /* Hack seriously; fsysdep_get_status only looks at the 394 zname element of the qsys argument, so if we fake that we 395 can read the status file. This should really be done 396 differently. */ 397 ssys.zname = qentry->d_name; 398 if (fsysdep_get_status (&ssys, qstat)) 399 return zscopy (qentry->d_name); 400 401 /* If fsysdep_get_status fails, it will output an error 402 message. We just continue with the next entry, so that 403 most of the status files will be displayed. */ 404 } 405 } 406 } 407 408 /* Finish getting the status file. */ 409 410 void 411 usysdep_all_status_free (phold) 412 pointer phold; 413 { 414 DIR *qdir = (DIR *) phold; 415 416 (void) closedir (qdir); 417 } 418 419 /* Get the status of all processes holding lock files. We do this by 420 invoking ps after we've figured out the process entries to use. */ 421 422 boolean 423 fsysdep_lock_status () 424 { 425 const char *zdir; 426 DIR *qdir; 427 struct dirent *qentry; 428 int calc; 429 int *pai; 430 int cgot; 431 int aidescs[3]; 432 char *zcopy, *ztok; 433 int cargs, iarg; 434 char **pazargs; 435 436 #ifdef LOCKDIR 437 zdir = LOCKDIR; 438 #else 439 zdir = "."; 440 #endif 441 442 qdir = opendir ((char *) zdir); 443 if (qdir == NULL) 444 { 445 ulog (LOG_ERROR, "opendir (%s): %s", zdir, strerror (errno)); 446 return FALSE; 447 } 448 449 /* We look for entries that start with "LCK.." and ignore everything 450 else. This won't find all possible lock files, but it should 451 find all the locks on terminals and systems. */ 452 453 calc = 0; 454 pai = NULL; 455 cgot = 0; 456 while ((qentry = readdir (qdir)) != NULL) 457 { 458 const char *zname; 459 int o; 460 #if HAVE_V2_LOCKFILES 461 int i; 462 #else 463 char ab[12]; 464 #endif 465 int cread; 466 int ierr; 467 int ipid; 468 469 if (strncmp (qentry->d_name, "LCK..", sizeof "LCK.." - 1) != 0) 470 continue; 471 472 zname = zsappend (zdir, qentry->d_name); 473 o = open (zname, O_RDONLY, 0); 474 if (o < 0) 475 { 476 if (errno != ENOENT) 477 ulog (LOG_ERROR, "open (%s): %s", zname, strerror (errno)); 478 continue; 479 } 480 481 #if HAVE_V2_LOCKFILES 482 cread = read (o, &i, sizeof i); 483 #else 484 cread = read (o, ab, sizeof ab - 1); 485 #endif 486 487 ierr = errno; 488 (void) close (o); 489 490 if (cread < 0) 491 { 492 ulog (LOG_ERROR, "read %s: %s", zname, strerror (ierr)); 493 continue; 494 } 495 496 #if HAVE_V2_LOCKFILES 497 ipid = i; 498 #else 499 ab[cread] = '\0'; 500 ipid = atoi (ab); 501 #endif 502 503 printf ("%s: %d\n", qentry->d_name, ipid); 504 505 if (cgot >= calc) 506 { 507 calc += 10; 508 pai = (int *) xrealloc ((pointer) pai, calc * sizeof (int)); 509 } 510 511 pai[cgot] = ipid; 512 ++cgot; 513 } 514 515 if (cgot == 0) 516 return TRUE; 517 518 aidescs[0] = SPAWN_NULL; 519 aidescs[1] = 1; 520 aidescs[2] = 2; 521 522 /* Parse PS_PROGRAM into an array of arguments. */ 523 zcopy = (char *) alloca (sizeof PS_PROGRAM); 524 strcpy (zcopy, PS_PROGRAM); 525 526 cargs = 0; 527 for (ztok = strtok (zcopy, " \t"); 528 ztok != NULL; 529 ztok = strtok ((char *) NULL, " \t")) 530 ++cargs; 531 532 pazargs = (char **) alloca ((cargs + 1) * sizeof (char *)); 533 534 strcpy (zcopy, PS_PROGRAM); 535 for (ztok = strtok (zcopy, " \t"), iarg = 0; 536 ztok != NULL; 537 ztok = strtok ((char *) NULL, " \t"), ++iarg) 538 pazargs[iarg] = ztok; 539 pazargs[iarg] = NULL; 540 541 #if ! HAVE_PS_MULTIPLE 542 /* We have to invoke ps multiple times. */ 543 { 544 int i; 545 char *zlast, *zset; 546 547 zlast = pazargs[cargs - 1]; 548 zset = (char *) alloca (strlen (zlast) + 20); 549 for (i = 0; i < cgot; i++) 550 { 551 pid_t ipid; 552 553 sprintf (zset, "%s%d", zlast, pai[i]); 554 pazargs[cargs - 1] = zset; 555 556 ipid = isspawn ((const char **) pazargs, aidescs, FALSE, FALSE, 557 (const char *) NULL, FALSE, TRUE, 558 (const char *) NULL, (const char *) NULL, 559 (const char *) NULL); 560 if (ipid < 0) 561 ulog (LOG_ERROR, "isspawn: %s", strerror (errno)); 562 else 563 (void) iswait ((unsigned long) ipid, PS_PROGRAM); 564 } 565 } 566 #else 567 { 568 char *zlast; 569 int i; 570 pid_t ipid; 571 572 zlast = (char *) alloca (strlen (pazargs[cargs - 1]) + cgot * 20 + 1); 573 strcpy (zlast, pazargs[cargs - 1]); 574 for (i = 0; i < cgot; i++) 575 { 576 char ab[20]; 577 578 sprintf (ab, "%d", pai[i]); 579 strcat (zlast, ab); 580 if (i + 1 < cgot) 581 strcat (zlast, ","); 582 } 583 pazargs[cargs - 1] = zlast; 584 585 ipid = isspawn ((const char **) pazargs, aidescs, FALSE, FALSE, 586 (const char *) NULL, FALSE, TRUE, 587 (const char *) NULL, (const char *) NULL, 588 (const char *) NULL); 589 if (ipid < 0) 590 ulog (LOG_ERROR, "isspawn: %s", strerror (errno)); 591 else 592 (void) iswait ((unsigned long) ipid, PS_PROGRAM); 593 } 594 #endif 595 596 return TRUE; 597 } 598 599 /* 600 Local variables: 601 mode:c 602 End: 603 */ 604