xref: /csrg-svn/bin/rcp/rcp.c (revision 6440)
1*6440Swnj #ifndef lint
2*6440Swnj static char sccsid[] = "@(#)rcp.c	4.1 82/04/02";
3*6440Swnj #endif
4*6440Swnj 
5*6440Swnj #include <stdio.h>
6*6440Swnj #include <signal.h>
7*6440Swnj #include <sys/types.h>
8*6440Swnj #include <sys/stat.h>
9*6440Swnj #include <sys/ioctl.h>
10*6440Swnj #include <net/in.h>
11*6440Swnj #include <pwd.h>
12*6440Swnj #include <ctype.h>
13*6440Swnj #include <errno.h>
14*6440Swnj /*
15*6440Swnj  * rcp
16*6440Swnj  */
17*6440Swnj int	rem;
18*6440Swnj char	*colon(), *index(), *rindex(), *malloc(), *strcpy(), *sprintf();
19*6440Swnj int	errs;
20*6440Swnj int	lostconn();
21*6440Swnj int	iamremote;
22*6440Swnj 
23*6440Swnj int	errno;
24*6440Swnj char	*sys_errlist[];
25*6440Swnj int	iamremote, targetshouldbedirectory;
26*6440Swnj int	iamrecursive;
27*6440Swnj struct	passwd *pwd;
28*6440Swnj struct	passwd *getpwuid();
29*6440Swnj 
30*6440Swnj /*VARARGS*/
31*6440Swnj int	error();
32*6440Swnj 
33*6440Swnj #define	ga()	 	(void) write(rem, "", 1)
34*6440Swnj 
35*6440Swnj main(argc, argv)
36*6440Swnj 	int argc;
37*6440Swnj 	char **argv;
38*6440Swnj {
39*6440Swnj 	char *targ, *host, *src;
40*6440Swnj 	char *suser, *tuser;
41*6440Swnj 	int i;
42*6440Swnj 	char buf[BUFSIZ], cmd[16];
43*6440Swnj 
44*6440Swnj 	setpwent();
45*6440Swnj 	pwd = getpwuid(getuid());
46*6440Swnj 	endpwent();
47*6440Swnj 	if (pwd == 0) {
48*6440Swnj 		fprintf(stderr, "who are you?\n");
49*6440Swnj 		exit(1);
50*6440Swnj 	}
51*6440Swnj 	argc--, argv++;
52*6440Swnj 	if (argc > 0 && !strcmp(*argv, "-r")) {
53*6440Swnj 		iamrecursive++;
54*6440Swnj 		argc--, argv++;
55*6440Swnj 	}
56*6440Swnj 	if (argc > 0 && !strcmp(*argv, "-d")) {
57*6440Swnj 		targetshouldbedirectory = 1;
58*6440Swnj 		argc--, argv++;
59*6440Swnj 	}
60*6440Swnj 	if (argc > 0 && !strcmp(*argv, "-f")) {
61*6440Swnj 		argc--, argv++; iamremote = 1;
62*6440Swnj 		(void) response();
63*6440Swnj 		(void) setuid(getuid());
64*6440Swnj 		source(argc, argv);
65*6440Swnj 		exit(errs);
66*6440Swnj 	}
67*6440Swnj 	if (argc > 0 && !strcmp(*argv, "-t")) {
68*6440Swnj 		argc--, argv++; iamremote = 1;
69*6440Swnj 		(void) setuid(getuid());
70*6440Swnj 		sink(argc, argv);
71*6440Swnj 		exit(errs);
72*6440Swnj 	}
73*6440Swnj 	rem = -1;
74*6440Swnj 	if (argc > 2)
75*6440Swnj 		targetshouldbedirectory = 1;
76*6440Swnj 	(void) sprintf(cmd, "rcp%s%s",
77*6440Swnj 	    iamrecursive ? " -r" : "", targetshouldbedirectory ? " -d" : "");
78*6440Swnj 	sigsys(SIGPIPE, lostconn);
79*6440Swnj 	targ = colon(argv[argc - 1]);
80*6440Swnj 	if (targ) {
81*6440Swnj 		*targ++ = 0;
82*6440Swnj 		tuser = rindex(argv[argc - 1], '.');
83*6440Swnj 		if (tuser) {
84*6440Swnj 			*tuser++ = 0;
85*6440Swnj 			if (!okname(tuser))
86*6440Swnj 				exit(1);
87*6440Swnj 		} else
88*6440Swnj 			tuser = pwd->pw_name;
89*6440Swnj 		for (i = 0; i < argc - 1; i++) {
90*6440Swnj 			src = colon(argv[i]);
91*6440Swnj 			if (src) {
92*6440Swnj 				*src++ = 0;
93*6440Swnj 				suser = rindex(argv[i], '.');
94*6440Swnj 				if (suser) {
95*6440Swnj 					*suser++ = 0;
96*6440Swnj 					if (!okname(suser))
97*6440Swnj 						continue;
98*6440Swnj 		(void) sprintf(buf, "rsh %s -l %s %s %s '%s:%s' </dev/null",
99*6440Swnj 					    argv[i], suser, cmd,
100*6440Swnj 					    src, argv[argc - 1], targ);
101*6440Swnj 				} else
102*6440Swnj 		(void) sprintf(buf, "rsh %s %s %s '%s:%s' </dev/null",
103*6440Swnj 					    argv[i], cmd,
104*6440Swnj 					    src, argv[argc - 1], targ);
105*6440Swnj 				(void) susystem(buf);
106*6440Swnj 			} else {
107*6440Swnj 				if (rem == -1) {
108*6440Swnj 					(void) sprintf(buf, "%s -t %s",
109*6440Swnj 					    cmd, targ);
110*6440Swnj 					host = argv[argc - 1];
111*6440Swnj 					rem = rcmd(&host, IPPORT_CMDSERVER,
112*6440Swnj 					    pwd->pw_name, tuser,
113*6440Swnj 					    buf, 0);
114*6440Swnj 					if (rem < 0)
115*6440Swnj 						exit(1);
116*6440Swnj 					if (response() < 0)
117*6440Swnj 						exit(1);
118*6440Swnj 				}
119*6440Swnj 				source(1, argv+i);
120*6440Swnj 			}
121*6440Swnj 		}
122*6440Swnj 	} else {
123*6440Swnj 		if (targetshouldbedirectory)
124*6440Swnj 			verifydir(argv[argc - 1]);
125*6440Swnj 		for (i = 0; i < argc - 1; i++) {
126*6440Swnj 			src = colon(argv[i]);
127*6440Swnj 			if (src == 0) {
128*6440Swnj 				(void) sprintf(buf, "/bin/cp%s %s %s",
129*6440Swnj 				    iamrecursive ? " -r" : "",
130*6440Swnj 				    argv[i], argv[argc - 1]);
131*6440Swnj 				(void) susystem(buf);
132*6440Swnj 			} else {
133*6440Swnj 				*src++ = 0;
134*6440Swnj 				suser = rindex(argv[i], '.');
135*6440Swnj 				if (suser) {
136*6440Swnj 					*suser++ = 0;
137*6440Swnj 					if (!okname(suser))
138*6440Swnj 						continue;
139*6440Swnj 				} else
140*6440Swnj 					suser = pwd->pw_name;
141*6440Swnj 				(void) sprintf(buf, "%s -f %s", cmd, src);
142*6440Swnj 				host = argv[i];
143*6440Swnj 				rem = rcmd(&host, IPPORT_CMDSERVER,
144*6440Swnj 				    pwd->pw_name, suser,
145*6440Swnj 				    buf, 0);
146*6440Swnj 				if (rem < 0)
147*6440Swnj 					exit(1);
148*6440Swnj 				sink(1, argv+argc-1);
149*6440Swnj 				(void) close(rem);
150*6440Swnj 				rem = -1;
151*6440Swnj 			}
152*6440Swnj 		}
153*6440Swnj 	}
154*6440Swnj 	exit(errs);
155*6440Swnj }
156*6440Swnj 
157*6440Swnj verifydir(cp)
158*6440Swnj 	char *cp;
159*6440Swnj {
160*6440Swnj 	struct stat stb;
161*6440Swnj 
162*6440Swnj 	if (stat(cp, &stb) < 0)
163*6440Swnj 		goto bad;
164*6440Swnj 	if ((stb.st_mode & S_IFMT) == S_IFDIR)
165*6440Swnj 		return;
166*6440Swnj 	errno = ENOTDIR;
167*6440Swnj bad:
168*6440Swnj 	error("rcp: %s: %s.\n", cp, sys_errlist[errno]);
169*6440Swnj 	exit(1);
170*6440Swnj }
171*6440Swnj 
172*6440Swnj char *
173*6440Swnj colon(cp)
174*6440Swnj 	char *cp;
175*6440Swnj {
176*6440Swnj 
177*6440Swnj 	while (*cp) {
178*6440Swnj 		if (*cp == ':')
179*6440Swnj 			return (cp);
180*6440Swnj 		if (*cp == '/')
181*6440Swnj 			return (0);
182*6440Swnj 		cp++;
183*6440Swnj 	}
184*6440Swnj 	return (0);
185*6440Swnj }
186*6440Swnj 
187*6440Swnj okname(cp0)
188*6440Swnj 	char *cp0;
189*6440Swnj {
190*6440Swnj 	register char *cp = cp0;
191*6440Swnj 	register int c;
192*6440Swnj 
193*6440Swnj 	do {
194*6440Swnj 		c = *cp;
195*6440Swnj 		if (c & 0200)
196*6440Swnj 			goto bad;
197*6440Swnj 		if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
198*6440Swnj 			goto bad;
199*6440Swnj 		cp++;
200*6440Swnj 	} while (*cp);
201*6440Swnj 	return (1);
202*6440Swnj bad:
203*6440Swnj 	fprintf(stderr, "rcp: invalid user name %s\n", cp0);
204*6440Swnj 	return (0);
205*6440Swnj }
206*6440Swnj 
207*6440Swnj susystem(buf)
208*6440Swnj 	char *buf;
209*6440Swnj {
210*6440Swnj 
211*6440Swnj 	if (fork() == 0) {
212*6440Swnj 		(void) setuid(getuid());
213*6440Swnj 		(void) system(buf);
214*6440Swnj 		_exit(0);
215*6440Swnj 	} else
216*6440Swnj 		(void) wait((int *)0);
217*6440Swnj }
218*6440Swnj 
219*6440Swnj source(argc, argv)
220*6440Swnj 	int argc;
221*6440Swnj 	char **argv;
222*6440Swnj {
223*6440Swnj 	char *last, *name;
224*6440Swnj 	struct stat stb;
225*6440Swnj 	char buf[BUFSIZ];
226*6440Swnj 	int x, sizerr, f, i;
227*6440Swnj 
228*6440Swnj 	for (x = 0; x < argc; x++) {
229*6440Swnj 		name = argv[x];
230*6440Swnj 		if (access(name, 4) < 0 || (f = open(name, 0)) < 0) {
231*6440Swnj 			error("rcp: %s: %s\n", name, sys_errlist[errno]);
232*6440Swnj 			continue;
233*6440Swnj 		}
234*6440Swnj 		if (fstat(f, &stb) < 0)
235*6440Swnj 			goto notreg;
236*6440Swnj 		switch (stb.st_mode&S_IFMT) {
237*6440Swnj 
238*6440Swnj 		case S_IFREG:
239*6440Swnj 			break;
240*6440Swnj 
241*6440Swnj 		case S_IFDIR:
242*6440Swnj 			if (iamrecursive) {
243*6440Swnj 				(void) close(f);
244*6440Swnj 				rsource(name, (int)stb.st_mode);
245*6440Swnj 				continue;
246*6440Swnj 			}
247*6440Swnj 			/* fall into ... */
248*6440Swnj 		default:
249*6440Swnj notreg:
250*6440Swnj 			(void) close(f);
251*6440Swnj 			error("rcp: %s: not a plain file\n", name);
252*6440Swnj 			continue;
253*6440Swnj 		}
254*6440Swnj 		last = rindex(name, '/');
255*6440Swnj 		if (last == 0)
256*6440Swnj 			last = name;
257*6440Swnj 		else
258*6440Swnj 			last++;
259*6440Swnj 		(void) sprintf(buf, "C%04o %d %s\n",
260*6440Swnj 		    stb.st_mode&07777, stb.st_size, last);
261*6440Swnj 		(void) write(rem, buf, strlen(buf));
262*6440Swnj 		if (response() < 0) {
263*6440Swnj 			(void) close(f);
264*6440Swnj 			continue;
265*6440Swnj 		}
266*6440Swnj 		sizerr = 0;
267*6440Swnj 		for (i = 0; i < stb.st_size; i += BUFSIZ) {
268*6440Swnj 			int amt = BUFSIZ;
269*6440Swnj 			if (i + amt > stb.st_size)
270*6440Swnj 				amt = stb.st_size - i;
271*6440Swnj 			if (sizerr == 0 && read(f, buf, amt) != amt)
272*6440Swnj 				sizerr = 1;
273*6440Swnj 			(void) write(rem, buf, amt);
274*6440Swnj 		}
275*6440Swnj 		(void) close(f);
276*6440Swnj 		if (sizerr == 0)
277*6440Swnj 			ga();
278*6440Swnj 		else
279*6440Swnj 			error("rcp: %s: file changed size\n", name);
280*6440Swnj 		(void) response();
281*6440Swnj 	}
282*6440Swnj }
283*6440Swnj 
284*6440Swnj #include <ndir.h>
285*6440Swnj 
286*6440Swnj rsource(name, mode)
287*6440Swnj 	char *name;
288*6440Swnj 	int mode;
289*6440Swnj {
290*6440Swnj 	DIR *d = opendir(name);
291*6440Swnj 	char *last;
292*6440Swnj 	struct direct *dp;
293*6440Swnj 	char buf[BUFSIZ];
294*6440Swnj 	char *bufv[1];
295*6440Swnj 
296*6440Swnj 	if (d == 0) {
297*6440Swnj 		error("%s: %s\n", name, sys_errlist[errno]);
298*6440Swnj 		return;
299*6440Swnj 	}
300*6440Swnj 	last = rindex(name, '/');
301*6440Swnj 	if (last == 0)
302*6440Swnj 		last = name;
303*6440Swnj 	else
304*6440Swnj 		last++;
305*6440Swnj 	(void) sprintf(buf, "D%04o %d %s\n", mode&07777, 0, last);
306*6440Swnj 	(void) write(rem, buf, strlen(buf));
307*6440Swnj 	if (response() < 0) {
308*6440Swnj 		closedir(d);
309*6440Swnj 		return;
310*6440Swnj 	}
311*6440Swnj 	while (dp = readdir(d)) {
312*6440Swnj 		if (dp->d_ino == 0)
313*6440Swnj 			continue;
314*6440Swnj 		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
315*6440Swnj 			continue;
316*6440Swnj 		if (strlen(name) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
317*6440Swnj 			error("%s/%s: Name too long.\n", name, dp->d_name);
318*6440Swnj 			continue;
319*6440Swnj 		}
320*6440Swnj 		(void) sprintf(buf, "%s/%s", name, dp->d_name);
321*6440Swnj 		bufv[0] = buf;
322*6440Swnj 		source(1, bufv);
323*6440Swnj 	}
324*6440Swnj 	closedir(d);
325*6440Swnj 	(void) write(rem, "E\n", 2);
326*6440Swnj 	(void) response();
327*6440Swnj }
328*6440Swnj 
329*6440Swnj response()
330*6440Swnj {
331*6440Swnj 	char resp, c, rbuf[BUFSIZ], *cp = rbuf;
332*6440Swnj 
333*6440Swnj 	if (read(rem, &resp, 1) != 1)
334*6440Swnj 		lostconn();
335*6440Swnj 	switch (resp) {
336*6440Swnj 
337*6440Swnj 	case 0:
338*6440Swnj 		return (0);
339*6440Swnj 
340*6440Swnj 	default:
341*6440Swnj 		*cp++ = resp;
342*6440Swnj 		/* fall into... */
343*6440Swnj 	case 1:
344*6440Swnj 	case 2:
345*6440Swnj 		do {
346*6440Swnj 			if (read(rem, &c, 1) != 1)
347*6440Swnj 				lostconn();
348*6440Swnj 			*cp++ = c;
349*6440Swnj 		} while (cp < &rbuf[BUFSIZ] && c != '\n');
350*6440Swnj 		if (iamremote == 0)
351*6440Swnj 			(void) write(2, rbuf, cp - rbuf);
352*6440Swnj 		errs++;
353*6440Swnj 		if (resp == 1)
354*6440Swnj 			return (-1);
355*6440Swnj 		exit(1);
356*6440Swnj 	}
357*6440Swnj 	/*NOTREACHED*/
358*6440Swnj }
359*6440Swnj 
360*6440Swnj lostconn()
361*6440Swnj {
362*6440Swnj 
363*6440Swnj 	if (iamremote == 0)
364*6440Swnj 		fprintf(stderr, "rcp: lost connection\n");
365*6440Swnj 	exit(1);
366*6440Swnj }
367*6440Swnj 
368*6440Swnj sink(argc, argv)
369*6440Swnj 	int argc;
370*6440Swnj 	char **argv;
371*6440Swnj {
372*6440Swnj 	char *targ;
373*6440Swnj 	char cmdbuf[BUFSIZ], nambuf[BUFSIZ], buf[BUFSIZ], *cp;
374*6440Swnj 	int of, mode, i, size, wrerr, exists;
375*6440Swnj 	char *whopp;
376*6440Swnj 	struct stat stb; int targisdir = 0;
377*6440Swnj #define	SCREWUP(str)	{ whopp = str; goto screwup; }
378*6440Swnj 	int mask = umask(0);
379*6440Swnj 	char *myargv[1];
380*6440Swnj 
381*6440Swnj 	umask(mask);
382*6440Swnj 	if (argc > 1) {
383*6440Swnj 		error("rcp: ambiguous target\n");
384*6440Swnj 		exit(1);
385*6440Swnj 	}
386*6440Swnj 	targ = *argv;
387*6440Swnj 	if (targetshouldbedirectory)
388*6440Swnj 		verifydir(targ);
389*6440Swnj 	ga();
390*6440Swnj 	if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR)
391*6440Swnj 		targisdir = 1;
392*6440Swnj 	for (;;) {
393*6440Swnj 		cp = cmdbuf;
394*6440Swnj 		if (read(rem, cp, 1) <= 0)
395*6440Swnj 			return;
396*6440Swnj 		if (*cp++ == '\n')
397*6440Swnj 			SCREWUP("unexpected '\\n'");
398*6440Swnj 		do {
399*6440Swnj 			if (read(rem, cp, 1) != 1)
400*6440Swnj 				SCREWUP("lost connection");
401*6440Swnj 		} while (*cp++ != '\n');
402*6440Swnj 		*cp = 0;
403*6440Swnj 		if (cmdbuf[0] == '\01' || cmdbuf[0] == '\02') {
404*6440Swnj 			if (iamremote == 0)
405*6440Swnj 				(void) write(2, cmdbuf, strlen(cmdbuf));
406*6440Swnj 			if (cmdbuf[0] == '\02')
407*6440Swnj 				exit(1);
408*6440Swnj 			errs++;
409*6440Swnj 			continue;
410*6440Swnj 		}
411*6440Swnj 		*--cp = 0;
412*6440Swnj 		cp = cmdbuf;
413*6440Swnj 		if (*cp == 'E') {
414*6440Swnj 			ga();
415*6440Swnj 			return;
416*6440Swnj 		}
417*6440Swnj 		if (*cp != 'C' && *cp != 'D')
418*6440Swnj 			SCREWUP("expected control record");
419*6440Swnj 		cp++;
420*6440Swnj 		mode = 0;
421*6440Swnj 		for (; cp < cmdbuf+5; cp++) {
422*6440Swnj 			if (*cp < '0' || *cp > '7')
423*6440Swnj 				SCREWUP("bad mode");
424*6440Swnj 			mode = (mode << 3) | (*cp - '0');
425*6440Swnj 		}
426*6440Swnj 		if (*cp++ != ' ')
427*6440Swnj 			SCREWUP("mode not delimited");
428*6440Swnj 		size = 0;
429*6440Swnj 		while (*cp >= '0' && *cp <= '9')
430*6440Swnj 			size = size * 10 + (*cp++ - '0');
431*6440Swnj 		if (*cp++ != ' ')
432*6440Swnj 			SCREWUP("size not delimited");
433*6440Swnj 		if (targisdir)
434*6440Swnj 			(void) sprintf(nambuf, "%s%s%s", targ,
435*6440Swnj 			    *targ ? "/" : "", cp);
436*6440Swnj 		else
437*6440Swnj 			(void) strcpy(nambuf, targ);
438*6440Swnj 		exists = stat(nambuf, &stb) == 0;
439*6440Swnj 		if (exists && access(nambuf, 2) < 0)
440*6440Swnj 			goto bad2;
441*6440Swnj 		{ char *slash = rindex(nambuf, '/'), *dir;
442*6440Swnj 		  if (slash == 0) {
443*6440Swnj 			slash = "/";
444*6440Swnj 			dir = ".";
445*6440Swnj 		  } else {
446*6440Swnj 			*slash = 0;
447*6440Swnj 			dir = nambuf;
448*6440Swnj 		  }
449*6440Swnj 		  if (exists == 0 && access(dir, 2) < 0)
450*6440Swnj 			goto bad;
451*6440Swnj 		  *slash = '/';
452*6440Swnj 		  if (cmdbuf[0] == 'D') {
453*6440Swnj 			if (stat(nambuf, &stb) == 0) {
454*6440Swnj 				if ((stb.st_mode&S_IFMT) != S_IFDIR) {
455*6440Swnj 					errno = ENOTDIR;
456*6440Swnj 					goto bad;
457*6440Swnj 				}
458*6440Swnj 			} else if (mkdir(nambuf, mode) < 0)
459*6440Swnj 				goto bad;
460*6440Swnj 			myargv[0] = nambuf;
461*6440Swnj 			sink(1, myargv);
462*6440Swnj 			continue;
463*6440Swnj 		  }
464*6440Swnj 		  if ((of = creat(nambuf, mode)) < 0) {
465*6440Swnj 	bad:
466*6440Swnj 			*slash = '/';
467*6440Swnj 	bad2:
468*6440Swnj 			error("rcp: %s: %s\n", nambuf, sys_errlist[errno]);
469*6440Swnj 			continue;
470*6440Swnj 		  }
471*6440Swnj 		}
472*6440Swnj 		if (exists == 0) {
473*6440Swnj 			(void) stat(nambuf, &stb);
474*6440Swnj 			(void) chown(nambuf, pwd->pw_uid, stb.st_gid);
475*6440Swnj 			(void) chmod(nambuf, mode &~ mask);
476*6440Swnj 		}
477*6440Swnj 		ga();
478*6440Swnj 		wrerr = 0;
479*6440Swnj 		for (i = 0; i < size; i += BUFSIZ) {
480*6440Swnj 			int amt = BUFSIZ;
481*6440Swnj 			char *cp = buf;
482*6440Swnj 
483*6440Swnj 			if (i + amt > size)
484*6440Swnj 				amt = size - i;
485*6440Swnj 			do {
486*6440Swnj 				int j = read(rem, cp, amt);
487*6440Swnj 
488*6440Swnj 				if (j <= 0)
489*6440Swnj 					exit(1);
490*6440Swnj 				amt -= j;
491*6440Swnj 				cp += j;
492*6440Swnj 			} while (amt > 0);
493*6440Swnj 			amt = BUFSIZ;
494*6440Swnj 			if (i + amt > size)
495*6440Swnj 				amt = size - i;
496*6440Swnj 			if (wrerr == 0 && write(of, buf, amt) != amt)
497*6440Swnj 				wrerr++;
498*6440Swnj 		}
499*6440Swnj 		(void) close(of);
500*6440Swnj 		(void) response();
501*6440Swnj 		if (wrerr)
502*6440Swnj 			error("rcp: %s: %s\n", cp, sys_errlist[errno]);
503*6440Swnj 		else
504*6440Swnj 			ga();
505*6440Swnj 	}
506*6440Swnj screwup:
507*6440Swnj 	error("rcp: protocol screwup: %s\n", whopp);
508*6440Swnj 	exit(1);
509*6440Swnj }
510*6440Swnj 
511*6440Swnj /*VARARGS*/
512*6440Swnj error(fmt, a1, a2, a3, a4, a5)
513*6440Swnj 	char *fmt;
514*6440Swnj 	int a1, a2, a3, a4, a5;
515*6440Swnj {
516*6440Swnj 	char buf[BUFSIZ], *cp = buf;
517*6440Swnj 
518*6440Swnj 	errs++;
519*6440Swnj 	*cp++ = 1;
520*6440Swnj 	(void) sprintf(cp, fmt, a1, a2, a3, a4, a5);
521*6440Swnj 	(void) write(rem, buf, strlen(buf));
522*6440Swnj 	if (iamremote == 0)
523*6440Swnj 		(void) write(2, buf+1, strlen(buf+1));
524*6440Swnj }
525*6440Swnj 
526*6440Swnj mkdir(name, mode)
527*6440Swnj 	char *name;
528*6440Swnj 	int mode;
529*6440Swnj {
530*6440Swnj 	char *argv[4];
531*6440Swnj 	int pid, rc;
532*6440Swnj 
533*6440Swnj 	argv[0] = "mkdir";
534*6440Swnj 	argv[1] = name;
535*6440Swnj 	argv[2] = 0;
536*6440Swnj 	pid = fork();
537*6440Swnj 	if (pid < 0) {
538*6440Swnj 		perror("cp");
539*6440Swnj 		return (1);
540*6440Swnj 	}
541*6440Swnj 	if (pid) {
542*6440Swnj 		while (wait(&rc) != pid)
543*6440Swnj 			continue;
544*6440Swnj 		if (rc == 0)
545*6440Swnj 			if (chmod(name, mode) < 0) {
546*6440Swnj 				perror(name);
547*6440Swnj 				rc = 1;
548*6440Swnj 			}
549*6440Swnj 		return (rc);
550*6440Swnj 	}
551*6440Swnj 	(void) setuid(getuid());
552*6440Swnj 	execv("/bin/mkdir", argv);
553*6440Swnj 	execv("/usr/bin/mkdir", argv);
554*6440Swnj 	perror("mkdir");
555*6440Swnj 	_exit(1);
556*6440Swnj 	/*NOTREACHED*/
557*6440Swnj }
558