/* * xqt: process work inside cico */ #include "cico.h" #include static char *x_input; /* current input file */ static char *x_output; /* current output file */ static char *x_command; /* current command */ static char *x_originator; /* user & system responsible for ^^^ */ /* * diagnostic() produces a error message for the execute() function, then * recovers memory used for workfile pointers. */ static diagnostic(fmt) char *fmt; { va_list args; if (fmt) { va_start(args, fmt); vprintf(fmt, args); va_end(args); putchar('\n'); } if (x_input) remove(x_input); if (x_output) remove(x_output); free(x_input); free(x_command); free(x_originator); } /* diagnostic */ /* * rmail() sends mail to someone on a remote system- used internally * by execute() to return output to the sender. * * what it does is creates a X.file, renames the file argument to * D.file, then adds a S line to the workfile for the remote system. */ static rmail(originator, workfile) char *originator; char *workfile; { char user[200], sys[20]; char fname[20]; int seq = getseq(); char *itob36(); char *zseq; FILE *x; if (sscanf(originator, "%200s %20s", user, sys) == 2 && findsys(sys)) { zseq = itob36(seq); sprintf(fname, "X%s.%s", sys, zseq); if (x = fopen(fname, "wb")) { fprintf(x, "U %s %s\n", sys, SITE); fprintf(x, "F D.%sbc%04x\n", sys, seq); fprintf(x, "I D.%sbc%04x\n", sys, seq); fprintf(x, "C rmail %s\n", user); fclose(x); if (x = fopen(sys, "a")) { fprintf(x, " %3sS D%s.%s D.%sbc%04x uucp - D%s.%s 0666 uucp\n", zseq, sys, zseq, sys, seq, sys, zseq); fprintf(x, " %3sS X%s.%s X.%sbc%04x uucp - X%s.%s 0666 uucp\n", zseq, sys, zseq, sys, seq, sys, zseq); fclose(x); } sprintf(fname, "D%s.%s", sys, zseq); rename(workfile, fname); } } } /* rmail */ /* * validate() validates a command according to COMMANDS; returns 1 if valid * On the first call (unread==1), it reads the contents of COMMANDS into a * linked list for subsequence accesses. */ static struct permit { struct permit *p_next; char p_name[1]; } *valid_cmds = (struct permit *)0; static validate(cmd) char *cmd; { static char text[200]; FILE *cmds; struct permit *chk; static char unread=1; /* has COMMANDS been read yet? */ if (unread) { unread=0; if (cmds=fopen(makepath(text, NETDIR, COMMANDS), "r")) { while (rdline(cmds, text, sizeof text)) { if (strlen(text) == 0) continue; chk = (struct permit *)xmalloc(sizeof(*chk) + strlen(text)); chk->p_next = valid_cmds; valid_cmds = chk; strcpy(chk->p_name, text); } fclose(cmds); } } if (sscanf(cmd, "%80s", text) == 1) for (chk=valid_cmds; chk; chk = chk->p_next) if (strcmp(text, chk->p_name) == 0) return 1; return 0; } /* validate */ /* * execute() does a single workfile * * first, walks through the workfile, picking up originator, command, and * standard input. (all of which are required) Then, it redirects stdin * to the input file and stdout and stderr to a spoolfile, then executes * the command. If the command generates output, it's mailed back to the * originator of the command. */ static void execute(work) register FILE *work; { char text[200], rest[128]; char cmd; register char *base; char talked; register status; x_output = x_input = x_command = x_originator = (char *)0; sprintf(text, "output.%03x", getpid()); x_output = strdup(text); while (fgets(text, sizeof text-1, work)) if (sscanf(text, "%c %[^\n]", &cmd, rest) == 2) switch (cmd) { /* User who instigated this command */ case 'U': if (x_originator) { diagnostic("duplicate U line"); return; } x_originator = strdup(rest); break; /* Command to execute */ case 'C': if (x_command) { diagnostic("duplicate C line"); return; } x_command = strdup(rest); break; /* standard Input */ case 'I': if (x_input) { diagnostic("duplicate I line"); return; } /* fall through into F code */ /* required File */ case 'F': tosify(rest); base = basename(rest); if (base == rest) /* D.file? */ twiddle(rest, text); else if (!parsegeneric(base, rest, text)) { diagnostic("badly formed %c line <%s>", cmd, rest); return; } if (access(text, 0) < 0) { diagnostic("cannot access file %s (%s)", rest, text); return; } if (cmd == 'I') x_input = strdup(text); break; } /* cmd switch */ /* * finished reading workfile, now try executing the beast... */ #if 0 printf("x_command = %s\n", x_command ? x_command : "{null}"); printf("x_originator = %s\n", x_originator ? x_originator : "{null}"); #endif if (x_command && x_originator) { #define LASTFD 2 int hold[1+LASTFD], input, output; register i; #if ATARIST if (x_input) input = open(x_input, O_RDONLY); else { /* no input file - connect input to a write-only file */ sprintf(text, "null.%03x", getpid()); x_input = strdup(text); input = open(x_input, O_WRONLY|O_CREAT, 0666); } if (input < 0) { diagnostic("execute() cannot open input"); return; } #endif #if UNIX if ((input = open(x_input ? x_input : "/dev/null", O_RDONLY)) < 0) { diagnostic("execute() cannot open input"); return; } #endif #if MSDOS if ((input = open(x_input ? x_input : "nul:", O_RDONLY)) < 0) { diagnostic("execute() cannot open input"); return; } #elif OS2 if ((input = open(x_input ? x_input : "/dev/nul", O_RDONLY)) < 0) { diagnostic("execute() cannot open input"); return; } #endif output = open(x_output, O_WRONLY|O_CREAT, 0666); if (output < 0) { diagnostic("execute() cannot create output - bye!\n"); return; } if (validate(x_command)) { for (i=0; i<=LASTFD; i++) { hold[i] = dup(i); close(i); dup2((i==0)?input:output, i); } status = system(x_command); if (talked = (tell(output) > 0 || status != 0)) { sprintf(text, "\nxqt cmd (%s!%s) status (exit %d)\n", SITE, x_command, status); write(output, text, strlen(text)); } for (i=0; i<=LASTFD; i++) { close(i); dup2(hold[i], i); close(hold[i]); } } else { sprintf(text, "xqt cmd (%s!%s) permission denied\n", SITE, x_command); write(output, text, strlen(text)); talked = 1; } if (talked && x_input) { lseek(input, 0L, 2); if (tell(input) > 0) { strcpy(text, "\n--Failed message follows--\n"); write(output, text, sizeof text); lseek(input, 0L, 0); while ((i=read(input, text, sizeof text)) > 0) write(output, text, sizeof text); } } close(output); close(input); if (talked) rmail(x_originator, x_output); diagnostic((char *)0); } else diagnostic("incomplete execute-file!"); return; } /* execute() */ /* * process() walks the spooldir, executing X. files */ process() { extern char *glob(); register char *fn; FILE *workfile; for (fn=glob("*.x", (void*)0); fn; fn=glob((char *)0, (void*)0)) { if (workfile=fopen(fn, "r")) { execute(workfile); fclose(workfile); remove(fn); } else logerror("Cannot open workfile %s", fn); } } /* process */