|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T e
Length: 7711 (0x1e1f) Types: TextFile Names: »exec.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki └─⟦this⟧ »EUUGD11/euug-87hel/sec8/uutty/exec.c«
#include "uutty.h" /* ** Start up a new program in the current process. This is normally ** to start up a shell for a logged-in user. If the command can't ** be executed, -1 is returned. Note that we can define a new search ** path here which will overwrite the one we were given. */ Flag forkfl = 0; /* Should we fork or exec directly? */ Flag pathfl = 0; /* True if PATH defined in environment */ /* ** The 'path' variable should be defined appropriately for your ** system. If it is null, we will just pass on the path that ** was handed to us, which may be right on many systems. */ #ifdef Cadmus char *path = "PATH=:.:/bin:/bin.cadmus:/bin.sys5:/bin.sys3:/bin.ver7:/usr/ucb:/usr/bin:/etc:/usr/local:/usr/new:"; #define Path #endif #ifdef VME char *path = "PATH=:.:/bin:/usr/bin:/etc:"; #define Path #endif #ifndef Path char *path = 0; /* No search path */ #endif exec(cook,cmd,pp) int cook; /* Should we do cooked or raw I/O? */ char *cmd; /* Null-terminated command */ struct passwd *pp; /* The user's /etc/passwd entry, unpacked */ { int a, c, e, i, n, r; int child; Flag lognfl, shelfl, homefl; char *av[10]; /* This should be room enough */ char *cp, *dp; char**ev; char arg0[30]; /* For shell's visible name */ char logn[30]; /* For LOGNAME=<id> string */ char home[30]; /* For HOME=<dir> string */ char shll[30]; /* For SHELL=<prog> string */ char *shell="/bin/sh"; /* default shell */ extern long malloc(); D5("exec(%d,\"%s\",%06lX)",cook,cmd,pp); r = -1; for (i=0; environ[i]; i++); /* How big is environ[]? */ n = (i+5) * sizeof(char**); /* Space for copy + 5 entries */ D5("exec: Get %d bytes for %d+5 environment entries.",n,i); ev = (char**)malloc(n); /* Allocate a copy for us */ if (ev == NULL) { E("Can't get %d bytes for environment table [exec].",n); Fail; } for (e=0; environ[e]; e++) { /* Copy the environment vector */ ev[e] = environ[e]; D6("ev[%2d]=\"%s\"",e,ev[e]); } ev[e] = 0; D3("exec: There are %d environment entries.",e); pid = getpid(); D4("exec: This is process %d.",pid); a = e = 0; /* indices for av[] and ev[] */ for (cp=cmd; *cp; ++cp) { /* Scan the command for whitespace */ c = *cp; if (c == ' ' || c == '\t') { av[a++] = "-sh"; av[a++] = "-c"; av[a++] = cmd; break; } else if (c == ':' || c == '\n') break; } if (a == 0) { /* the command is just a program name */ shell = cmd; /* Note that it's our shell */ dp = av[a++] = arg0; /* Name to tell shell */ *dp++ = '-'; /* Build arg0 with initial '-' */ cp = lastfield(cmd,'/'); /* Find the last field of the name */ while (*cp) *dp++ = *cp++; /* Copy name to arg0 */ *dp = 0; /* Gotta have a null terminator */ D4("exec: arg0=\"%s\"",arg0); } D3("av[%2d]=\"%s\"",a-1,av[a-1]); D7("exec:before sprintf(%06lX,\"%s\",%06lX)",logn,"LOGNAME=%s\0",pp->pw_name); sprintf(logn,"LOGNAME=%s\0",pp->pw_name); D6("exec: after sprintf() logn=\"%s\"",logn); D7("exec:before sprintf(%06lX,\"%s\",%06lX)",home,"HOME=%s\0" ,pp->pw_dir); sprintf(home,"HOME=%s\0" ,pp->pw_dir); D6("exec: after sprintf() home=\"%s\"",home); D7("exec:before sprintf(%06lX,\"%s\",%06lX)",shll,"SHELL=%s\0" ,shell); sprintf(shll,"SHELL=%s\0" ,shell); D6("exec: after sprintf() shll=\"%s\"",shll); if (debug >= 5) { av[a++] = "-VX"; /* This turns on shell debugging */ D3("av[%2d]=\"%s\"",a-1,av[a-1]); } av[a] = 0; /* Paranoia */ /* ** This is supposed to help, but seems not to: ** D4("exec: before setpgrp()"); i = setpgrp(); D4("exec: setpgrp()=%d",i); */ lognfl = shelfl = homefl = 0; /* Flags for noticing environment entries */ for (e=0; ev[e]; e++) { /* Examine the environment table */ D3("exec: Examine ev[%2d]=%06lX=\"%s\"",e,ev[e],ev[e]); if (st_init("PATH=",ev[e]) > 0) { D7("exec: Matched \"PATH=\"; path=%06lX=\"%s\"",path,path); if (path) ev[e] = path; /* Use special path */ D6("ev[%2d]=\"%s\"",e,ev[e]); pathfl++; /* Note we did it */ } if (st_init("LOGNAME=",ev[e]) > 0) { ev[e] = logn; /* Use special path */ D6("ev[%2d]=\"%s\"",e,ev[e]); lognfl++; /* Note we did it */ } if (st_init("HOME=",ev[e]) > 0) { ev[e] = home; /* Use special path */ D6("ev[%2d]=\"%s\"",e,ev[e]); homefl++; /* Note we did it */ } if (st_init("SHELL=",ev[e]) > 0) { ev[e] = shll; /* Use special path */ D6("ev[%2d]=\"%s\"",e,ev[e]); shelfl++; /* Note we did it */ } } if (!homefl) ev[e++] = home; /* Add the home directory */ if (!lognfl) ev[e++] = logn; /* Add the login id */ if (!shelfl) ev[e++] = shll; /* Add the shell's name */ if (!pathfl) ev[e++] = path; /* Add the search path (may be null) */ D3("exec: There are %d environment entries.",e); ev[e] = 0; /* Paranoia */ if (debug >= 3) { /* Display the shell's parameters */ P("before execve(\"%s\",%lX,%lX)",shell,av,ev); for (i=0; av[i]; i++) P("arg[%2d]=\"%s\"",i,av[i]); for (i=0; ev[i]; i++) P("env[%2d]=\"%s\"",i,ev[i]); } if (debug) P("%s Start %s for u=%d=%s g=%d.",getime(),shell,pp->pw_uid,pp->pw_name,pp->pw_gid); if (cook) makesane(dev); if (dev != 0) {close(0); i = dup(dev); D3("exec: File %d=\"%s\"",i,device); } if (dev != 1) {close(1); i = dup(dev); D3("exec: File %d=\"%s\"",i,device); } child = -1; /* Default is no child process */ pid = getpid(); /* Note which process we are now */ if (forkfl) { /* Are we forking or execing directly? */ D4("exec: Forking sub-process for shell."); if (lockfl) { /* Should we create a lockfile? */ lockfn = creat(lockfile,0); if (debug >= 2) P("%s: Create lockfile %d=\"%s\".",getime(),lockfn,lockfile); if (lockfn < 0) { /* Either locked or directory isn't writable */ E("Can't create lockfile \"%s\" [errno=%d]",lockfile,errno); die(errno); } locked = 1; /* Note that there's a lockfile */ } if ((child = fork()) > 0) { /* Are we the parent? */ D3("exec: %s: Shell process %d created.",getime(),child); if (lsleep > 0) sleep(lsleep); for (;;) { /* Loop until shell goes away */ errno = 0; r = wait(0); /* Sleep until a subprocess dies */ D3("%s: wait(0)=%d",getime(),r); if (r == child) /* Was it the shell process? */ Done; /* If so, all's fine */ D3("%s: After wait(0)=%d [errno=%d]",getime(),r,errno); if (r > 0) { E("%s: Wrong child %d died; waiting for %d.",getime(),r,child); continue; } switch(errno) { case ECHILD: D3("exec: wait(0)=%d [errno=%d=No child]",r,errno); Done; default: E("Unknown errno=%d after wait(0)=%d",errno,r); Done; } } /* Hang until the shell process dies */ done: if (debug) sleep(1); D3("exec: %s: Child %d gone.",getime(),r); if (r > 0) r = 0; if (lockfl) unlock(); if (debug) P("%s: \"%s\" done , die(%d)",getime(),shell,r); Fail; } } /* ** If we fall through to here, we are the process to exec a shell. ** We may be the original process or a subprocess. */ if (debug > 1) { pid = getpid(); P("%s: Shell process %d.",getime(),pid); } if (dev != 2) { close(2); i = dup(dev); } /**** Don't produce debug output after this! */ errno = 0; if (dev>2) close(dev); /* Don't give excess open files to the shell */ r = execve(shell,av,ev); E("Can't exec \"%s\"\t[errno=%d]",shell,errno); /* ** Note that we always terminate, regardless of how we get here. ** If we are being run from init(1), a new process will be started ** up. If not, we just go away. This isn't necessary, but seems ** in general to be a good idea. */ fail: /* Both processes come here to terminate */ if (lsleep > 0) sleep(lsleep); /* Don't respawn too fast */ die(r); /* This will respawn if we're a daemon */ }