xref: /csrg-svn/bin/rcp/rcp.c (revision 18026)
16440Swnj #ifndef lint
2*18026Sralph static char sccsid[] = "@(#)rcp.c	4.12 85/02/20";
36440Swnj #endif
46440Swnj 
512989Ssam /*
612989Ssam  * rcp
712989Ssam  */
86720Smckusick #include <sys/param.h>
96440Swnj #include <sys/stat.h>
106440Swnj #include <sys/ioctl.h>
119199Ssam 
129199Ssam #include <netinet/in.h>
139199Ssam 
149199Ssam #include <stdio.h>
159199Ssam #include <signal.h>
166440Swnj #include <pwd.h>
176440Swnj #include <ctype.h>
18*18026Sralph #include <netdb.h>
196440Swnj #include <errno.h>
2012989Ssam 
216440Swnj int	rem;
226440Swnj char	*colon(), *index(), *rindex(), *malloc(), *strcpy(), *sprintf();
236440Swnj int	errs;
246440Swnj int	lostconn();
256440Swnj int	iamremote;
266440Swnj 
276440Swnj int	errno;
286440Swnj char	*sys_errlist[];
296440Swnj int	iamremote, targetshouldbedirectory;
306440Swnj int	iamrecursive;
316440Swnj struct	passwd *pwd;
326440Swnj struct	passwd *getpwuid();
33*18026Sralph struct	servent *sp;
346440Swnj 
356440Swnj /*VARARGS*/
366440Swnj int	error();
376440Swnj 
386440Swnj #define	ga()	 	(void) write(rem, "", 1)
396440Swnj 
406440Swnj main(argc, argv)
416440Swnj 	int argc;
426440Swnj 	char **argv;
436440Swnj {
446440Swnj 	char *targ, *host, *src;
456440Swnj 	char *suser, *tuser;
466440Swnj 	int i;
476440Swnj 	char buf[BUFSIZ], cmd[16];
48*18026Sralph 
49*18026Sralph 	sp = getservbyname("shell", "tcp");
50*18026Sralph 	if (sp == NULL) {
51*18026Sralph 		fprintf(stderr, "rcp: shell/tcp: unknown service\n");
52*18026Sralph 		exit(1);
53*18026Sralph 	}
546440Swnj 	setpwent();
556440Swnj 	pwd = getpwuid(getuid());
566440Swnj 	endpwent();
576440Swnj 	if (pwd == 0) {
586440Swnj 		fprintf(stderr, "who are you?\n");
596440Swnj 		exit(1);
606440Swnj 	}
616440Swnj 	argc--, argv++;
626440Swnj 	if (argc > 0 && !strcmp(*argv, "-r")) {
636440Swnj 		iamrecursive++;
646440Swnj 		argc--, argv++;
656440Swnj 	}
666440Swnj 	if (argc > 0 && !strcmp(*argv, "-d")) {
676440Swnj 		targetshouldbedirectory = 1;
686440Swnj 		argc--, argv++;
696440Swnj 	}
706440Swnj 	if (argc > 0 && !strcmp(*argv, "-f")) {
716440Swnj 		argc--, argv++; iamremote = 1;
726440Swnj 		(void) response();
736440Swnj 		(void) setuid(getuid());
746440Swnj 		source(argc, argv);
756440Swnj 		exit(errs);
766440Swnj 	}
776440Swnj 	if (argc > 0 && !strcmp(*argv, "-t")) {
786440Swnj 		argc--, argv++; iamremote = 1;
796440Swnj 		(void) setuid(getuid());
806440Swnj 		sink(argc, argv);
816440Swnj 		exit(errs);
826440Swnj 	}
836440Swnj 	rem = -1;
846440Swnj 	if (argc > 2)
856440Swnj 		targetshouldbedirectory = 1;
866440Swnj 	(void) sprintf(cmd, "rcp%s%s",
876440Swnj 	    iamrecursive ? " -r" : "", targetshouldbedirectory ? " -d" : "");
8812989Ssam 	signal(SIGPIPE, lostconn);
896440Swnj 	targ = colon(argv[argc - 1]);
906440Swnj 	if (targ) {
916440Swnj 		*targ++ = 0;
9213542Ssam 		if (*targ == 0)
9313542Ssam 			targ = ".";
946440Swnj 		tuser = rindex(argv[argc - 1], '.');
956440Swnj 		if (tuser) {
966440Swnj 			*tuser++ = 0;
976440Swnj 			if (!okname(tuser))
986440Swnj 				exit(1);
996440Swnj 		} else
1006440Swnj 			tuser = pwd->pw_name;
1016440Swnj 		for (i = 0; i < argc - 1; i++) {
1026440Swnj 			src = colon(argv[i]);
1036440Swnj 			if (src) {
1046440Swnj 				*src++ = 0;
10513542Ssam 				if (*src == 0)
10613738Ssam 					src = ".";
1076440Swnj 				suser = rindex(argv[i], '.');
1086440Swnj 				if (suser) {
1096440Swnj 					*suser++ = 0;
1106440Swnj 					if (!okname(suser))
1116440Swnj 						continue;
11215898Sralph 		(void) sprintf(buf, "rsh %s -l %s -n %s %s '%s.%s:%s'",
11315898Sralph 					    argv[i], suser, cmd, src,
11415898Sralph 					    argv[argc - 1], tuser, targ);
1156440Swnj 				} else
11615898Sralph 		(void) sprintf(buf, "rsh %s -n %s %s '%s.%s:%s'",
11715898Sralph 					    argv[i], cmd, src,
11815898Sralph 					    argv[argc - 1], tuser, targ);
1196440Swnj 				(void) susystem(buf);
1206440Swnj 			} else {
1216440Swnj 				if (rem == -1) {
1226440Swnj 					(void) sprintf(buf, "%s -t %s",
1236440Swnj 					    cmd, targ);
1246440Swnj 					host = argv[argc - 1];
125*18026Sralph 					rem = rcmd(&host, sp->s_port,
1266440Swnj 					    pwd->pw_name, tuser,
1276440Swnj 					    buf, 0);
1286440Swnj 					if (rem < 0)
1296440Swnj 						exit(1);
1306440Swnj 					if (response() < 0)
1316440Swnj 						exit(1);
1326440Swnj 				}
1336440Swnj 				source(1, argv+i);
1346440Swnj 			}
1356440Swnj 		}
1366440Swnj 	} else {
1376440Swnj 		if (targetshouldbedirectory)
1386440Swnj 			verifydir(argv[argc - 1]);
1396440Swnj 		for (i = 0; i < argc - 1; i++) {
1406440Swnj 			src = colon(argv[i]);
1416440Swnj 			if (src == 0) {
1426440Swnj 				(void) sprintf(buf, "/bin/cp%s %s %s",
1436440Swnj 				    iamrecursive ? " -r" : "",
1446440Swnj 				    argv[i], argv[argc - 1]);
1456440Swnj 				(void) susystem(buf);
1466440Swnj 			} else {
1476440Swnj 				*src++ = 0;
14813542Ssam 				if (*src == 0)
14913542Ssam 					src = ".";
1506440Swnj 				suser = rindex(argv[i], '.');
1516440Swnj 				if (suser) {
1526440Swnj 					*suser++ = 0;
1536440Swnj 					if (!okname(suser))
1546440Swnj 						continue;
1556440Swnj 				} else
1566440Swnj 					suser = pwd->pw_name;
1576440Swnj 				(void) sprintf(buf, "%s -f %s", cmd, src);
1586440Swnj 				host = argv[i];
159*18026Sralph 				rem = rcmd(&host, sp->s_port,
1606440Swnj 				    pwd->pw_name, suser,
1616440Swnj 				    buf, 0);
1626440Swnj 				if (rem < 0)
1636440Swnj 					exit(1);
1646440Swnj 				sink(1, argv+argc-1);
1656440Swnj 				(void) close(rem);
1666440Swnj 				rem = -1;
1676440Swnj 			}
1686440Swnj 		}
1696440Swnj 	}
1706440Swnj 	exit(errs);
1716440Swnj }
1726440Swnj 
1736440Swnj verifydir(cp)
1746440Swnj 	char *cp;
1756440Swnj {
1766440Swnj 	struct stat stb;
1776440Swnj 
1786440Swnj 	if (stat(cp, &stb) < 0)
1796440Swnj 		goto bad;
1806440Swnj 	if ((stb.st_mode & S_IFMT) == S_IFDIR)
1816440Swnj 		return;
1826440Swnj 	errno = ENOTDIR;
1836440Swnj bad:
1846440Swnj 	error("rcp: %s: %s.\n", cp, sys_errlist[errno]);
1856440Swnj 	exit(1);
1866440Swnj }
1876440Swnj 
1886440Swnj char *
1896440Swnj colon(cp)
1906440Swnj 	char *cp;
1916440Swnj {
1926440Swnj 
1936440Swnj 	while (*cp) {
1946440Swnj 		if (*cp == ':')
1956440Swnj 			return (cp);
1966440Swnj 		if (*cp == '/')
1976440Swnj 			return (0);
1986440Swnj 		cp++;
1996440Swnj 	}
2006440Swnj 	return (0);
2016440Swnj }
2026440Swnj 
2036440Swnj okname(cp0)
2046440Swnj 	char *cp0;
2056440Swnj {
2066440Swnj 	register char *cp = cp0;
2076440Swnj 	register int c;
2086440Swnj 
2096440Swnj 	do {
2106440Swnj 		c = *cp;
2116440Swnj 		if (c & 0200)
2126440Swnj 			goto bad;
2136440Swnj 		if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
2146440Swnj 			goto bad;
2156440Swnj 		cp++;
2166440Swnj 	} while (*cp);
2176440Swnj 	return (1);
2186440Swnj bad:
2196440Swnj 	fprintf(stderr, "rcp: invalid user name %s\n", cp0);
2206440Swnj 	return (0);
2216440Swnj }
2226440Swnj 
22317999Sserge susystem(s)
22417999Sserge 	char *s;
2256440Swnj {
22617999Sserge 	int status, pid, w;
22717999Sserge 	register int (*istat)(), (*qstat)();
2286440Swnj 
22917999Sserge 	if ((pid = vfork()) == 0) {
23017999Sserge 		setuid(getuid());
23117999Sserge 		execl("/bin/sh", "sh", "-c", s, (char *)0);
23217999Sserge 		_exit(127);
23317999Sserge 	}
23417999Sserge 	istat = signal(SIGINT, SIG_IGN);
23517999Sserge 	qstat = signal(SIGQUIT, SIG_IGN);
23617999Sserge 	while ((w = wait(&status)) != pid && w != -1)
23717999Sserge 		;
23817999Sserge 	if (w == -1)
23917999Sserge 		status = -1;
24017999Sserge 	signal(SIGINT, istat);
24117999Sserge 	signal(SIGQUIT, qstat);
24217999Sserge 	return (status);
2436440Swnj }
2446440Swnj 
2456440Swnj source(argc, argv)
2466440Swnj 	int argc;
2476440Swnj 	char **argv;
2486440Swnj {
2496440Swnj 	char *last, *name;
2506440Swnj 	struct stat stb;
2516440Swnj 	char buf[BUFSIZ];
2526623Smckusick 	int x, sizerr, f;
2536623Smckusick 	off_t i;
2546440Swnj 
2556440Swnj 	for (x = 0; x < argc; x++) {
2566440Swnj 		name = argv[x];
2576440Swnj 		if (access(name, 4) < 0 || (f = open(name, 0)) < 0) {
2586440Swnj 			error("rcp: %s: %s\n", name, sys_errlist[errno]);
2596440Swnj 			continue;
2606440Swnj 		}
2616440Swnj 		if (fstat(f, &stb) < 0)
2626440Swnj 			goto notreg;
2636440Swnj 		switch (stb.st_mode&S_IFMT) {
2646440Swnj 
2656440Swnj 		case S_IFREG:
2666440Swnj 			break;
2676440Swnj 
2686440Swnj 		case S_IFDIR:
2696440Swnj 			if (iamrecursive) {
2706440Swnj 				(void) close(f);
2716440Swnj 				rsource(name, (int)stb.st_mode);
2726440Swnj 				continue;
2736440Swnj 			}
2746440Swnj 			/* fall into ... */
2756440Swnj 		default:
2766440Swnj notreg:
2776440Swnj 			(void) close(f);
2786440Swnj 			error("rcp: %s: not a plain file\n", name);
2796440Swnj 			continue;
2806440Swnj 		}
2816440Swnj 		last = rindex(name, '/');
2826440Swnj 		if (last == 0)
2836440Swnj 			last = name;
2846440Swnj 		else
2856440Swnj 			last++;
2866623Smckusick 		(void) sprintf(buf, "C%04o %D %s\n",
2876440Swnj 		    stb.st_mode&07777, stb.st_size, last);
2886440Swnj 		(void) write(rem, buf, strlen(buf));
2896440Swnj 		if (response() < 0) {
2906440Swnj 			(void) close(f);
2916440Swnj 			continue;
2926440Swnj 		}
2936440Swnj 		sizerr = 0;
2946440Swnj 		for (i = 0; i < stb.st_size; i += BUFSIZ) {
2956440Swnj 			int amt = BUFSIZ;
2966440Swnj 			if (i + amt > stb.st_size)
2976440Swnj 				amt = stb.st_size - i;
2986440Swnj 			if (sizerr == 0 && read(f, buf, amt) != amt)
2996440Swnj 				sizerr = 1;
3006440Swnj 			(void) write(rem, buf, amt);
3016440Swnj 		}
3026440Swnj 		(void) close(f);
3036440Swnj 		if (sizerr == 0)
3046440Swnj 			ga();
3056440Swnj 		else
3066440Swnj 			error("rcp: %s: file changed size\n", name);
3076440Swnj 		(void) response();
3086440Swnj 	}
3096440Swnj }
3106440Swnj 
31113542Ssam #include <sys/dir.h>
3126440Swnj 
3136440Swnj rsource(name, mode)
3146440Swnj 	char *name;
3156440Swnj 	int mode;
3166440Swnj {
3176440Swnj 	DIR *d = opendir(name);
3186440Swnj 	char *last;
3196440Swnj 	struct direct *dp;
3206440Swnj 	char buf[BUFSIZ];
3216440Swnj 	char *bufv[1];
3226440Swnj 
3236440Swnj 	if (d == 0) {
3246440Swnj 		error("%s: %s\n", name, sys_errlist[errno]);
3256440Swnj 		return;
3266440Swnj 	}
3276440Swnj 	last = rindex(name, '/');
3286440Swnj 	if (last == 0)
3296440Swnj 		last = name;
3306440Swnj 	else
3316440Swnj 		last++;
3326440Swnj 	(void) sprintf(buf, "D%04o %d %s\n", mode&07777, 0, last);
3336440Swnj 	(void) write(rem, buf, strlen(buf));
3346440Swnj 	if (response() < 0) {
3356440Swnj 		closedir(d);
3366440Swnj 		return;
3376440Swnj 	}
3386440Swnj 	while (dp = readdir(d)) {
3396440Swnj 		if (dp->d_ino == 0)
3406440Swnj 			continue;
3416440Swnj 		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
3426440Swnj 			continue;
3436440Swnj 		if (strlen(name) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
3446440Swnj 			error("%s/%s: Name too long.\n", name, dp->d_name);
3456440Swnj 			continue;
3466440Swnj 		}
3476440Swnj 		(void) sprintf(buf, "%s/%s", name, dp->d_name);
3486440Swnj 		bufv[0] = buf;
3496440Swnj 		source(1, bufv);
3506440Swnj 	}
3516440Swnj 	closedir(d);
3526440Swnj 	(void) write(rem, "E\n", 2);
3536440Swnj 	(void) response();
3546440Swnj }
3556440Swnj 
3566440Swnj response()
3576440Swnj {
3586440Swnj 	char resp, c, rbuf[BUFSIZ], *cp = rbuf;
3596440Swnj 
3606440Swnj 	if (read(rem, &resp, 1) != 1)
3616440Swnj 		lostconn();
3626440Swnj 	switch (resp) {
3636440Swnj 
3646440Swnj 	case 0:
3656440Swnj 		return (0);
3666440Swnj 
3676440Swnj 	default:
3686440Swnj 		*cp++ = resp;
3696440Swnj 		/* fall into... */
3706440Swnj 	case 1:
3716440Swnj 	case 2:
3726440Swnj 		do {
3736440Swnj 			if (read(rem, &c, 1) != 1)
3746440Swnj 				lostconn();
3756440Swnj 			*cp++ = c;
3766440Swnj 		} while (cp < &rbuf[BUFSIZ] && c != '\n');
3776440Swnj 		if (iamremote == 0)
3786440Swnj 			(void) write(2, rbuf, cp - rbuf);
3796440Swnj 		errs++;
3806440Swnj 		if (resp == 1)
3816440Swnj 			return (-1);
3826440Swnj 		exit(1);
3836440Swnj 	}
3846440Swnj 	/*NOTREACHED*/
3856440Swnj }
3866440Swnj 
3876440Swnj lostconn()
3886440Swnj {
3896440Swnj 
3906440Swnj 	if (iamremote == 0)
3916440Swnj 		fprintf(stderr, "rcp: lost connection\n");
3926440Swnj 	exit(1);
3936440Swnj }
3946440Swnj 
3956440Swnj sink(argc, argv)
3966440Swnj 	int argc;
3976440Swnj 	char **argv;
3986440Swnj {
3996440Swnj 	char *targ;
4006440Swnj 	char cmdbuf[BUFSIZ], nambuf[BUFSIZ], buf[BUFSIZ], *cp;
40114580Sralph 	int of, mode, wrerr, exists, first;
4026623Smckusick 	off_t i, size;
4036440Swnj 	char *whopp;
4046440Swnj 	struct stat stb; int targisdir = 0;
4056440Swnj #define	SCREWUP(str)	{ whopp = str; goto screwup; }
4066440Swnj 	int mask = umask(0);
4076440Swnj 	char *myargv[1];
4086440Swnj 
4096440Swnj 	umask(mask);
4106440Swnj 	if (argc > 1) {
4116440Swnj 		error("rcp: ambiguous target\n");
4126440Swnj 		exit(1);
4136440Swnj 	}
4146440Swnj 	targ = *argv;
4156440Swnj 	if (targetshouldbedirectory)
4166440Swnj 		verifydir(targ);
4176440Swnj 	ga();
4186440Swnj 	if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR)
4196440Swnj 		targisdir = 1;
42014580Sralph 	for (first = 1; ; first = 0) {
4216440Swnj 		cp = cmdbuf;
4226440Swnj 		if (read(rem, cp, 1) <= 0)
4236440Swnj 			return;
4246440Swnj 		if (*cp++ == '\n')
4256440Swnj 			SCREWUP("unexpected '\\n'");
4266440Swnj 		do {
4276440Swnj 			if (read(rem, cp, 1) != 1)
4286440Swnj 				SCREWUP("lost connection");
4296440Swnj 		} while (*cp++ != '\n');
4306440Swnj 		*cp = 0;
4316440Swnj 		if (cmdbuf[0] == '\01' || cmdbuf[0] == '\02') {
4326440Swnj 			if (iamremote == 0)
43313542Ssam 				(void) write(2, cmdbuf+1, strlen(cmdbuf+1));
4346440Swnj 			if (cmdbuf[0] == '\02')
4356440Swnj 				exit(1);
4366440Swnj 			errs++;
4376440Swnj 			continue;
4386440Swnj 		}
4396440Swnj 		*--cp = 0;
4406440Swnj 		cp = cmdbuf;
4416440Swnj 		if (*cp == 'E') {
4426440Swnj 			ga();
4436440Swnj 			return;
4446440Swnj 		}
44514580Sralph 		if (*cp != 'C' && *cp != 'D') {
44614580Sralph 			/*
44714580Sralph 			 * Check for the case "rcp remote:foo\* local:bar".
44814580Sralph 			 * In this case, the line "No match." can be returned
44914580Sralph 			 * by the shell before the rcp command on the remote is
45014580Sralph 			 * executed so the ^Aerror_message convention isn't
45114580Sralph 			 * followed.
45214580Sralph 			 */
45314580Sralph 			if (first) {
45414580Sralph 				error("%s\n", cp);
45514580Sralph 				exit(1);
45614580Sralph 			}
4576440Swnj 			SCREWUP("expected control record");
45814580Sralph 		}
4596440Swnj 		cp++;
4606440Swnj 		mode = 0;
4616440Swnj 		for (; cp < cmdbuf+5; cp++) {
4626440Swnj 			if (*cp < '0' || *cp > '7')
4636440Swnj 				SCREWUP("bad mode");
4646440Swnj 			mode = (mode << 3) | (*cp - '0');
4656440Swnj 		}
4666440Swnj 		if (*cp++ != ' ')
4676440Swnj 			SCREWUP("mode not delimited");
4686440Swnj 		size = 0;
4696440Swnj 		while (*cp >= '0' && *cp <= '9')
4706440Swnj 			size = size * 10 + (*cp++ - '0');
4716440Swnj 		if (*cp++ != ' ')
4726440Swnj 			SCREWUP("size not delimited");
4736440Swnj 		if (targisdir)
4746440Swnj 			(void) sprintf(nambuf, "%s%s%s", targ,
4756440Swnj 			    *targ ? "/" : "", cp);
4766440Swnj 		else
4776440Swnj 			(void) strcpy(nambuf, targ);
4786440Swnj 		exists = stat(nambuf, &stb) == 0;
4796440Swnj 		if (exists && access(nambuf, 2) < 0)
4806440Swnj 			goto bad2;
4816440Swnj 		{ char *slash = rindex(nambuf, '/'), *dir;
4826440Swnj 		  if (slash == 0) {
4836440Swnj 			slash = "/";
4846440Swnj 			dir = ".";
4856440Swnj 		  } else {
4866440Swnj 			*slash = 0;
4876440Swnj 			dir = nambuf;
48816039Sralph 			if (*dir == '\0')
48916039Sralph 				dir = "/";
4906440Swnj 		  }
4916440Swnj 		  if (exists == 0 && access(dir, 2) < 0)
4926440Swnj 			goto bad;
4936440Swnj 		  *slash = '/';
4946440Swnj 		  if (cmdbuf[0] == 'D') {
4956440Swnj 			if (stat(nambuf, &stb) == 0) {
4966440Swnj 				if ((stb.st_mode&S_IFMT) != S_IFDIR) {
4976440Swnj 					errno = ENOTDIR;
4986440Swnj 					goto bad;
4996440Swnj 				}
50017999Sserge 			} else if (makedir(nambuf, mode) < 0)
5016440Swnj 				goto bad;
5026440Swnj 			myargv[0] = nambuf;
5036440Swnj 			sink(1, myargv);
5046440Swnj 			continue;
5056440Swnj 		  }
5066440Swnj 		  if ((of = creat(nambuf, mode)) < 0) {
5076440Swnj 	bad:
5086440Swnj 			*slash = '/';
5096440Swnj 	bad2:
5106440Swnj 			error("rcp: %s: %s\n", nambuf, sys_errlist[errno]);
5116440Swnj 			continue;
5126440Swnj 		  }
5136440Swnj 		}
5146440Swnj 		if (exists == 0) {
51517999Sserge 			(void) chown(nambuf, pwd->pw_uid, -1);
5166440Swnj 			(void) chmod(nambuf, mode &~ mask);
5176440Swnj 		}
5186440Swnj 		ga();
5196440Swnj 		wrerr = 0;
5206440Swnj 		for (i = 0; i < size; i += BUFSIZ) {
5216440Swnj 			int amt = BUFSIZ;
5226440Swnj 			char *cp = buf;
5236440Swnj 
5246440Swnj 			if (i + amt > size)
5256440Swnj 				amt = size - i;
5266440Swnj 			do {
5276440Swnj 				int j = read(rem, cp, amt);
5286440Swnj 
5296440Swnj 				if (j <= 0)
5306440Swnj 					exit(1);
5316440Swnj 				amt -= j;
5326440Swnj 				cp += j;
5336440Swnj 			} while (amt > 0);
5346440Swnj 			amt = BUFSIZ;
5356440Swnj 			if (i + amt > size)
5366440Swnj 				amt = size - i;
5376440Swnj 			if (wrerr == 0 && write(of, buf, amt) != amt)
5386440Swnj 				wrerr++;
5396440Swnj 		}
5406440Swnj 		(void) close(of);
5416440Swnj 		(void) response();
5426440Swnj 		if (wrerr)
5436440Swnj 			error("rcp: %s: %s\n", cp, sys_errlist[errno]);
5446440Swnj 		else
5456440Swnj 			ga();
5466440Swnj 	}
5476440Swnj screwup:
5486440Swnj 	error("rcp: protocol screwup: %s\n", whopp);
5496440Swnj 	exit(1);
5506440Swnj }
5516440Swnj 
5526440Swnj /*VARARGS*/
5536440Swnj error(fmt, a1, a2, a3, a4, a5)
5546440Swnj 	char *fmt;
5556440Swnj 	int a1, a2, a3, a4, a5;
5566440Swnj {
5576440Swnj 	char buf[BUFSIZ], *cp = buf;
5586440Swnj 
5596440Swnj 	errs++;
5606440Swnj 	*cp++ = 1;
5616440Swnj 	(void) sprintf(cp, fmt, a1, a2, a3, a4, a5);
5626440Swnj 	(void) write(rem, buf, strlen(buf));
5636440Swnj 	if (iamremote == 0)
5646440Swnj 		(void) write(2, buf+1, strlen(buf+1));
5656440Swnj }
5666440Swnj 
56717999Sserge makedir(name, mode)
56817999Sserge 	register char *name;
56917999Sserge 	register int mode;
5706440Swnj {
57117999Sserge 	register int _errno;
5726440Swnj 
57317999Sserge 	if (mkdir(name, mode) < 0 || chown(name, getuid(), -1) < 0) {
57417999Sserge 		_errno = errno;
57517999Sserge 		rmdir(name);
57617999Sserge 		errno = _errno;
57717999Sserge 		return (-1);
5786440Swnj 	}
57917999Sserge 
58017999Sserge 	return (0);
5816440Swnj }
582