/* uustat.c UUCP status program Copyright (C) 1991, 1992, 1993, 1994, 1995 Ian Lance Taylor This file is part of the Taylor UUCP package. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. The author of the program may be contacted at ian@airs.com or c/o Cygnus Support, 48 Grove Street, Somerville, MA 02144. */ #include "uucp.h" #if USE_RCS_ID const char uustat_rcsid[] = "$Id: uustat.c,v 1.3 1995/08/24 05:23:33 jtc Exp $"; #endif #include #include #if TM_IN_SYS_TIME #include #else #include #endif #include "getopt.h" #include "uudefs.h" #include "uuconf.h" #include "system.h" /* The uustat program permits various listings and manipulations of files in the spool directory. This implementation supports the following switches: -a list all jobs -Blines number of lines of standard input to mail -ccommand list only executions of specified command -Ccommand list only jobs other than executions of specified command -e list execute jobs rather than command requests -i ask user whether to kill each listed job -Ifile set configuration file name -kjobid kill job with specified ID -K kill each listed job -m report status for all remote machines -M mail uucp about each job killed with -K -N mail requestor about each job killed with -K -ohour report jobs older than specified number of hours -p do "ps -flp" on all processes holding lock files (Unix specific) -q list number of jobs for all systems -Q don't list jobs, just do -K processing -rjobid rejuvenate job with specified ID -ssystem report on all jobs for specified system -Ssystem report on all jobs other than for specified system -uuser report on all jobs for specified user -Uuser report on all jobs other than for specified user -Wcomment comment to include in mail messages -xdebug set debugging level -yhour report jobs younger than specified number of hours */ /* What to do with a job that matches the selection criteria; these values may be or'red together. */ #define JOB_SHOW (01) #define JOB_INQUIRE (02) #define JOB_KILL (04) #define JOB_REJUVENATE (010) #define JOB_MAIL (020) #define JOB_NOTIFY (040) /* This structure is used to accumulate all the lines in a single command file, so that they can all be displayed at once and so that executions can be displayed reasonably. */ struct scmdlist { struct scmdlist *qnext; struct scmd s; long itime; }; /* Local functions. */ static void ususage P((void)); static void ushelp P((void)); static boolean fsxqt_file_read P((pointer puuconf, FILE *)); static void usxqt_file_free P((void)); static int isxqt_cmd P((pointer puuconf, int argc, char **argv, pointer pvar, pointer pinfo)); static int isxqt_file P((pointer puuconf, int argc, char **argv, pointer pvar, pointer pinfo)); static int isxqt_user P((pointer puuconf, int argc, char **argv, pointer pvar, pointer pinfo)); static boolean fsworkfiles P((pointer puuconf, int icmd, int csystems, char **pazsystems, boolean fnotsystems, int cusers, char **pazusers, boolean fnotusers, long iold, long iyoung, int ccommands, char **pazcommands, boolean fnotcommands, const char *zcomment, int cstdin)); static boolean fsworkfiles_system P((pointer puuconf,int icmd, const struct uuconf_system *qsys, int cusers, char **pazusers, boolean fnotusers, long iold, long iyoung, int ccommands, char **pazcommands, boolean fnotcommands, const char *zcomment, int cstdin)); static boolean fsworkfile_show P((pointer puuconf, int icmd, const struct uuconf_system *qsys, const struct scmd *qcmd, long itime, int ccommands, char **pazcommands, boolean fnotcommands, const char *zcomment, int cstdin)); static void usworkfile_header P((const struct uuconf_system *qsys, const struct scmd *qcmd, const char *zjobid, long itime, boolean ffirst)); static boolean fsexecutions P((pointer puuconf, int icmd, int csystems, char **pazsystems, boolean fnotsystems, int cusers, char **pazusers, boolean fnotusers, long iold, long iyoung, int ccommands, char **pazcommands, boolean fnotcommands, const char *zcomment, int cstdin)); static boolean fsnotify P((pointer puuconf, int icmd, const char *zcomment, int cstdin, boolean fkilled, const char *zcmd, struct scmdlist *qcmd, const char *zid, long itime, const char *zuser, const struct uuconf_system *qsys, const char *zstdin, pointer pstdinseq, const char *zrequestor)); static boolean fsquery P((pointer puuconf, int csystems, char **pazsystems, boolean fnotsystems, long iold, long iyoung)); static int csunits_show P((long idiff)); static boolean fsmachines P((void)); /* Long getopt options. */ static const struct option asSlongopts[] = { { "all", no_argument, NULL, 'a' }, { "mail-lines", required_argument, NULL, 'B' }, { "command", required_argument, NULL, 'c' }, { "not-command", required_argument, NULL, 'C' }, { "executions", no_argument, NULL, 'e' }, { "prompt", no_argument, NULL, 'i' }, { "kill", required_argument, NULL, 'k' }, { "kill-all", no_argument, NULL, 'K' }, { "status", no_argument, NULL, 'm' }, { "mail", no_argument, NULL, 'M' }, { "notify", no_argument, NULL, 'N' }, { "older-than", required_argument, NULL, 'o' }, { "ps", no_argument, NULL, 'p' }, { "list", no_argument, NULL, 'q' }, { "no-list", no_argument, NULL, 'Q' }, { "rejuvenate", required_argument, NULL, 'r' }, { "rejuvenate-all", no_argument, NULL, 'R' }, { "system", required_argument, NULL, 's' }, { "not-system", required_argument, NULL, 'S' }, { "user", required_argument, NULL, 'u' }, { "not-user", required_argument, NULL, 'U' }, { "comment", required_argument, NULL, 'W' }, { "younger-than", required_argument, NULL, 'y' }, { "config", required_argument, NULL, 'I' }, { "debug", required_argument, NULL, 'x' }, { "version", no_argument, NULL, 'v' }, { "help", no_argument, NULL, 1 }, { NULL, 0, NULL, 0 } }; int main (argc, argv) int argc; char **argv; { /* -a: list all jobs. */ boolean fall = FALSE; /* -B lines: number of lines of standard input to mail. */ int cstdin = 100; /* -c,-C command: list only specified command. */ int ccommands = 0; char **pazcommands = NULL; boolean fnotcommands = FALSE; /* -e: list execute jobs. */ boolean fexecute = FALSE; /* -k jobid: kill specified job. */ int ckills = 0; char **pazkills = NULL; /* -m: report machine status. */ boolean fmachine = FALSE; /* -o hour: report jobs older than given number of hours. */ int ioldhours = -1; /* -p: report status of jobs holding lock files. */ boolean fps = FALSE; /* -q: list number of jobs for each system. */ boolean fquery = FALSE; /* -r jobid: rejuvenate specified job. */ int crejuvs = 0; char **pazrejuvs = NULL; /* -s,-S system: list all jobs for specified system. */ int csystems = 0; char **pazsystems = NULL; boolean fnotsystems = FALSE; /* -u,-U user: list all jobs for specified user. */ int cusers = 0; char **pazusers = NULL; boolean fnotusers = FALSE; /* -W comment: comment to include in mail messages. */ const char *zcomment = NULL; /* -y hour: report jobs younger than given number of hours. */ int iyounghours = -1; /* -I file: set configuration file. */ const char *zconfig = NULL; /* -Q, -i, -K, -M, -N: what to do with each job. */ int icmd = JOB_SHOW; int ccmds; int iopt; pointer puuconf; int iuuconf; long iold; long iyoung; const char *azoneuser[1]; boolean fret; zProgram = argv[0]; while ((iopt = getopt_long (argc, argv, "aB:c:C:eiI:k:KmMNo:pqQr:Rs:S:u:U:vW:x:y:", asSlongopts, (int *) NULL)) != EOF) { switch (iopt) { case 'a': /* List all jobs. */ fall = TRUE; break; case 'B': /* Number of lines of standard input to mail. */ cstdin = (int) strtol (optarg, (char **) NULL, 10); break; case 'C': /* List jobs for other than specified command. */ fnotcommands = TRUE; /* Fall through. */ case 'c': /* List specified command. */ ++ccommands; pazcommands = (char **) xrealloc ((pointer) pazcommands, ccommands * sizeof (char *)); pazcommands[ccommands - 1] = optarg; break; case 'e': /* List execute jobs. */ fexecute = TRUE; break; case 'i': /* Prompt the user whether to kill each job. */ icmd |= JOB_INQUIRE; break; case 'I': /* Set configuration file name. */ if (fsysdep_other_config (optarg)) zconfig = optarg; break; case 'k': /* Kill specified job. */ ++ckills; pazkills = (char **) xrealloc ((pointer) pazkills, ckills * sizeof (char *)); pazkills[ckills - 1] = optarg; break; case 'K': /* Kill each listed job. */ icmd |= JOB_KILL; break; case 'm': /* Report machine status. */ fmachine = TRUE; break; case 'M': /* Mail to uucp action taken on each job. */ icmd |= JOB_MAIL; break; case 'N': /* Mail to requestor action taken on each job. */ icmd |= JOB_NOTIFY; break; case 'o': /* Report old jobs. */ ioldhours = (int) strtol (optarg, (char **) NULL, 10); break; case 'p': /* Get status of processes holding locks. */ fps = TRUE; break; case 'q': /* List number of jobs for each system. */ fquery = TRUE; break; case 'Q': /* Don't list jobs, just do -K processing. */ icmd &=~ JOB_SHOW; break; case 'r': /* Rejuvenate specified job. */ ++crejuvs; pazrejuvs = (char **) xrealloc ((pointer) pazrejuvs, crejuvs * sizeof (char *)); pazrejuvs[crejuvs - 1] = optarg; break; case 'R': /* Rejuvenate each listed job. */ icmd |= JOB_REJUVENATE; break; case 'S': /* List jobs for other than specified system. */ fnotsystems = TRUE; /* Fall through. */ case 's': /* List jobs for specified system. */ ++csystems; pazsystems = (char **) xrealloc ((pointer) pazsystems, csystems * sizeof (char *)); pazsystems[csystems - 1] = optarg; break; case 'U': /* List jobs for other than specified user. */ fnotusers = TRUE; /* Fall through. */ case 'u': /* List jobs for specified user. */ ++cusers; pazusers = (char **) xrealloc ((pointer) pazusers, cusers * sizeof (char *)); pazusers[cusers - 1] = optarg; break; case 'W': /* Comment to include in mail messages. */ zcomment = optarg; break; case 'x': #if DEBUG > 1 /* Set debugging level. */ iDebug |= idebug_parse (optarg); #endif break; case 'y': /* List jobs younger than given number of hours. */ iyounghours = (int) strtol (optarg, (char **) NULL, 10); break; case 'v': /* Print version and exit. */ printf ("%s: Taylor UUCP %s, copyright (C) 1991, 92, 93, 94, 1995 Ian Lance Taylor\n", zProgram, VERSION); exit (EXIT_SUCCESS); /*NOTREACHED*/ case 1: /* --help. */ ushelp (); exit (EXIT_SUCCESS); /*NOTREACHED*/ case 0: /* Long option found and flag set. */ break; default: ususage (); /*NOTREACHED*/ } } if (optind != argc) ususage (); /* To avoid confusion, most options are only permitted by themselves. This restriction might be removed later, but it is imposed by most implementations. We do permit any combination of -c, -s, -u, -o and -y, and any combination of -k and -r. */ ccmds = 0; if (fall) ++ccmds; if (ckills > 0 || crejuvs > 0) ++ccmds; if (fmachine) ++ccmds; if (fps) ++ccmds; if (fexecute || fquery || csystems > 0 || cusers > 0 || ioldhours != -1 || iyounghours != -1 || ccommands > 0) ++ccmds; if (fexecute && fquery) ++ccmds; if (ccmds > 1) { fprintf (stderr, "%s: too many options\n", zProgram); ususage (); } if ((icmd & JOB_KILL) != 0 && (icmd & JOB_REJUVENATE) != 0) { fprintf (stderr, "%s: can not both rejuvenate and kill jobs\n", zProgram); ususage (); } iuuconf = uuconf_init (&puuconf, (const char *) NULL, zconfig); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); #if DEBUG > 1 { const char *zdebug; iuuconf = uuconf_debuglevel (puuconf, &zdebug); if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); if (zdebug != NULL) iDebug |= idebug_parse (zdebug); } #endif usysdep_initialize (puuconf, INIT_SUID); /* If no commands were specified, we list all commands for the given user. */ if (ccmds == 0) { cusers = 1; azoneuser[0] = zsysdep_login_name (); pazusers = (char **) azoneuser; } /* Canonicalize the system names. */ if (csystems > 0) { int i; for (i = 0; i < csystems; i++) { struct uuconf_system ssys; iuuconf = uuconf_system_info (puuconf, pazsystems[i], &ssys); if (iuuconf != UUCONF_SUCCESS) { if (iuuconf == UUCONF_NOT_FOUND) ulog (LOG_FATAL, "%s: System not found", pazsystems[i]); else ulog_uuconf (LOG_FATAL, puuconf, iuuconf); } if (strcmp (pazsystems[i], ssys.uuconf_zname) != 0) pazsystems[i] = zbufcpy (ssys.uuconf_zname); (void) uuconf_system_free (puuconf, &ssys); } } if (ioldhours == -1) iold = (long) -1; else { iold = (ixsysdep_time ((long *) NULL) - (long) ioldhours * (long) 60 * (long) 60); if (iold < 0L) iold = 0L; } if (iyounghours == -1) iyoung = (long) -1; else { iyoung = (ixsysdep_time ((long *) NULL) - (long) iyounghours * (long) 60 * (long) 60); if (iyoung < 0L) iyoung = 0L; } if (! fexecute && ! fquery && (fall || csystems > 0 || cusers > 0 || ioldhours != -1 || iyounghours != -1 || ccommands > 0)) fret = fsworkfiles (puuconf, icmd, csystems, pazsystems, fnotsystems, cusers, pazusers, fnotusers, iold, iyoung, ccommands, pazcommands, fnotcommands, zcomment, cstdin); else if (fexecute) fret = fsexecutions (puuconf, icmd, csystems, pazsystems, fnotsystems, cusers, pazusers, fnotusers, iold, iyoung, ccommands, pazcommands, fnotcommands, zcomment, cstdin); else if (icmd != JOB_SHOW) { ulog (LOG_ERROR, "-i, -K, -M, -N, -Q, -R not supported with -k, -m, -p, -q, -r"); ususage (); fret = FALSE; } else if (fquery) { if (cusers > 0 || ccommands > 0) { ulog (LOG_ERROR, "-u, -c not supported with -q"); ususage (); fret = FALSE; } else fret = fsquery (puuconf, csystems, pazsystems, fnotsystems, iold, iyoung); } else if (fmachine) fret = fsmachines (); else if (ckills > 0 || crejuvs > 0) { int i; fret = TRUE; for (i = 0; i < ckills; i++) if (! fsysdep_kill_job (puuconf, pazkills[i])) fret = FALSE; for (i = 0; i < crejuvs; i++) if (! fsysdep_rejuvenate_job (puuconf, pazrejuvs[i])) fret = FALSE; } else if (fps) fret = fsysdep_lock_status (); else { #if DEBUG > 0 ulog (LOG_FATAL, "Can't happen"); #endif fret = FALSE; } ulog_close (); usysdep_exit (fret); /* Avoid errors about not returning a value. */ return 0; } /* Print a usage message and die. */ static void ususage () { fprintf (stderr, "Usage: %s [options]\n", zProgram); fprintf (stderr, "Use %s --help for help\n", zProgram); exit (EXIT_FAILURE); } /* Print a help message. */ static void ushelp () { printf ("Taylor UUCP %s, copyright (C) 1991, 92, 93, 94, 1995 Ian Lance Taylor\n", VERSION); printf ("Usage: %s [options]\n", zProgram); printf (" -a,--all: list all UUCP jobs\n"); printf (" -B,--mail-lines num: number of lines to return in -M or -N mail message\n"); printf (" -c,--command command: list requests for named command\n"); printf (" -C,--not-command command: list requests for other than named command\n"); printf (" -e,--executions: list queued executions rather than job requests\n"); printf (" -i,--prompt: prompt for whether to kill each listed job\n"); printf (" -k,--kill job: kill specified UUCP job\n"); printf (" -K,--kill-all: kill each listed job\n"); printf (" -m,--status: report status for all remote machines\n"); printf (" -M,--mail: mail report on each listed job to UUCP administrator\n"); printf (" -N,--notify: mail report on each listed job to requestor\n"); printf (" -o,--older-than hours: list all jobs older than given number of hours\n"); printf (" -p,--ps: show status of all processes holding UUCP locks\n"); printf (" -q,--list: list number of jobs for each system\n"); printf (" -Q,--no-list: don't list jobs, just take actions (-i, -K, -M, -N)\n"); printf (" -r,--rejuvenate job: rejuvenate specified UUCP job\n"); printf (" -R,--rejuvenate-all: rejuvenate each listed job\n"); printf (" -s,--system system: list all jobs for specified system\n"); printf (" -S,--not-system system: list all jobs for other than specified system\n"); printf (" -u,--user user: list all jobs for specified user\n"); printf (" -U,--not-user user: list all jobs for other than specified user\n"); printf (" -W,--comment comment: comment to include in mail messages\n"); printf (" -y,--younger-than hours: list all jobs younger than given number of hours\n"); printf (" -x,--debug debug: Set debugging level\n"); #if HAVE_TAYLOR_CONFIG printf (" -I,--config file: Set configuration file to use\n"); #endif /* HAVE_TAYLOR_CONFIG */ printf (" -v,--version: Print version and exit\n"); printf (" --help: Print help and exit\n"); } /* We need to be able to read information from an execution file. */ /* The user name extracted from an execution file. */ static char *zSxqt_user; /* The system name from an execution file. */ static char *zSxqt_system; /* Address of requesting user (who to send mail to). */ static const char *zSxqt_requestor; /* The command (no arguments) from an execution file. */ static char *zSxqt_prog; /* The full command line from an execution file. */ static char *zSxqt_cmd; /* Number of files associated with an execution file. */ static int cSxqt_files; /* Names of files associated with execution file. */ static char **pazSxqt_files; /* Standard input file name. */ static const char *zSxqt_stdin; /* A command table used to dispatch an execution file. */ static const struct uuconf_cmdtab asSxqt_cmds[] = { { "C", UUCONF_CMDTABTYPE_FN | 0, NULL, isxqt_cmd }, { "I", UUCONF_CMDTABTYPE_STRING, (pointer) &zSxqt_stdin, NULL }, { "F", UUCONF_CMDTABTYPE_FN | 0, NULL, isxqt_file }, { "R", UUCONF_CMDTABTYPE_STRING, (pointer) &zSxqt_requestor, NULL }, { "U", UUCONF_CMDTABTYPE_FN | 3, NULL, isxqt_user }, { NULL, 0, NULL, NULL } }; /* Read an execution file, setting the above variables. */ static boolean fsxqt_file_read (puuconf, e) pointer puuconf; FILE *e; { int iuuconf; boolean fret; zSxqt_user = NULL; zSxqt_system = NULL; zSxqt_stdin = NULL; zSxqt_requestor = NULL; zSxqt_prog = NULL; zSxqt_cmd = NULL; cSxqt_files = 0; pazSxqt_files = NULL; iuuconf = uuconf_cmd_file (puuconf, e, asSxqt_cmds, (pointer) NULL, (uuconf_cmdtabfn) NULL, UUCONF_CMDTABFLAG_CASE, (pointer) NULL); if (iuuconf == UUCONF_SUCCESS) fret = TRUE; else { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); fret = FALSE; } if (zSxqt_user == NULL) zSxqt_user = zbufcpy ("*unknown*"); if (zSxqt_system == NULL) zSxqt_system = zbufcpy ("*unknown*"); if (zSxqt_prog == NULL) { zSxqt_prog = zbufcpy ("*none*"); zSxqt_cmd = zbufcpy ("*none*"); } return fret; } /* Free up the information read from an execution file. */ static void usxqt_file_free () { int i; ubuffree (zSxqt_user); zSxqt_user = NULL; ubuffree (zSxqt_system); zSxqt_system = NULL; ubuffree (zSxqt_prog); zSxqt_prog = NULL; ubuffree (zSxqt_cmd); zSxqt_cmd = NULL; for (i = 0; i < cSxqt_files; i++) ubuffree (pazSxqt_files[i]); cSxqt_files = 0; xfree ((pointer) pazSxqt_files); pazSxqt_files = NULL; zSxqt_stdin = NULL; zSxqt_requestor = NULL; } /* Get the command from an execution file. */ /*ARGSUSED*/ static int isxqt_cmd (puuconf, argc, argv, pvar, pinfo) pointer puuconf; int argc; char **argv; pointer pvar; pointer pinfo; { size_t clen; int i; if (argc <= 1) return UUCONF_CMDTABRET_CONTINUE; zSxqt_prog = zbufcpy (argv[1]); clen = 0; for (i = 1; i < argc; i++) clen += strlen (argv[i]) + 1; zSxqt_cmd = zbufalc (clen); zSxqt_cmd[0] = '\0'; for (i = 1; i < argc - 1; i++) { strcat (zSxqt_cmd, argv[i]); strcat (zSxqt_cmd, " "); } strcat (zSxqt_cmd, argv[i]); return UUCONF_CMDTABRET_CONTINUE; } /* Get the associated files from an execution file. */ /*ARGSUSED*/ static int isxqt_file (puuconf, argc, argv, pvar, pinfo) pointer puuconf; int argc; char **argv; pointer pvar; pointer pinfo; { if (argc != 2 && argc != 3) return UUCONF_CMDTABRET_CONTINUE; /* If this file is not in the spool directory, just ignore it. */ if (! fspool_file (argv[1])) return UUCONF_CMDTABRET_CONTINUE; ++cSxqt_files; pazSxqt_files = (char **) xrealloc ((pointer) pazSxqt_files, cSxqt_files * sizeof (char *)); pazSxqt_files[cSxqt_files - 1] = zbufcpy (argv[1]); return UUCONF_CMDTABRET_CONTINUE; } /* Get the requesting user and system from an execution file. */ /*ARGSUSED*/ static int isxqt_user (puuconf, argc, argv, pvar, pinfo) pointer puuconf; int argc; char **argv; pointer pvar; pointer pinfo; { zSxqt_user = zbufcpy (argv[1]); zSxqt_system = zbufcpy (argv[2]); return UUCONF_CMDTABRET_CONTINUE; } /* Handle various possible requests to look at work files. */ static boolean fsworkfiles (puuconf, icmd, csystems, pazsystems, fnotsystems, cusers, pazusers, fnotusers, iold, iyoung, ccommands, pazcommands, fnotcommands, zcomment, cstdin) pointer puuconf; int icmd; int csystems; char **pazsystems; boolean fnotsystems; int cusers; char **pazusers; boolean fnotusers; long iold; long iyoung; int ccommands; char **pazcommands; boolean fnotcommands; const char *zcomment; int cstdin; { boolean fret; int i; int iuuconf; struct uuconf_system ssys; fret = TRUE; if (csystems > 0 && ! fnotsystems) { for (i = 0; i < csystems; i++) { iuuconf = uuconf_system_info (puuconf, pazsystems[i], &ssys); if (iuuconf != UUCONF_SUCCESS) { if (iuuconf == UUCONF_NOT_FOUND) ulog (LOG_ERROR, "%s: System not found", pazsystems[i]); else ulog_uuconf (LOG_ERROR, puuconf, iuuconf); fret = FALSE; continue; } if (! fsworkfiles_system (puuconf, icmd, &ssys, cusers, pazusers, fnotusers, iold, iyoung, ccommands, pazcommands, fnotcommands, zcomment, cstdin)) fret = FALSE; (void) uuconf_system_free (puuconf, &ssys); } } else { char **pznames, **pz; iuuconf = uuconf_system_names (puuconf, &pznames, 0); if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); return FALSE; } for (pz = pznames; *pz != NULL; pz++) { if (csystems > 0) { for (i = 0; i < csystems; i++) if (strcmp (*pz, pazsystems[i]) == 0) break; if (i < csystems) continue; } iuuconf = uuconf_system_info (puuconf, *pz, &ssys); if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); fret = FALSE; continue; } if (! fsworkfiles_system (puuconf, icmd, &ssys, cusers, pazusers, fnotusers, iold, iyoung, ccommands, pazcommands, fnotcommands, zcomment, cstdin)) fret = FALSE; (void) uuconf_system_free (puuconf, &ssys); xfree ((pointer) *pz); } xfree ((pointer) pznames); } return fret; } /* Look at the work files for a particular system. */ static boolean fsworkfiles_system (puuconf, icmd, qsys, cusers, pazusers, fnotusers, iold, iyoung, ccommands, pazcommands, fnotcommands, zcomment, cstdin) pointer puuconf; int icmd; const struct uuconf_system *qsys; int cusers; char **pazusers; boolean fnotusers; long iold; long iyoung; int ccommands; char **pazcommands; boolean fnotcommands; const char *zcomment; int cstdin; { boolean fret; if (! fsysdep_get_work_init (qsys, UUCONF_GRADE_LOW)) return FALSE; while (TRUE) { struct scmd s; long itime; if (! fsysdep_get_work (qsys, UUCONF_GRADE_LOW, &s)) { usysdep_get_work_free (qsys); return FALSE; } if (s.bcmd == 'H') break; if (cusers > 0) { boolean fmatch; int i; fmatch = fnotusers; for (i = 0; i < cusers; i++) { if (s.zuser != NULL && strcmp (pazusers[i], s.zuser) == 0) { fmatch = ! fmatch; break; } } if (! fmatch) continue; } itime = ixsysdep_work_time (qsys, s.pseq); if (iold != (long) -1 && itime > iold) continue; if (iyoung != (long) -1 && itime < iyoung) continue; if (! fsworkfile_show (puuconf, icmd, qsys, &s, itime, ccommands, pazcommands, fnotcommands, zcomment, cstdin)) { usysdep_get_work_free (qsys); return FALSE; } } fret = fsworkfile_show (puuconf, icmd, qsys, (const struct scmd *) NULL, 0L, ccommands, pazcommands, fnotcommands, zcomment, cstdin); usysdep_get_work_free (qsys); return fret; } /* Show a single workfile. This is actually called once for each line in the workfile, so we accumulate the lines and show them all at once. This lets us show an execution in a useful fashion. */ static boolean fsworkfile_show (puuconf, icmd, qsys, qcmd, itime, ccommands, pazcommands, fnotcommands, zcomment, cstdin) pointer puuconf; int icmd; const struct uuconf_system *qsys; const struct scmd *qcmd; long itime; int ccommands; char **pazcommands; boolean fnotcommands; const char *zcomment; int cstdin; { static struct scmdlist *qlist; static char *zlistid; char *zid; if (qcmd == NULL) zid = NULL; else { zid = zsysdep_jobid (qsys, qcmd->pseq); if (zid == NULL) return FALSE; } /* If this is the same jobid as the list, put it on the end. */ if (qcmd != NULL && qlist != NULL && strcmp (zlistid, zid) == 0) { struct scmdlist *qnew, **pq; ubuffree (zid); qnew = (struct scmdlist *) xmalloc (sizeof (struct scmdlist)); qnew->qnext = NULL; qnew->s = *qcmd; qnew->itime = itime; for (pq = &qlist; *pq != NULL; pq = &(*pq)->qnext) ; *pq = qnew; return TRUE; } /* Here we have found a different job ID, so we print the scmd structures that we have accumulated. We look for the special case of an execution (an E command, or one of the destination files begins with X.). We could be more clever about other situations as well. */ if (qlist != NULL) { boolean fmatch; const char *zprog, *zcmd, *zrequestor, *zstdin; char *zfree; struct scmdlist *qxqt; FILE *exqt = NULL; struct scmdlist *qfree; fmatch = FALSE; zprog = zcmd = zrequestor = zstdin = NULL; zfree = NULL; for (qxqt = qlist; qxqt != NULL; qxqt = qxqt->qnext) { if (qxqt->s.bcmd == 'E') break; if (qxqt->s.bcmd == 'S' && qxqt->s.zto[0] == 'X' && qxqt->s.zto[1] == '.' && fspool_file (qxqt->s.zfrom)) { char *zxqt; /* Open the file now, so that, if it does not exist, we can still report sensibly (the qxqt == NULL case) on any other files that may exist. */ zxqt = zsysdep_spool_file_name (qsys, qxqt->s.zfrom, qxqt->s.pseq); if (zxqt == NULL) return FALSE; exqt = fopen (zxqt, "r"); ubuffree (zxqt); if (exqt != NULL) break; } } if (qxqt == NULL) { if (ccommands == 0 || (fnotcommands && strcmp (pazcommands[0], "ALL") == 0)) { /* Show all the lines in a regular work file. */ fmatch = TRUE; if ((icmd & JOB_SHOW) != 0) { struct scmdlist *qshow; for (qshow = qlist; qshow != NULL; qshow = qshow->qnext) { char *zfile; long cbytes; usworkfile_header (qsys, &qshow->s, zlistid, qshow->itime, qshow == qlist); switch (qshow->s.bcmd) { case 'S': if (strchr (qshow->s.zoptions, 'C') != NULL || fspool_file (qshow->s.zfrom)) zfile = zsysdep_spool_file_name (qsys, qshow->s.ztemp, qshow->s.pseq); else zfile = zbufcpy (qshow->s.zfrom); if (zfile == NULL) cbytes = -1; else cbytes = csysdep_size (zfile); if (cbytes >= 0) printf ("Sending %s (%ld bytes) to %s", qshow->s.zfrom, cbytes, qshow->s.zto); ubuffree (zfile); break; case 'R': printf ("Requesting %s to %s", qshow->s.zfrom, qshow->s.zto); break; case 'X': printf ("Requesting %s to %s", qshow->s.zfrom, qshow->s.zto); break; case 'P': printf ("(poll file)"); break; #if DEBUG > 0 default: printf ("Bad line %d", qshow->s.bcmd); break; #endif } printf ("\n"); } } } } else { long csize; struct scmdlist *qsize; /* Show the command for an execution file. */ if (qxqt->s.bcmd == 'E') { zfree = zbufcpy (qxqt->s.zcmd); zfree[strcspn (zfree, " \t")] = '\0'; zprog = zfree; zcmd = qxqt->s.zcmd; if (strchr (qxqt->s.zoptions, 'R') != NULL) zrequestor = qxqt->s.znotify; } else { if (! fsxqt_file_read (puuconf, exqt)) { (void) fclose (exqt); return FALSE; } (void) fclose (exqt); zprog = zSxqt_prog; zcmd = zSxqt_cmd; zrequestor = zSxqt_requestor; } csize = 0L; for (qsize = qlist; qsize != NULL; qsize = qsize->qnext) { if (qsize->s.bcmd == 'S' || qsize->s.bcmd == 'E') { char *zfile; if (strchr (qsize->s.zoptions, 'C') != NULL || fspool_file (qsize->s.zfrom)) zfile = zsysdep_spool_file_name (qsys, qsize->s.ztemp, qsize->s.pseq); else zfile = zbufcpy (qsize->s.zfrom); if (zfile != NULL) { long cbytes; cbytes = csysdep_size (zfile); if (cbytes > 0) csize += cbytes; ubuffree (zfile); } } } if (ccommands == 0) fmatch = TRUE; else { int i; fmatch = fnotcommands; for (i = 0; i < ccommands; i++) { if (strcmp (pazcommands[i], "ALL") == 0 || strcmp (pazcommands[i], zprog) == 0) { fmatch = ! fmatch; break; } } } /* To get the name of the standard input file on this system we have to look through the list of file transfers to find the right one on the remote system. */ if (fmatch) { struct scmdlist *qstdin; if (qxqt->s.bcmd == 'E') qstdin = qxqt; else if (zSxqt_stdin != NULL) { for (qstdin = qlist; qstdin != NULL; qstdin = qstdin->qnext) if (qstdin->s.bcmd == 'S' && strcmp (qstdin->s.zto, zSxqt_stdin) == 0) break; } else qstdin = NULL; if (qstdin != NULL) { if (strchr (qstdin->s.zoptions, 'C') != NULL || fspool_file (qstdin->s.zfrom)) zstdin = qstdin->s.ztemp; else zstdin = qstdin->s.zfrom; } } if (fmatch && (icmd & JOB_SHOW) != 0) { usworkfile_header (qsys, &qxqt->s, zlistid, qxqt->itime, TRUE); printf ("Executing %s (sending %ld bytes)\n", zcmd, csize); } } if (fmatch) { boolean fkill_or_rejuv; fkill_or_rejuv = FALSE; if ((icmd & JOB_INQUIRE) != 0) { int b; /* Ask stdin whether this job should be killed. */ fprintf (stderr, "%s: %s %s? ", zProgram, (icmd & JOB_REJUVENATE) != 0 ? "Rejuvenate" : "Kill", zlistid); (void) fflush (stderr); b = getchar (); fkill_or_rejuv = b == 'y' || b == 'Y'; while (b != EOF && b != '\n') b = getchar (); } else if ((icmd & JOB_KILL) != 0 || (icmd & JOB_REJUVENATE) != 0) fkill_or_rejuv = TRUE; if (fkill_or_rejuv && (qlist->s.zuser == NULL || strcmp (zsysdep_login_name (), qlist->s.zuser) != 0) && ! fsysdep_privileged ()) ulog (LOG_ERROR, "%s: Not submitted by you", zlistid); else { if ((icmd & (JOB_MAIL | JOB_NOTIFY)) != 0) { if (! fsnotify (puuconf, icmd, zcomment, cstdin, (fkill_or_rejuv && (icmd & JOB_REJUVENATE) == 0), zcmd, qlist, zlistid, qlist->itime, qlist->s.zuser, qsys, zstdin, qlist->s.pseq, zrequestor)) return FALSE; } if (fkill_or_rejuv) { if ((icmd & JOB_REJUVENATE) == 0) { if (! fsysdep_kill_job (puuconf, zlistid)) return FALSE; } else { if (! fsysdep_rejuvenate_job (puuconf, zlistid)) return FALSE; } } } } if (qxqt != NULL) { if (qxqt->s.bcmd == 'E') ubuffree (zfree); else usxqt_file_free (); } /* Free up the list of entries. */ qfree = qlist; while (qfree != NULL) { struct scmdlist *qnext; qnext = qfree->qnext; xfree ((pointer) qfree); qfree = qnext; } ubuffree (zlistid); qlist = NULL; zlistid = NULL; } /* Start a new list with the entry we just got. */ if (qcmd != NULL) { qlist = (struct scmdlist *) xmalloc (sizeof (struct scmdlist)); qlist->qnext = NULL; qlist->s = *qcmd; qlist->itime = itime; zlistid = zid; } return TRUE; } /* Show the header of the line describing a workfile. */ static void usworkfile_header (qsys, qcmd, zjobid, itime, ffirst) const struct uuconf_system *qsys; const struct scmd *qcmd; const char *zjobid; long itime; boolean ffirst; { const char *zshowid; struct tm stime; if (ffirst) zshowid = zjobid; else zshowid = "-"; printf ("%s %s %s ", zshowid, qsys->uuconf_zname, qcmd->zuser != NULL ? qcmd->zuser : OWNER); usysdep_localtime (itime, &stime); printf ("%02d-%02d %02d:%02d ", stime.tm_mon + 1, stime.tm_mday, stime.tm_hour, stime.tm_min); } /* List queued executions that have not been processed by uuxqt for one reason or another. */ static boolean fsexecutions (puuconf, icmd, csystems, pazsystems, fnotsystems, cusers, pazusers, fnotusers, iold, iyoung, ccommands, pazcommands, fnotcommands, zcomment, cstdin) pointer puuconf; int icmd; int csystems; char **pazsystems; boolean fnotsystems; int cusers; char **pazusers; boolean fnotusers; long iold; long iyoung; int ccommands; char **pazcommands; boolean fnotcommands; const char *zcomment; int cstdin; { const char *zlocalname; int iuuconf; char *zfile; char *zsystem; boolean ferr; iuuconf = uuconf_localname (puuconf, &zlocalname); if (iuuconf == UUCONF_NOT_FOUND) { zlocalname = zsysdep_localname (); if (zlocalname == NULL) return FALSE; } else if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); return FALSE; } if (! fsysdep_get_xqt_init ((const char *) NULL)) return FALSE; while ((zfile = zsysdep_get_xqt ((const char *) NULL, &zsystem, &ferr)) != NULL) { boolean fmatch; int i; long itime; FILE *e; if (csystems > 0) { fmatch = fnotsystems; for (i = 0; i < csystems; i++) { if (strcmp (pazsystems[i], zsystem) == 0) { fmatch = ! fmatch; break; } } if (! fmatch) { ubuffree (zfile); ubuffree (zsystem); continue; } } itime = ixsysdep_file_time (zfile); if ((iold != (long) -1 && itime > iold) || (iyoung != (long) -1 && itime < iyoung)) { ubuffree (zfile); ubuffree (zsystem); continue; } /* We need to read the execution file before we can check the user name. */ e = fopen (zfile, "r"); if (e == NULL) { /* Probably uucico just deleted the file. */ continue; } if (! fsxqt_file_read (puuconf, e)) { (void) fclose (e); ubuffree (zfile); ubuffree (zsystem); continue; } (void) fclose (e); if (cusers == 0) fmatch = TRUE; else { fmatch = fnotusers; for (i = 0; i < cusers; i++) { if (strcmp (zSxqt_user, pazusers[i]) == 0 || (zSxqt_requestor != NULL && strcmp (zSxqt_requestor, pazusers[i]) == 0)) { fmatch = ! fmatch; break; } } } if (fmatch && ccommands > 0) { fmatch = fnotcommands; for (i = 0; i < ccommands; i++) { if (strcmp (pazcommands[i], "ALL") == 0 || strcmp (pazcommands[i], zSxqt_prog) == 0) { fmatch = ! fmatch; break; } } } if (fmatch) { boolean fbad, fkill_or_rejuv; struct uuconf_system ssys; fbad = FALSE; if ((icmd & JOB_SHOW) != 0) { struct tm stime; printf ("%s %s!", zsystem, zSxqt_system); if (zSxqt_requestor != NULL) printf ("%s", zSxqt_requestor); else printf ("%s", zSxqt_user); usysdep_localtime (itime, &stime); printf (" %02d-%02d %02d:%02d ", stime.tm_mon + 1, stime.tm_mday, stime.tm_hour, stime.tm_min); printf ("%s\n", zSxqt_cmd); } fkill_or_rejuv = FALSE; if ((icmd & JOB_INQUIRE) != 0) { int b; /* Ask stdin whether this job should be killed. */ fprintf (stderr, "%s: %s %s? ", zProgram, (icmd & JOB_REJUVENATE) != 0 ? "Rejuvenate" : "Kill", zSxqt_cmd); (void) fflush (stderr); b = getchar (); fkill_or_rejuv = b == 'y' || b == 'Y'; while (b != EOF && b != '\n') b = getchar (); } else if ((icmd & JOB_KILL) != 0 || (icmd & JOB_REJUVENATE) != 0) fkill_or_rejuv = TRUE; if (fkill_or_rejuv) { if ((strcmp (zSxqt_user, zsysdep_login_name ()) != 0 || strcmp (zsystem, zlocalname) != 0) && ! fsysdep_privileged ()) { ulog (LOG_ERROR, "Job not submitted by you\n"); fbad = TRUE; } } if (! fbad) { iuuconf = uuconf_system_info (puuconf, zsystem, &ssys); if (iuuconf != UUCONF_SUCCESS) { if (iuuconf != UUCONF_NOT_FOUND) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); fbad = TRUE; } else if (strcmp (zsystem, zlocalname) == 0) { iuuconf = uuconf_system_local (puuconf, &ssys); if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); fbad = TRUE; } ssys.uuconf_zname = (char *) zlocalname; } else if (! funknown_system (puuconf, zsystem, &ssys)) { ulog (LOG_ERROR, "Job for unknown system %s", zsystem); fbad = TRUE; } } } if (! fbad && (icmd & (JOB_MAIL | JOB_NOTIFY)) != 0) { if (! fsnotify (puuconf, icmd, zcomment, cstdin, fkill_or_rejuv && (icmd & JOB_REJUVENATE) == 0, zSxqt_cmd, (struct scmdlist *) NULL, (const char *) NULL, itime, zSxqt_user, &ssys, zSxqt_stdin, (pointer) NULL, zSxqt_requestor)) { ferr = TRUE; usxqt_file_free (); ubuffree (zfile); ubuffree (zsystem); break; } } if (! fbad && fkill_or_rejuv) { for (i = 0; i < cSxqt_files; i++) { char *z; z = zsysdep_spool_file_name (&ssys, pazSxqt_files[i], (pointer) NULL); if (z != NULL) { if ((icmd & JOB_REJUVENATE) != 0) (void) fsysdep_touch_file (z); else (void) remove (z); ubuffree (z); } } if ((icmd & JOB_REJUVENATE) != 0) (void) fsysdep_touch_file (zfile); else { if (remove (zfile) != 0) ulog (LOG_ERROR, "remove (%s): %s", zfile, strerror (errno)); } } if (! fbad) (void) uuconf_system_free (puuconf, &ssys); } usxqt_file_free (); ubuffree (zfile); ubuffree (zsystem); } usysdep_get_xqt_free ((const char *) NULL); return ferr; } /* When a job is killed, send mail to the appropriate people. */ static boolean fsnotify (puuconf, icmd, zcomment, cstdin, fkilled, zcmd, qcmd, zid, itime, zuser, qsys, zstdin, pstdinseq, zrequestor) pointer puuconf; int icmd; const char *zcomment; int cstdin; boolean fkilled; const char *zcmd; struct scmdlist *qcmd; const char *zid; long itime; const char *zuser; const struct uuconf_system *qsys; const char *zstdin; pointer pstdinseq; const char *zrequestor; { const char **pz; int cgot; int i, istdin; struct tm stime; char ab[sizeof "1991-12-31 12:00:00"]; const char *zsubject; boolean fret; pz = (const char **) xmalloc (20 * sizeof (const char *)); cgot = 20; i = 0; if (zid == NULL) pz[i++] = "A UUCP execution request"; else { pz[i++] = "UUCP job\n\t"; pz[i++] = zid; pz[i++] = "\nfor system\n\t"; pz[i++] = qsys->uuconf_zname; } pz[i++] = "\nrequested by\n\t"; pz[i++] = zuser != NULL ? zuser : OWNER; if (zid == NULL) { pz[i++] = "\non system\n\t"; pz[i++] = qsys->uuconf_zname; } pz[i++] = "\n"; if (fkilled) pz[i++] = "has been killed.\n"; if (zcomment != NULL) { pz[i++] = zcomment; pz[i++] = "\n"; } pz[i++] = "The job was queued at "; usysdep_localtime (itime, &stime); sprintf (ab, "%04d-%02d-%02d %02d:%02d:%02d", stime.tm_year + 1900, stime.tm_mon + 1, stime.tm_mday, stime.tm_hour, stime.tm_min, stime.tm_sec); pz[i++] = ab; pz[i++] = ".\nIt "; if (fkilled) pz[i++] = "was\n"; else pz[i++] = "is\n"; if (zcmd != NULL) { pz[i++] = "\t"; pz[i++] = zcmd; } else { struct scmdlist *qshow; for (qshow = qcmd; qshow != NULL; qshow = qshow->qnext) { if (i + 10 > cgot) { cgot += 20; pz = (const char **) xrealloc ((pointer) pz, cgot * sizeof (const char *)); } switch (qshow->s.bcmd) { case 'S': pz[i++] = "\tsend "; break; default: case 'R': case 'X': pz[i++] = "\trequest "; break; case 'P': pz[i++] = "\tpoll "; break; #if DEBUG > 0 case 'E': ulog (LOG_FATAL, "fsnotify: Can't happen"); break; #endif } if (qshow->s.zfrom != NULL && qshow->s.zto != NULL) { pz[i++] = qshow->s.zfrom; pz[i++] = " to "; pz[i++] = qshow->s.zto; } } } istdin = i; if (cstdin > 0 && zstdin != NULL) { boolean fspool; char *zfile; FILE *e; fspool = fspool_file (zstdin); if (fspool) zfile = zsysdep_spool_file_name (qsys, zstdin, pstdinseq); else zfile = zsysdep_local_file (zstdin, qsys->uuconf_zpubdir, (boolean *) NULL); if (zfile != NULL && (fspool || fin_directory_list (zfile, qsys->uuconf_pzremote_send, qsys->uuconf_zpubdir, TRUE, TRUE, (const char *) NULL))) { e = fopen (zfile, "r"); if (e != NULL) { int clines, clen; char *zline; size_t cline; pz[i++] = "\n"; istdin = i; clines = 0; zline = NULL; cline = 0; while ((clen = getline (&zline, &cline, e)) > 0) { if (memchr (zline, '\0', (size_t) clen) != NULL) { int ifree; /* A null character means this is probably a binary file. */ for (ifree = istdin; ifree < i; ifree++) ubuffree ((char *) pz[ifree]); i = istdin - 1; break; } ++clines; if (clines > cstdin) break; if (i >= cgot) { cgot += 20; pz = (const char **) xrealloc ((pointer) pz, (cgot * sizeof (char *))); } if (strncmp (zline, "From ", sizeof "From " - 1) != 0) pz[i++] = zbufcpy (zline); else { char *zalc; /* Escape "From " at the start of a line. This should really be the responsibility of the mail transfer agent. On some systems, though, the mail transfer agent does not do it, but user mail programs expect it. We help them out here, since it doesn't matter much--we're already truncating the message anyhow. */ zalc = zbufalc (strlen (zline) + 2); zalc[0] = '>'; strcpy (zalc + 1, zline); pz[i++] = zalc; } } xfree ((pointer) zline); (void) fclose (e); } } ubuffree (zfile); } if (fkilled) zsubject = "UUCP job killed"; else zsubject = "UUCP notification"; fret = TRUE; if ((icmd & JOB_MAIL) != 0) { if (! fsysdep_mail (OWNER, zsubject, i, pz)) fret = FALSE; } if ((icmd & JOB_NOTIFY) != 0 && (zrequestor != NULL || zuser != NULL)) { const char *zmail; char *zfree; if (zrequestor != NULL) zmail = zrequestor; else zmail = zuser; zfree = NULL; if (zid == NULL) { int iuuconf; const char *zloc; /* This is an execution request, which may be from another system. If it is, we must prepend that system name to the user name extracted from the X. file. */ iuuconf = uuconf_localname (puuconf, &zloc); if (iuuconf == UUCONF_NOT_FOUND) { zloc = zsysdep_localname (); if (zloc == NULL) return FALSE; } else if (iuuconf != UUCONF_SUCCESS) ulog_uuconf (LOG_FATAL, puuconf, iuuconf); if (strcmp (qsys->uuconf_zname, zloc) != 0 #if HAVE_INTERNET_MAIL && strchr (zmail, '@') == NULL #endif ) { zfree = zbufalc (strlen (qsys->uuconf_zname) + strlen (zmail) + sizeof "!"); sprintf (zfree, "%s!%s", qsys->uuconf_zname, zmail); zmail = zfree; } } if (! fsysdep_mail (zmail, zsubject, i, pz)) fret = FALSE; ubuffree (zfree); } while (istdin < i) { ubuffree ((char *) pz[istdin]); istdin++; } xfree ((pointer) pz); return fret; } /* Handle the -q option. For each remote system this lists the number of jobs queued, the number of executions queued, and the current call status. We get the executions all at once, because they are not accessed by system. They could be, but it is possible to have executions pending for an unknown system, so special handling would still be required. */ struct sxqtlist { struct sxqtlist *qnext; char *zsystem; int cxqts; long ifirst; }; /* These local functions need the definition of sxqtlist for the prototype. */ static boolean fsquery_system P((const struct uuconf_system *qsys, struct sxqtlist **pq, long inow, const char *zlocalname, int csystems, char **pazsystems, boolean fnotsystems, long iold, long iyoung)); static boolean fsquery_show P((const struct uuconf_system *qsys, int cwork, long ifirstwork, struct sxqtlist *qxqt, long inow, const char *zlocalname, int csystems, char **pazsystems, boolean fnotsystems, long iold, long iyoung)); static boolean fsquery (puuconf, csystems, pazsystems, fnotsystems, iold, iyoung) pointer puuconf; int csystems; char **pazsystems; boolean fnotsystems; long iold; long iyoung; { int iuuconf; const char *zlocalname; struct sxqtlist *qlist; char *zfile, *zsystem; boolean ferr; long inow; char **pznames, **pz; boolean fret; iuuconf = uuconf_localname (puuconf, &zlocalname); if (iuuconf == UUCONF_NOT_FOUND) { zlocalname = zsysdep_localname (); if (zlocalname == NULL) return FALSE; } else if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); return FALSE; } /* Get a count of all the execution files. */ if (! fsysdep_get_xqt_init ((const char *) NULL)) return FALSE; qlist = NULL; while ((zfile = zsysdep_get_xqt ((const char *) NULL, &zsystem, &ferr)) != NULL) { struct sxqtlist *qlook; for (qlook = qlist; qlook != NULL; qlook = qlook->qnext) if (strcmp (zsystem, qlook->zsystem) == 0) break; if (qlook != NULL) { long itime; ubuffree (zsystem); ++qlook->cxqts; itime = ixsysdep_file_time (zfile); if (itime < qlook->ifirst) qlook->ifirst = itime; } else { struct sxqtlist *qnew; qnew = (struct sxqtlist *) xmalloc (sizeof (struct sxqtlist)); qnew->qnext = qlist; qnew->zsystem = zsystem; qnew->cxqts = 1; qnew->ifirst = ixsysdep_file_time (zfile); qlist = qnew; } ubuffree (zfile); } usysdep_get_xqt_free ((const char *) NULL); if (ferr) return FALSE; inow = ixsysdep_time ((long *) NULL); /* Show the information for each system. */ iuuconf = uuconf_system_names (puuconf, &pznames, 0); if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); return FALSE; } fret = TRUE; for (pz = pznames; *pz != NULL; pz++) { struct uuconf_system ssys; iuuconf = uuconf_system_info (puuconf, *pz, &ssys); if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); fret = FALSE; continue; } if (! fsquery_system (&ssys, &qlist, inow, zlocalname, csystems, pazsystems, fnotsystems, iold, iyoung)) fret = FALSE; (void) uuconf_system_free (puuconf, &ssys); xfree ((pointer) *pz); } /* Check for the local system in the list of execution files. */ if (qlist != NULL) { struct sxqtlist **pq; for (pq = &qlist; *pq != NULL; pq = &(*pq)->qnext) { if (strcmp ((*pq)->zsystem, zlocalname) == 0) { struct uuconf_system ssys; struct sxqtlist *qfree; iuuconf = uuconf_system_info (puuconf, zlocalname, &ssys); if (iuuconf != UUCONF_SUCCESS) { if (iuuconf != UUCONF_NOT_FOUND) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); fret = FALSE; break; } iuuconf = uuconf_system_local (puuconf, &ssys); if (iuuconf != UUCONF_SUCCESS) { ulog_uuconf (LOG_ERROR, puuconf, iuuconf); fret = FALSE; break; } ssys.uuconf_zname = (char *) zlocalname; } if (! fsquery_show (&ssys, 0, 0L, *pq, inow, zlocalname, csystems, pazsystems, fnotsystems, iold, iyoung)) fret = FALSE; (void) uuconf_system_free (puuconf, &ssys); qfree = *pq; *pq = qfree->qnext; ubuffree (qfree->zsystem); xfree ((pointer) qfree); break; } } } /* Print out information for any unknown systems for which we have execution files. */ while (qlist != NULL) { struct uuconf_system ssys; struct sxqtlist *qnext; if (! funknown_system (puuconf, qlist->zsystem, &ssys)) { ulog (LOG_ERROR, "Executions queued up for unknown systems"); fret = FALSE; break; } if (! fsquery_show (&ssys, 0, 0L, qlist, inow, zlocalname, csystems, pazsystems, fnotsystems, iold, iyoung)) fret = FALSE; (void) uuconf_system_free (puuconf, &ssys); qnext = qlist->qnext; ubuffree (qlist->zsystem); xfree ((pointer) qlist); qlist = qnext; } return fret; } /* Query a single known system. */ static boolean fsquery_system (qsys, pq, inow, zlocalname, csystems, pazsystems, fnotsystems, iold, iyoung) const struct uuconf_system *qsys; struct sxqtlist **pq; long inow; const char *zlocalname; int csystems; char **pazsystems; boolean fnotsystems; long iold; long iyoung; { int cwork; long ifirstwork; char *zid; boolean fret; if (! fsysdep_get_work_init (qsys, UUCONF_GRADE_LOW)) return FALSE; cwork = 0; ifirstwork = 0L; zid = NULL; while (TRUE) { struct scmd s; long itime; char *zthisid; if (! fsysdep_get_work (qsys, UUCONF_GRADE_LOW, &s)) return FALSE; if (s.bcmd == 'H') break; zthisid = zsysdep_jobid (qsys, s.pseq); if (zid != NULL && strcmp (zid, zthisid) == 0) ubuffree (zthisid); else { ++cwork; ubuffree (zid); zid = zthisid; } itime = ixsysdep_work_time (qsys, s.pseq); if (ifirstwork == 0L || ifirstwork > itime) ifirstwork = itime; } usysdep_get_work_free (qsys); ubuffree (zid); /* Find the execution information, if any. */ while (*pq != NULL) { if (strcmp ((*pq)->zsystem, qsys->uuconf_zname) == 0) break; pq = &(*pq)->qnext; } /* If there are no commands and no executions, don't print any information for this system. */ if (cwork == 0 && *pq == NULL) return TRUE; fret = fsquery_show (qsys, cwork, ifirstwork, *pq, inow, zlocalname, csystems, pazsystems, fnotsystems, iold, iyoung); if (*pq != NULL) { struct sxqtlist *qfree; qfree = *pq; *pq = qfree->qnext; ubuffree (qfree->zsystem); xfree ((pointer) qfree); } return fret; } /* Print out the query information for a single system. We handle the local system specially. */ static boolean fsquery_show (qsys, cwork, ifirstwork, qxqt, inow, zlocalname, csystems, pazsystems, fnotsystems, iold, iyoung) const struct uuconf_system *qsys; int cwork; long ifirstwork; struct sxqtlist *qxqt; long inow; const char *zlocalname; int csystems; char **pazsystems; boolean fnotsystems; long iold; long iyoung; { boolean flocal; struct sstatus sstat; boolean fnostatus; struct tm stime; int cpad; /* Make sure this is one of the systems we are printing. */ if (csystems > 0) { boolean fmatch; int i; fmatch = fnotsystems; for (i = 0; i < csystems; i++) { if (strcmp (pazsystems[i], qsys->uuconf_zname) == 0) { fmatch = ! fmatch; break; } } if (! fmatch) return TRUE; } /* Make sure the commands are within the time bounds. */ if ((iold != (long) -1 && (cwork == 0 || ifirstwork > iold) && (qxqt == NULL || qxqt->ifirst > iold)) || (iyoung != (long) -1 && (cwork == 0 || ifirstwork < iyoung) && (qxqt == NULL || qxqt->ifirst < iyoung))) return TRUE; flocal = strcmp (qsys->uuconf_zname, zlocalname) == 0; if (! flocal) { if (! fsysdep_get_status (qsys, &sstat, &fnostatus)) return FALSE; } printf ("%-10s %3dC (", qsys->uuconf_zname, cwork); if (cwork == 0) { printf ("0 secs"); cpad = 3; } else cpad = csunits_show (inow - ifirstwork); printf (") "); while (cpad-- != 0) printf (" "); if (qxqt == NULL) printf (" 0X (0 secs) "); else { printf ("%3dX (", qxqt->cxqts); cpad = csunits_show (inow - qxqt->ifirst); printf (")"); while (cpad-- != 0) printf (" "); } if (flocal || fnostatus) { printf ("\n"); if (! flocal) ubuffree (sstat.zstring); return TRUE; } usysdep_localtime (sstat.ilast, &stime); printf (" %02d-%02d %02d:%02d ", stime.tm_mon + 1,stime.tm_mday, stime.tm_hour, stime.tm_min); if (sstat.zstring == NULL) printf ("%s\n", azStatus[(int) sstat.ttype]); else { printf ("%s\n", sstat.zstring); ubuffree (sstat.zstring); } return TRUE; } /* Print a time difference in the largest applicable units. */ static int csunits_show (idiff) long idiff; { const char *zunit; long iunits; int cpad; if (idiff > (long) 24 * (long) 60 * (long) 60) { iunits = idiff / ((long) 24 * (long) 60 * (long) 60); zunit = "day"; cpad = 4; } else if (idiff > (long) 60 * 60) { iunits = idiff / (long) (60 * 60); zunit = "hour"; cpad = 3; } else if (idiff > (long) 60) { iunits = idiff / (long) 60; zunit = "min"; cpad = 4; } else { iunits = idiff; zunit = "sec"; cpad = 4; } printf ("%ld %s%s", iunits, zunit, iunits == 1 ? "" : "s"); if (iunits != 1) --cpad; if (iunits > 99) --cpad; if (iunits > 9) --cpad; return cpad; } /* Give a list of all status entries for all machines that we have status entries for. We need to get a list of status entries in a system dependent fashion, since we may have status for unknown systems. */ static boolean fsmachines () { pointer phold; char *zsystem; boolean ferr; struct sstatus sstat; if (! fsysdep_all_status_init (&phold)) return FALSE; while ((zsystem = zsysdep_all_status (phold, &ferr, &sstat)) != NULL) { struct tm stime; usysdep_localtime (sstat.ilast, &stime); printf ("%-14s %02d-%02d %02d:%02d ", zsystem, stime.tm_mon + 1, stime.tm_mday, stime.tm_hour, stime.tm_min); if (sstat.zstring == NULL) printf ("%s", azStatus[(int) sstat.ttype]); else { printf ("%s", sstat.zstring); ubuffree (sstat.zstring); } ubuffree (zsystem); if (sstat.ttype != STATUS_TALKING && sstat.cwait > 0) { printf (" (%d %s", sstat.cretries, sstat.cretries == 1 ? "try" : "tries"); if (sstat.ilast + sstat.cwait > ixsysdep_time ((long *) NULL)) { usysdep_localtime (sstat.ilast + sstat.cwait, &stime); printf (", next after %02d-%02d %02d:%02d", stime.tm_mon + 1, stime.tm_mday, stime.tm_hour, stime.tm_min); } printf (")"); } printf ("\n"); } usysdep_all_status_free (phold); return ! ferr; }