xref: /386bsd/usr/src/libexec/uucp/sys7.c (revision a2142627)
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