1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 *
22 * Copyright 1985 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28
29 /*
30 * under.c - program to execute a command under a given directory
31 *
32 */
33
34 #include <errno.h>
35 #include <signal.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #include <rpc/rpc.h>
41 #include <nfs/nfs.h>
42 #include <rpcsvc/mount.h>
43 #include <sys/time.h>
44
45 static char **Argv; /* saved argument vector (for ps) */
46 static char *LastArgv; /* saved end-of-argument vector */
47
48 int Debug = 0;
49
50 int child = 0; /* pid of the executed process */
51 int ChildDied = 0; /* true when above is valid */
52 int HasHelper = 0; /* must kill helpers (interactive mode) */
53 time_t time_now;
54 /*
55 * SETPROCTITLE -- set the title of this process for "ps"
56 *
57 * Does nothing if there were not enough arguments on the command
58 * line for the information.
59 *
60 * Side Effects:
61 * Clobbers argv[] of our main procedure.
62 */
63 void
setproctitle(user,host)64 setproctitle(user, host)
65 char *user, *host;
66 {
67 register char *tohere;
68
69 tohere = Argv[0];
70 if ((int)(LastArgv == (char *)NULL) ||
71 (int)(strlen(user)+strlen(host)+3) > (int)(LastArgv - tohere))
72 return;
73 *tohere++ = '-'; /* So ps prints (rpc.rexd) */
74 sprintf(tohere, "%s@%s", user, host);
75 while (*tohere++) /* Skip to end of printf output */
76 ;
77 while (tohere < LastArgv) /* Avoid confusing ps */
78 *tohere++ = ' ';
79 }
80
81
82 void
main(argc,argv)83 main(argc, argv)
84 int argc;
85 char **argv;
86 {
87 static char usage[] = "Usage: under [-d] dir command...\n";
88 char *dir, *p;
89 char hostname[255];
90 char *tmpdir, *subdir, *parsefs();
91 char dirbuf[1024];
92 char error[1024];
93 int status;
94 int len;
95
96 if (argc < 3)
97 {
98 fprintf(stderr, usage);
99 exit(1);
100 }
101
102 /*
103 * argv start and extent for setproctitle()
104 */
105 Argv = argv;
106 if (argc > 0)
107 LastArgv = argv[argc-1] + strlen(argv[argc-1]);
108 else
109 LastArgv = NULL;
110
111 gethostname(hostname, 255);
112 strcat(hostname, ":/");
113 len = strlen(hostname);
114 if ( strcmp( argv[1], "-d" ) == 0 )
115 {
116 Debug = 1;
117 argv++;
118 }
119 dir = argv[1];
120 if ( (int)strlen(dir) > len && (int)strncmp(dir, hostname, len) == 0)
121 dir = strchr(dir, ':') + 1;
122 else if (p = strchr(dir, ':'))
123 {
124 if (p[1] != '/')
125 {
126 fprintf(stderr, "under: %s invalid name\n", dir);
127 exit(1);
128 }
129
130 tmpdir = mktemp("/tmp/underXXXXXX");
131
132 if ( Debug && errno )
133 {
134 if ( errno != ENOENT )
135 printf("mktemp of %s returned %d %s\n",
136 tmpdir, errno, strerror(errno));
137 }
138 errno = 0; /* XXX access() call in mktemp sets errno = ENOENT */
139
140 if (mkdir(tmpdir, 0777))
141 {
142 perror(tmpdir);
143 exit(1);
144 }
145
146 if ( Debug && errno )
147 printf("mkdir of %s returned %d %s\n",
148 tmpdir, errno, strerror(errno));
149
150 subdir = parsefs(dir, error);
151 if (subdir == NULL)
152 {
153 exit(1);
154 }
155 time_now = time((long *) 0);
156 if (mount_nfs(dir, tmpdir, error))
157 {
158 exit(1);
159 }
160 strcpy(dirbuf, tmpdir);
161 strcat(dirbuf, "/");
162 strcat(dirbuf, subdir);
163 status = runcmd(dirbuf, argv[2], &argv[2]);
164 if (umount_nfs(dir, tmpdir))
165 fprintf(stderr, "under: couldn't umount %s\n", dir);
166 rmdir(tmpdir);
167 exit(status);
168 }
169
170 setgid(getgid());
171 setuid(getuid());
172 if (chdir(dir))
173 {
174 perror(dir);
175 exit(1);
176 }
177 execvp(argv[2], &argv[2]);
178 perror(argv[2]);
179 exit(1);
180 /* NOTREACHED */
181 }
182
183 typedef void (*sig_t)();
184
185 int
runcmd(dir,cmd,args)186 runcmd(dir, cmd, args)
187 char *dir;
188 char *cmd;
189 char **args;
190 {
191 int pid, child, status;
192 sig_t sigint, sigquit;
193
194 sigint = sigset(SIGINT, SIG_IGN);
195 sigquit = sigset(SIGQUIT, SIG_IGN);
196 pid = fork();
197 if (pid == -1)
198 return (0177);
199 if (pid == 0)
200 {
201 setgid(getgid());
202 setuid(getuid());
203 if (chdir(dir))
204 {
205 perror(dir);
206 exit(1);
207 }
208 (void) sigset(SIGINT, sigint);
209 (void) sigset(SIGQUIT, sigquit);
210 execvp(cmd, args);
211 perror(cmd);
212 exit(1);
213 }
214 while ((child = wait(&status)) != pid && child != -1)
215 ;
216 (void) sigset(SIGINT, sigint);
217 (void) sigset(SIGQUIT, sigquit);
218 if (child == -1)
219 return (0177);
220 if (status & 0377)
221 return (status & 0377);
222 return ((status >> 8) & 0377);
223 }
224