200 lines
4.0 KiB
C
Executable File
200 lines
4.0 KiB
C
Executable File
#ident "@(#)under.c 1.9 92/07/14 SMI"
|
|
|
|
|
|
/*
|
|
* under.c - program to execute a command under a given directory
|
|
*
|
|
* Copyright (c) 1985 Sun Microsystems, Inc.
|
|
*/
|
|
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <rpc/rpc.h>
|
|
#include <nfs/nfs.h>
|
|
#include <rpcsvc/mount.h>
|
|
#include <sys/time.h>
|
|
|
|
static char **Argv; /* saved argument vector (for ps) */
|
|
static char *LastArgv; /* saved end-of-argument vector */
|
|
|
|
int Debug = 0;
|
|
|
|
int child = 0; /* pid of the executed process */
|
|
int ChildDied = 0; /* true when above is valid */
|
|
int HasHelper = 0; /* must kill helpers (interactive mode) */
|
|
time_t time_now;
|
|
/*
|
|
* SETPROCTITLE -- set the title of this process for "ps"
|
|
*
|
|
* Does nothing if there were not enough arguments on the command
|
|
* line for the information.
|
|
*
|
|
* Side Effects:
|
|
* Clobbers argv[] of our main procedure.
|
|
*/
|
|
void
|
|
setproctitle(user, host)
|
|
char *user, *host;
|
|
{
|
|
register char *tohere;
|
|
|
|
tohere = Argv[0];
|
|
if ((int)(LastArgv == (char *)NULL) ||
|
|
(int)(strlen(user)+strlen(host)+3) > (int)(LastArgv - tohere))
|
|
return;
|
|
*tohere++ = '-'; /* So ps prints (rpc.rexd) */
|
|
sprintf(tohere, "%s@%s", user, host);
|
|
while (*tohere++) /* Skip to end of printf output */
|
|
;
|
|
while (tohere < LastArgv) /* Avoid confusing ps */
|
|
*tohere++ = ' ';
|
|
}
|
|
|
|
|
|
void
|
|
main(argc, argv)
|
|
int argc;
|
|
char **argv;
|
|
{
|
|
static char usage[] = "Usage: under [-d] dir command...\n";
|
|
char *dir, *p;
|
|
char hostname[255];
|
|
char *tmpdir, *subdir, *parsefs();
|
|
char dirbuf[1024];
|
|
char error[1024];
|
|
int status;
|
|
int len;
|
|
|
|
if (argc < 3)
|
|
{
|
|
fprintf(stderr, usage);
|
|
exit(1);
|
|
}
|
|
|
|
/*
|
|
* argv start and extent for setproctitle()
|
|
*/
|
|
Argv = argv;
|
|
if (argc > 0)
|
|
LastArgv = argv[argc-1] + strlen(argv[argc-1]);
|
|
else
|
|
LastArgv = NULL;
|
|
|
|
gethostname(hostname, 255);
|
|
strcat(hostname, ":/");
|
|
len = strlen(hostname);
|
|
if ( strcmp( argv[1], "-d" ) == 0 )
|
|
{
|
|
Debug = 1;
|
|
argv++;
|
|
}
|
|
dir = argv[1];
|
|
if ( (int)strlen(dir) > len && (int)strncmp(dir, hostname, len) == 0)
|
|
dir = strchr(dir, ':') + 1;
|
|
else if (p = strchr(dir, ':'))
|
|
{
|
|
if (p[1] != '/')
|
|
{
|
|
fprintf(stderr, "under: %s invalid name\n", dir);
|
|
exit(1);
|
|
}
|
|
|
|
tmpdir = mktemp("/tmp/underXXXXXX");
|
|
|
|
if ( Debug && errno )
|
|
{
|
|
if ( errno != ENOENT )
|
|
printf("mktemp of %s returned %d %s\n",
|
|
tmpdir, errno, strerror(errno));
|
|
}
|
|
errno = 0; /* XXX access() call in mktemp sets errno = ENOENT */
|
|
|
|
if (mkdir(tmpdir, 0777))
|
|
{
|
|
perror(tmpdir);
|
|
exit(1);
|
|
}
|
|
|
|
if ( Debug && errno )
|
|
printf("mkdir of %s returned %d %s\n",
|
|
tmpdir, errno, strerror(errno));
|
|
|
|
subdir = parsefs(dir, error);
|
|
if (subdir == NULL)
|
|
{
|
|
exit(1);
|
|
}
|
|
time_now = time((long *) 0);
|
|
if (mount_nfs(dir, tmpdir, error))
|
|
{
|
|
exit(1);
|
|
}
|
|
strcpy(dirbuf, tmpdir);
|
|
strcat(dirbuf, "/");
|
|
strcat(dirbuf, subdir);
|
|
status = runcmd(dirbuf, argv[2], &argv[2]);
|
|
if (umount_nfs(dir, tmpdir))
|
|
fprintf(stderr, "under: couldn't umount %s\n", dir);
|
|
rmdir(tmpdir);
|
|
exit(status);
|
|
}
|
|
|
|
setgid(getgid());
|
|
setuid(getuid());
|
|
if (chdir(dir))
|
|
{
|
|
perror(dir);
|
|
exit(1);
|
|
}
|
|
execvp(argv[2], &argv[2]);
|
|
perror(argv[2]);
|
|
exit(1);
|
|
/* NOTREACHED */
|
|
}
|
|
|
|
typedef void (*sig_t)();
|
|
|
|
int
|
|
runcmd(dir, cmd, args)
|
|
char *dir;
|
|
char *cmd;
|
|
char **args;
|
|
{
|
|
int pid, child, status;
|
|
sig_t sigint, sigquit;
|
|
|
|
sigint = sigset(SIGINT, SIG_IGN);
|
|
sigquit = sigset(SIGQUIT, SIG_IGN);
|
|
pid = fork();
|
|
if (pid == -1)
|
|
return (0177);
|
|
if (pid == 0)
|
|
{
|
|
setgid(getgid());
|
|
setuid(getuid());
|
|
if (chdir(dir))
|
|
{
|
|
perror(dir);
|
|
exit(1);
|
|
}
|
|
(void) sigset(SIGINT, sigint);
|
|
(void) sigset(SIGQUIT, sigquit);
|
|
execvp(cmd, args);
|
|
perror(cmd);
|
|
exit(1);
|
|
}
|
|
while ((child = wait(&status)) != pid && child != -1)
|
|
;
|
|
(void) sigset(SIGINT, sigint);
|
|
(void) sigset(SIGQUIT, sigquit);
|
|
if (child == -1)
|
|
return (0177);
|
|
if (status & 0377)
|
|
return (status & 0377);
|
|
return ((status >> 8) & 0377);
|
|
}
|