1babdf84bSdist /* 2babdf84bSdist * Copyright (c) 1983 Regents of the University of California. 3*7a864411Sbostic * All rights reserved. 4*7a864411Sbostic * 5*7a864411Sbostic * Redistribution and use in source and binary forms are permitted 6*7a864411Sbostic * provided that this notice is preserved and that due credit is given 7*7a864411Sbostic * to the University of California at Berkeley. The name of the University 8*7a864411Sbostic * may not be used to endorse or promote products derived from this 9*7a864411Sbostic * software without specific prior written permission. This software 10*7a864411Sbostic * is provided ``as is'' without express or implied warranty. 11babdf84bSdist */ 12babdf84bSdist 13978e44c9Sralph #ifndef lint 14*7a864411Sbostic static char sccsid[] = "@(#)server.c 5.6 (Berkeley) 02/01/88"; 15*7a864411Sbostic #endif /* not lint */ 16978e44c9Sralph 17978e44c9Sralph #include "defs.h" 18978e44c9Sralph 196d401060Sralph #define ack() (void) write(rem, "\0\n", 2) 206d401060Sralph #define err() (void) write(rem, "\1\n", 2) 21978e44c9Sralph 222cb25675Sralph struct linkbuf *ihead; /* list of files with more than one link */ 23d49851feSralph char buf[BUFSIZ]; /* general purpose buffer */ 24978e44c9Sralph char target[BUFSIZ]; /* target/source directory name */ 25978e44c9Sralph char *tp; /* pointer to end of target name */ 2626ce117eSsklower char *Tdest; /* pointer to last T dest*/ 27978e44c9Sralph int catname; /* cat name to target name */ 2865a0d230Sralph char *stp[32]; /* stack of saved tp's for directories */ 2901de96ecSralph int oumask; /* old umask for creating files */ 30d49851feSralph 31d49851feSralph extern FILE *lfp; /* log file for mailing changes */ 32d49851feSralph 33aca7acf4Sralph int cleanup(); 342cb25675Sralph struct linkbuf *savelink(); 35aca7acf4Sralph 36978e44c9Sralph /* 37978e44c9Sralph * Server routine to read requests and process them. 38978e44c9Sralph * Commands are: 39978e44c9Sralph * Tname - Transmit file if out of date 40978e44c9Sralph * Vname - Verify if file out of date or not 41978e44c9Sralph * Qname - Query if file exists. Return mtime & size if it does. 42978e44c9Sralph */ 43978e44c9Sralph server() 44978e44c9Sralph { 45978e44c9Sralph char cmdbuf[BUFSIZ]; 46978e44c9Sralph register char *cp; 47978e44c9Sralph 48aca7acf4Sralph signal(SIGHUP, cleanup); 49aca7acf4Sralph signal(SIGINT, cleanup); 50aca7acf4Sralph signal(SIGQUIT, cleanup); 51aca7acf4Sralph signal(SIGTERM, cleanup); 52aca7acf4Sralph signal(SIGPIPE, cleanup); 53aca7acf4Sralph 54aca7acf4Sralph rem = 0; 5501de96ecSralph oumask = umask(0); 5636a9f5b1Sralph (void) sprintf(buf, "V%d\n", VERSION); 5736a9f5b1Sralph (void) write(rem, buf, strlen(buf)); 58978e44c9Sralph 59978e44c9Sralph for (;;) { 60978e44c9Sralph cp = cmdbuf; 61978e44c9Sralph if (read(rem, cp, 1) <= 0) 62978e44c9Sralph return; 63978e44c9Sralph if (*cp++ == '\n') { 6401de96ecSralph error("server: expected control record\n"); 65978e44c9Sralph continue; 66978e44c9Sralph } 67978e44c9Sralph do { 68978e44c9Sralph if (read(rem, cp, 1) != 1) 69aca7acf4Sralph cleanup(); 70d49851feSralph } while (*cp++ != '\n' && cp < &cmdbuf[BUFSIZ]); 71978e44c9Sralph *--cp = '\0'; 72978e44c9Sralph cp = cmdbuf; 73978e44c9Sralph switch (*cp++) { 74978e44c9Sralph case 'T': /* init target file/directory name */ 75d49851feSralph catname = 1; /* target should be directory */ 76d49851feSralph goto dotarget; 77d49851feSralph 78d49851feSralph case 't': /* init target file/directory name */ 79978e44c9Sralph catname = 0; 80d49851feSralph dotarget: 8101de96ecSralph if (exptilde(target, cp) == NULL) 8201de96ecSralph continue; 83978e44c9Sralph tp = target; 84978e44c9Sralph while (*tp) 85978e44c9Sralph tp++; 866d401060Sralph ack(); 87978e44c9Sralph continue; 88978e44c9Sralph 892cb25675Sralph case 'R': /* Transfer a regular file. */ 902cb25675Sralph recvf(cp, S_IFREG); 91978e44c9Sralph continue; 92978e44c9Sralph 932cb25675Sralph case 'D': /* Transfer a directory. */ 942cb25675Sralph recvf(cp, S_IFDIR); 952cb25675Sralph continue; 962cb25675Sralph 972cb25675Sralph case 'K': /* Transfer symbolic link. */ 982cb25675Sralph recvf(cp, S_IFLNK); 992cb25675Sralph continue; 1002cb25675Sralph 1012cb25675Sralph case 'k': /* Transfer hard link. */ 1022cb25675Sralph hardlink(cp); 103978e44c9Sralph continue; 104978e44c9Sralph 105978e44c9Sralph case 'E': /* End. (of directory) */ 106978e44c9Sralph *tp = '\0'; 10701de96ecSralph if (catname <= 0) { 10801de96ecSralph error("server: too many 'E's\n"); 109978e44c9Sralph continue; 110978e44c9Sralph } 11101de96ecSralph tp = stp[--catname]; 11265a0d230Sralph *tp = '\0'; 1136d401060Sralph ack(); 114978e44c9Sralph continue; 115978e44c9Sralph 116c27256c0Sralph case 'C': /* Clean. Cleanup a directory */ 1176d401060Sralph clean(cp); 118c27256c0Sralph continue; 119c27256c0Sralph 12001de96ecSralph case 'Q': /* Query. Does the file/directory exist? */ 12101de96ecSralph query(cp); 12265a0d230Sralph continue; 12365a0d230Sralph 1246d401060Sralph case 'S': /* Special. Execute commands */ 1256d401060Sralph dospecial(cp); 1266d401060Sralph continue; 1276d401060Sralph 12801de96ecSralph #ifdef notdef 12901de96ecSralph /* 13001de96ecSralph * These entries are reserved but not currently used. 13101de96ecSralph * The intent is to allow remote hosts to have master copies. 13201de96ecSralph * Currently, only the host rdist runs on can have masters. 13301de96ecSralph */ 13401de96ecSralph case 'X': /* start a new list of files to exclude */ 13501de96ecSralph except = bp = NULL; 13601de96ecSralph case 'x': /* add name to list of files to exclude */ 13701de96ecSralph if (*cp == '\0') { 1386d401060Sralph ack(); 13901de96ecSralph continue; 14001de96ecSralph } 14101de96ecSralph if (*cp == '~') { 14201de96ecSralph if (exptilde(buf, cp) == NULL) 14301de96ecSralph continue; 14401de96ecSralph cp = buf; 14501de96ecSralph } 14601de96ecSralph if (bp == NULL) 1476d401060Sralph except = bp = expand(makeblock(NAME, cp), E_VARS); 14801de96ecSralph else 1496d401060Sralph bp->b_next = expand(makeblock(NAME, cp), E_VARS); 15001de96ecSralph while (bp->b_next != NULL) 15101de96ecSralph bp = bp->b_next; 1526d401060Sralph ack(); 15301de96ecSralph continue; 15401de96ecSralph 1556d401060Sralph case 'I': /* Install. Transfer file if out of date. */ 15601de96ecSralph opts = 0; 15701de96ecSralph while (*cp >= '0' && *cp <= '7') 15801de96ecSralph opts = (opts << 3) | (*cp++ - '0'); 15901de96ecSralph if (*cp++ != ' ') { 16001de96ecSralph error("server: options not delimited\n"); 16101de96ecSralph return; 16201de96ecSralph } 1636d401060Sralph install(cp, opts); 164978e44c9Sralph continue; 165978e44c9Sralph 166978e44c9Sralph case 'L': /* Log. save message in log file */ 16765a0d230Sralph log(lfp, cp); 168978e44c9Sralph continue; 16901de96ecSralph #endif 170978e44c9Sralph 171d49851feSralph case '\1': 172aca7acf4Sralph nerrs++; 173d49851feSralph continue; 174d49851feSralph 175d49851feSralph case '\2': 176d49851feSralph return; 177d49851feSralph 178978e44c9Sralph default: 17901de96ecSralph error("server: unknown command '%s'\n", cp); 180978e44c9Sralph case '\0': 181978e44c9Sralph continue; 182978e44c9Sralph } 183978e44c9Sralph } 184978e44c9Sralph } 185978e44c9Sralph 186978e44c9Sralph /* 18701de96ecSralph * Update the file(s) if they are different. 18801de96ecSralph * destdir = 1 if destination should be a directory 18901de96ecSralph * (i.e., more than one source is being copied to the same destination). 190978e44c9Sralph */ 19101de96ecSralph install(src, dest, destdir, opts) 19201de96ecSralph char *src, *dest; 19301de96ecSralph int destdir, opts; 19401de96ecSralph { 19501de96ecSralph char *rname; 19626ce117eSsklower char destcopy[BUFSIZ]; 19701de96ecSralph 19801de96ecSralph if (dest == NULL) { 19901de96ecSralph opts &= ~WHOLE; /* WHOLE mode only useful if renaming */ 20001de96ecSralph dest = src; 20101de96ecSralph } 20201de96ecSralph 20301de96ecSralph if (nflag || debug) { 20401de96ecSralph printf("%s%s%s%s%s %s %s\n", opts & VERIFY ? "verify":"install", 20501de96ecSralph opts & WHOLE ? " -w" : "", 20601de96ecSralph opts & YOUNGER ? " -y" : "", 20701de96ecSralph opts & COMPARE ? " -b" : "", 2086d401060Sralph opts & REMOVE ? " -R" : "", src, dest); 20901de96ecSralph if (nflag) 21001de96ecSralph return; 21101de96ecSralph } 21201de96ecSralph 21301de96ecSralph rname = exptilde(target, src); 21401de96ecSralph if (rname == NULL) 21501de96ecSralph return; 21601de96ecSralph tp = target; 21701de96ecSralph while (*tp) 21801de96ecSralph tp++; 21901de96ecSralph /* 22001de96ecSralph * If we are renaming a directory and we want to preserve 2216d401060Sralph * the directory heirarchy (-w), we must strip off the leading 22201de96ecSralph * directory name and preserve the rest. 22301de96ecSralph */ 22401de96ecSralph if (opts & WHOLE) { 2256d401060Sralph while (*rname == '/') 22601de96ecSralph rname++; 2276d401060Sralph destdir = 1; 22801de96ecSralph } else { 22901de96ecSralph rname = rindex(target, '/'); 23001de96ecSralph if (rname == NULL) 23101de96ecSralph rname = target; 23201de96ecSralph else 23301de96ecSralph rname++; 23401de96ecSralph } 23501de96ecSralph if (debug) 23601de96ecSralph printf("target = %s, rname = %s\n", target, rname); 23701de96ecSralph /* 23801de96ecSralph * Pass the destination file/directory name to remote. 23901de96ecSralph */ 24001de96ecSralph (void) sprintf(buf, "%c%s\n", destdir ? 'T' : 't', dest); 24101de96ecSralph if (debug) 24201de96ecSralph printf("buf = %s", buf); 24301de96ecSralph (void) write(rem, buf, strlen(buf)); 24401de96ecSralph if (response() < 0) 24501de96ecSralph return; 24601de96ecSralph 24726ce117eSsklower if (destdir) { 24826ce117eSsklower strcpy(destcopy, dest); 24926ce117eSsklower Tdest = destcopy; 25026ce117eSsklower } 25101de96ecSralph sendf(rname, opts); 25226ce117eSsklower Tdest = 0; 25301de96ecSralph } 25401de96ecSralph 25526ce117eSsklower #define protoname() (pw ? pw->pw_name : user) 25626ce117eSsklower #define protogroup() (gr ? gr->gr_name : group) 25701de96ecSralph /* 25801de96ecSralph * Transfer the file or directory in target[]. 25901de96ecSralph * rname is the name of the file on the remote host. 26001de96ecSralph */ 26101de96ecSralph sendf(rname, opts) 26201de96ecSralph char *rname; 263ad3d87d9Sralph int opts; 264978e44c9Sralph { 265aca7acf4Sralph register struct subcmd *sc; 266978e44c9Sralph struct stat stb; 2672cb25675Sralph int sizerr, f, u, len; 268978e44c9Sralph off_t i; 2692cb25675Sralph DIR *d; 2702cb25675Sralph struct direct *dp; 2712cb25675Sralph char *otp, *cp; 27258fc31f7Sralph extern struct subcmd *subcmds; 27326ce117eSsklower static char user[15], group[15]; 274978e44c9Sralph 275978e44c9Sralph if (debug) 27601de96ecSralph printf("sendf(%s, %x)\n", rname, opts); 277978e44c9Sralph 27858fc31f7Sralph if (except(target)) 27965a0d230Sralph return; 280e980046fSralph if ((opts & FOLLOW ? stat(target, &stb) : lstat(target, &stb)) < 0) { 28101de96ecSralph error("%s: %s\n", target, sys_errlist[errno]); 282978e44c9Sralph return; 283978e44c9Sralph } 2842cb25675Sralph if ((u = update(rname, opts, &stb)) == 0) { 2852cb25675Sralph if ((stb.st_mode & S_IFMT) == S_IFREG && stb.st_nlink > 1) 2862cb25675Sralph (void) savelink(&stb); 287978e44c9Sralph return; 2882cb25675Sralph } 289978e44c9Sralph 29001de96ecSralph if (pw == NULL || pw->pw_uid != stb.st_uid) 29101de96ecSralph if ((pw = getpwuid(stb.st_uid)) == NULL) { 2926dfcab80Ssklower log(lfp, "%s: no password entry for uid %d \n", 2936dfcab80Ssklower target, stb.st_uid); 29426ce117eSsklower pw = NULL; 29526ce117eSsklower sprintf(user, ":%d", stb.st_uid); 296978e44c9Sralph } 29701de96ecSralph if (gr == NULL || gr->gr_gid != stb.st_gid) 29801de96ecSralph if ((gr = getgrgid(stb.st_gid)) == NULL) { 2996dfcab80Ssklower log(lfp, "%s: no name for group %d\n", 3006dfcab80Ssklower target, stb.st_gid); 30126ce117eSsklower gr = NULL; 30226ce117eSsklower sprintf(group, ":%d", stb.st_gid); 303978e44c9Sralph } 304156664fbSralph if (u == 1) { 3056d401060Sralph if (opts & VERIFY) { 3066d401060Sralph log(lfp, "need to install: %s\n", target); 3076d401060Sralph goto dospecial; 3086d401060Sralph } 30901de96ecSralph log(lfp, "installing: %s\n", target); 3106d401060Sralph opts &= ~(COMPARE|REMOVE); 311156664fbSralph } 312978e44c9Sralph 313978e44c9Sralph switch (stb.st_mode & S_IFMT) { 3142cb25675Sralph case S_IFDIR: 3152cb25675Sralph if ((d = opendir(target)) == NULL) { 3162cb25675Sralph error("%s: %s\n", target, sys_errlist[errno]); 3172cb25675Sralph return; 3182cb25675Sralph } 3192cb25675Sralph (void) sprintf(buf, "D%o %04o 0 0 %s %s %s\n", opts, 32026ce117eSsklower stb.st_mode & 07777, protoname(), protogroup(), rname); 3212cb25675Sralph if (debug) 32215867ad7Sralph printf("buf = %s", buf); 3232cb25675Sralph (void) write(rem, buf, strlen(buf)); 3242cb25675Sralph if (response() < 0) { 3252cb25675Sralph closedir(d); 3262cb25675Sralph return; 3272cb25675Sralph } 3282cb25675Sralph 3292cb25675Sralph if (opts & REMOVE) 3302cb25675Sralph rmchk(opts); 3312cb25675Sralph 3322cb25675Sralph otp = tp; 3332cb25675Sralph len = tp - target; 3342cb25675Sralph while (dp = readdir(d)) { 3352cb25675Sralph if (!strcmp(dp->d_name, ".") || 3362cb25675Sralph !strcmp(dp->d_name, "..")) 3372cb25675Sralph continue; 3382cb25675Sralph if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { 3392cb25675Sralph error("%s/%s: Name too long\n", target, 3402cb25675Sralph dp->d_name); 3412cb25675Sralph continue; 3422cb25675Sralph } 3432cb25675Sralph tp = otp; 3442cb25675Sralph *tp++ = '/'; 3452cb25675Sralph cp = dp->d_name; 3462cb25675Sralph while (*tp++ = *cp++) 3472cb25675Sralph ; 3482cb25675Sralph tp--; 3492cb25675Sralph sendf(dp->d_name, opts); 3502cb25675Sralph } 3512cb25675Sralph closedir(d); 3522cb25675Sralph (void) write(rem, "E\n", 2); 3532cb25675Sralph (void) response(); 3542cb25675Sralph tp = otp; 3552cb25675Sralph *tp = '\0'; 3562cb25675Sralph return; 3572cb25675Sralph 3582cb25675Sralph case S_IFLNK: 3592cb25675Sralph if (u != 1) 3602cb25675Sralph opts |= COMPARE; 36126ce117eSsklower if (stb.st_nlink > 1) { 36226ce117eSsklower struct linkbuf *lp; 36326ce117eSsklower 36426ce117eSsklower if ((lp = savelink(&stb)) != NULL) { 36526ce117eSsklower /* install link */ 36626ce117eSsklower if (*lp->target == 0) 36726ce117eSsklower (void) sprintf(buf, "k%o %s %s\n", opts, 36826ce117eSsklower lp->pathname, rname); 36926ce117eSsklower else 37026ce117eSsklower (void) sprintf(buf, "k%o %s/%s %s\n", opts, 37126ce117eSsklower lp->target, lp->pathname, rname); 37226ce117eSsklower if (debug) 37326ce117eSsklower printf("buf = %s", buf); 37426ce117eSsklower (void) write(rem, buf, strlen(buf)); 37526ce117eSsklower (void) response(); 37626ce117eSsklower return; 37726ce117eSsklower } 37826ce117eSsklower } 379e980046fSralph (void) sprintf(buf, "K%o %o %ld %ld %s %s %s\n", opts, 3802cb25675Sralph stb.st_mode & 07777, stb.st_size, stb.st_mtime, 38126ce117eSsklower protoname(), protogroup(), rname); 3822cb25675Sralph if (debug) 3832cb25675Sralph printf("buf = %s", buf); 3842cb25675Sralph (void) write(rem, buf, strlen(buf)); 3852cb25675Sralph if (response() < 0) 3862cb25675Sralph return; 3872cb25675Sralph sizerr = (readlink(target, buf, BUFSIZ) != stb.st_size); 3882cb25675Sralph (void) write(rem, buf, stb.st_size); 3892cb25675Sralph if (debug) 390e157bfacSbostic printf("readlink = %.*s\n", (int)stb.st_size, buf); 3912cb25675Sralph goto done; 3922cb25675Sralph 393978e44c9Sralph case S_IFREG: 394978e44c9Sralph break; 395978e44c9Sralph 396978e44c9Sralph default: 3972cb25675Sralph error("%s: not a file or directory\n", target); 398978e44c9Sralph return; 399978e44c9Sralph } 400978e44c9Sralph 401156664fbSralph if (u == 2) { 4026d401060Sralph if (opts & VERIFY) { 4036d401060Sralph log(lfp, "need to update: %s\n", target); 4046d401060Sralph goto dospecial; 405156664fbSralph } 4066d401060Sralph log(lfp, "updating: %s\n", target); 4076d401060Sralph } 4082cb25675Sralph 4092cb25675Sralph if (stb.st_nlink > 1) { 4102cb25675Sralph struct linkbuf *lp; 4112cb25675Sralph 4122cb25675Sralph if ((lp = savelink(&stb)) != NULL) { 4132cb25675Sralph /* install link */ 41426ce117eSsklower if (*lp->target == 0) 4152cb25675Sralph (void) sprintf(buf, "k%o %s %s\n", opts, 4162cb25675Sralph lp->pathname, rname); 41726ce117eSsklower else 41826ce117eSsklower (void) sprintf(buf, "k%o %s/%s %s\n", opts, 41926ce117eSsklower lp->target, lp->pathname, rname); 4202cb25675Sralph if (debug) 4212cb25675Sralph printf("buf = %s", buf); 4222cb25675Sralph (void) write(rem, buf, strlen(buf)); 4232cb25675Sralph (void) response(); 4242cb25675Sralph return; 4252cb25675Sralph } 4262cb25675Sralph } 427978e44c9Sralph 42801de96ecSralph if ((f = open(target, 0)) < 0) { 42901de96ecSralph error("%s: %s\n", target, sys_errlist[errno]); 430d49851feSralph return; 431d49851feSralph } 432e980046fSralph (void) sprintf(buf, "R%o %o %ld %ld %s %s %s\n", opts, 433ad3d87d9Sralph stb.st_mode & 07777, stb.st_size, stb.st_mtime, 43426ce117eSsklower protoname(), protogroup(), rname); 435978e44c9Sralph if (debug) 436978e44c9Sralph printf("buf = %s", buf); 437978e44c9Sralph (void) write(rem, buf, strlen(buf)); 438978e44c9Sralph if (response() < 0) { 439978e44c9Sralph (void) close(f); 440978e44c9Sralph return; 441978e44c9Sralph } 442978e44c9Sralph sizerr = 0; 443978e44c9Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 444978e44c9Sralph int amt = BUFSIZ; 445978e44c9Sralph if (i + amt > stb.st_size) 446978e44c9Sralph amt = stb.st_size - i; 447978e44c9Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 448978e44c9Sralph sizerr = 1; 449978e44c9Sralph (void) write(rem, buf, amt); 450978e44c9Sralph } 451978e44c9Sralph (void) close(f); 4522cb25675Sralph done: 4536d401060Sralph if (sizerr) { 45401de96ecSralph error("%s: file changed size\n", target); 4556d401060Sralph err(); 4566d401060Sralph } else 4576d401060Sralph ack(); 4582cb25675Sralph f = response(); 4592cb25675Sralph if (f < 0 || f == 0 && (opts & COMPARE)) 4606d401060Sralph return; 4616d401060Sralph dospecial: 46258fc31f7Sralph for (sc = subcmds; sc != NULL; sc = sc->sc_next) { 463aca7acf4Sralph if (sc->sc_type != SPECIAL) 4646d401060Sralph continue; 465e980046fSralph if (sc->sc_args != NULL && !inlist(sc->sc_args, target)) 4666d401060Sralph continue; 467aca7acf4Sralph log(lfp, "special \"%s\"\n", sc->sc_name); 4686d401060Sralph if (opts & VERIFY) 4696d401060Sralph continue; 470e980046fSralph (void) sprintf(buf, "SFILE=%s;%s\n", target, sc->sc_name); 4716d401060Sralph if (debug) 4726d401060Sralph printf("buf = %s", buf); 4736d401060Sralph (void) write(rem, buf, strlen(buf)); 4746d401060Sralph while (response() > 0) 4756d401060Sralph ; 4766d401060Sralph } 477978e44c9Sralph } 478978e44c9Sralph 4792cb25675Sralph struct linkbuf * 4802cb25675Sralph savelink(stp) 4812cb25675Sralph struct stat *stp; 482978e44c9Sralph { 4832cb25675Sralph struct linkbuf *lp; 4842cb25675Sralph int found = 0; 485978e44c9Sralph 4862cb25675Sralph for (lp = ihead; lp != NULL; lp = lp->nextp) 4872cb25675Sralph if (lp->inum == stp->st_ino && lp->devnum == stp->st_dev) { 4882cb25675Sralph lp->count--; 4892cb25675Sralph return(lp); 490978e44c9Sralph } 4912cb25675Sralph lp = (struct linkbuf *) malloc(sizeof(*lp)); 4922cb25675Sralph if (lp == NULL) 4932cb25675Sralph log(lfp, "out of memory, link information lost\n"); 4942cb25675Sralph else { 4952cb25675Sralph lp->nextp = ihead; 4962cb25675Sralph ihead = lp; 4972cb25675Sralph lp->inum = stp->st_ino; 4982cb25675Sralph lp->devnum = stp->st_dev; 4992cb25675Sralph lp->count = stp->st_nlink - 1; 5002cb25675Sralph strcpy(lp->pathname, target); 50126ce117eSsklower if (Tdest) 50226ce117eSsklower strcpy(lp->target, Tdest); 50326ce117eSsklower else 50426ce117eSsklower *lp->target = 0; 505978e44c9Sralph } 5062cb25675Sralph return(NULL); 507978e44c9Sralph } 508978e44c9Sralph 509978e44c9Sralph /* 510978e44c9Sralph * Check to see if file needs to be updated on the remote machine. 51101de96ecSralph * Returns 0 if no update, 1 if remote doesn't exist, 2 if out of date 51201de96ecSralph * and 3 if comparing binaries to determine if out of date. 513978e44c9Sralph */ 5142cb25675Sralph update(rname, opts, stp) 51501de96ecSralph char *rname; 516ad3d87d9Sralph int opts; 5172cb25675Sralph struct stat *stp; 518978e44c9Sralph { 51901de96ecSralph register char *cp, *s; 520978e44c9Sralph register off_t size; 521978e44c9Sralph register time_t mtime; 522978e44c9Sralph 523978e44c9Sralph if (debug) 5242cb25675Sralph printf("update(%s, %x, %x)\n", rname, opts, stp); 525978e44c9Sralph 526978e44c9Sralph /* 527978e44c9Sralph * Check to see if the file exists on the remote machine. 528978e44c9Sralph */ 52901de96ecSralph (void) sprintf(buf, "Q%s\n", rname); 530978e44c9Sralph if (debug) 531978e44c9Sralph printf("buf = %s", buf); 532978e44c9Sralph (void) write(rem, buf, strlen(buf)); 53326ce117eSsklower again: 53401de96ecSralph cp = s = buf; 535978e44c9Sralph do { 536978e44c9Sralph if (read(rem, cp, 1) != 1) 537d58796b1Sralph lostconn(); 538d49851feSralph } while (*cp++ != '\n' && cp < &buf[BUFSIZ]); 539978e44c9Sralph 54001de96ecSralph switch (*s++) { 541978e44c9Sralph case 'Y': 542978e44c9Sralph break; 543978e44c9Sralph 544d49851feSralph case 'N': /* file doesn't exist so install it */ 545978e44c9Sralph return(1); 546978e44c9Sralph 547978e44c9Sralph case '\1': 548aca7acf4Sralph nerrs++; 54901de96ecSralph if (*s != '\n') { 550d49851feSralph if (!iamremote) { 551d49851feSralph fflush(stdout); 55201de96ecSralph (void) write(2, s, cp - s); 553d49851feSralph } 554d49851feSralph if (lfp != NULL) 55501de96ecSralph (void) fwrite(s, 1, cp - s, lfp); 556d49851feSralph } 557978e44c9Sralph return(0); 558978e44c9Sralph 55926ce117eSsklower case '\3': 56026ce117eSsklower *--cp = '\0'; 56126ce117eSsklower if (lfp != NULL) 56226ce117eSsklower log(lfp, "update: note: %s\n", s); 56326ce117eSsklower goto again; 56426ce117eSsklower 565978e44c9Sralph default: 56615867ad7Sralph *--cp = '\0'; 56726ce117eSsklower error("update: unexpected response '%s'\n", s); 568978e44c9Sralph return(0); 569978e44c9Sralph } 570978e44c9Sralph 57101de96ecSralph if (*s == '\n') 572d49851feSralph return(2); 573978e44c9Sralph 574156664fbSralph if (opts & COMPARE) 575156664fbSralph return(3); 576156664fbSralph 577978e44c9Sralph size = 0; 57801de96ecSralph while (isdigit(*s)) 57901de96ecSralph size = size * 10 + (*s++ - '0'); 58001de96ecSralph if (*s++ != ' ') { 58101de96ecSralph error("update: size not delimited\n"); 582978e44c9Sralph return(0); 583978e44c9Sralph } 584978e44c9Sralph mtime = 0; 58501de96ecSralph while (isdigit(*s)) 58601de96ecSralph mtime = mtime * 10 + (*s++ - '0'); 58701de96ecSralph if (*s != '\n') { 58801de96ecSralph error("update: mtime not delimited\n"); 589978e44c9Sralph return(0); 590978e44c9Sralph } 591978e44c9Sralph /* 592978e44c9Sralph * File needs to be updated? 593978e44c9Sralph */ 594ad3d87d9Sralph if (opts & YOUNGER) { 5952cb25675Sralph if (stp->st_mtime == mtime) 59665a0d230Sralph return(0); 5972cb25675Sralph if (stp->st_mtime < mtime) { 59801de96ecSralph log(lfp, "Warning: %s: remote copy is newer\n", target); 59965a0d230Sralph return(0); 60065a0d230Sralph } 6012cb25675Sralph } else if (stp->st_mtime == mtime && stp->st_size == size) 602978e44c9Sralph return(0); 603d49851feSralph return(2); 604978e44c9Sralph } 605978e44c9Sralph 606978e44c9Sralph /* 607978e44c9Sralph * Query. Check to see if file exists. Return one of the following: 608978e44c9Sralph * N\n - doesn't exist 609978e44c9Sralph * Ysize mtime\n - exists and its a regular file (size & mtime of file) 6102cb25675Sralph * Y\n - exists and its a directory or symbolic link 611978e44c9Sralph * ^Aerror message\n 612978e44c9Sralph */ 61301de96ecSralph query(name) 614978e44c9Sralph char *name; 615978e44c9Sralph { 616978e44c9Sralph struct stat stb; 617978e44c9Sralph 618978e44c9Sralph if (catname) 619978e44c9Sralph (void) sprintf(tp, "/%s", name); 62065a0d230Sralph 6212cb25675Sralph if (lstat(target, &stb) < 0) { 622e980046fSralph if (errno == ENOENT) 623978e44c9Sralph (void) write(rem, "N\n", 2); 624e980046fSralph else 625e980046fSralph error("%s:%s: %s\n", host, target, sys_errlist[errno]); 626978e44c9Sralph *tp = '\0'; 627978e44c9Sralph return; 628978e44c9Sralph } 629978e44c9Sralph 630978e44c9Sralph switch (stb.st_mode & S_IFMT) { 631978e44c9Sralph case S_IFREG: 632e980046fSralph (void) sprintf(buf, "Y%ld %ld\n", stb.st_size, stb.st_mtime); 633978e44c9Sralph (void) write(rem, buf, strlen(buf)); 634978e44c9Sralph break; 635978e44c9Sralph 6362cb25675Sralph case S_IFLNK: 637978e44c9Sralph case S_IFDIR: 638978e44c9Sralph (void) write(rem, "Y\n", 2); 639978e44c9Sralph break; 640978e44c9Sralph 641978e44c9Sralph default: 6422cb25675Sralph error("%s: not a file or directory\n", name); 643978e44c9Sralph break; 644978e44c9Sralph } 645978e44c9Sralph *tp = '\0'; 646978e44c9Sralph } 647978e44c9Sralph 6482cb25675Sralph recvf(cmd, type) 649978e44c9Sralph char *cmd; 6502cb25675Sralph int type; 651978e44c9Sralph { 652978e44c9Sralph register char *cp; 65344f1d1c2Sralph int f, mode, opts, wrerr, olderrno; 654978e44c9Sralph off_t i, size; 655978e44c9Sralph time_t mtime; 656978e44c9Sralph struct stat stb; 657978e44c9Sralph struct timeval tvp[2]; 658e980046fSralph char *owner, *group; 659978e44c9Sralph char new[BUFSIZ]; 660d49851feSralph extern char *tmpname; 661978e44c9Sralph 662ad3d87d9Sralph cp = cmd; 663156664fbSralph opts = 0; 664156664fbSralph while (*cp >= '0' && *cp <= '7') 665156664fbSralph opts = (opts << 3) | (*cp++ - '0'); 666ad3d87d9Sralph if (*cp++ != ' ') { 66701de96ecSralph error("recvf: options not delimited\n"); 668ad3d87d9Sralph return; 669ad3d87d9Sralph } 670978e44c9Sralph mode = 0; 671156664fbSralph while (*cp >= '0' && *cp <= '7') 672ad3d87d9Sralph mode = (mode << 3) | (*cp++ - '0'); 673978e44c9Sralph if (*cp++ != ' ') { 67401de96ecSralph error("recvf: mode not delimited\n"); 675978e44c9Sralph return; 676978e44c9Sralph } 677978e44c9Sralph size = 0; 678978e44c9Sralph while (isdigit(*cp)) 679978e44c9Sralph size = size * 10 + (*cp++ - '0'); 680978e44c9Sralph if (*cp++ != ' ') { 68101de96ecSralph error("recvf: size not delimited\n"); 682978e44c9Sralph return; 683978e44c9Sralph } 684978e44c9Sralph mtime = 0; 685978e44c9Sralph while (isdigit(*cp)) 686978e44c9Sralph mtime = mtime * 10 + (*cp++ - '0'); 687978e44c9Sralph if (*cp++ != ' ') { 68801de96ecSralph error("recvf: mtime not delimited\n"); 689978e44c9Sralph return; 690978e44c9Sralph } 691978e44c9Sralph owner = cp; 692978e44c9Sralph while (*cp && *cp != ' ') 693978e44c9Sralph cp++; 694978e44c9Sralph if (*cp != ' ') { 69501de96ecSralph error("recvf: owner name not delimited\n"); 696978e44c9Sralph return; 697978e44c9Sralph } 698978e44c9Sralph *cp++ = '\0'; 699978e44c9Sralph group = cp; 700978e44c9Sralph while (*cp && *cp != ' ') 701978e44c9Sralph cp++; 702978e44c9Sralph if (*cp != ' ') { 70301de96ecSralph error("recvf: group name not delimited\n"); 704978e44c9Sralph return; 705978e44c9Sralph } 706978e44c9Sralph *cp++ = '\0'; 707978e44c9Sralph 7082cb25675Sralph if (type == S_IFDIR) { 70965a0d230Sralph if (catname >= sizeof(stp)) { 7102cb25675Sralph error("%s:%s: too many directory levels\n", 7112cb25675Sralph host, target); 71265a0d230Sralph return; 71365a0d230Sralph } 71465a0d230Sralph stp[catname] = tp; 715978e44c9Sralph if (catname++) { 716978e44c9Sralph *tp++ = '/'; 717978e44c9Sralph while (*tp++ = *cp++) 718978e44c9Sralph ; 719978e44c9Sralph tp--; 720978e44c9Sralph } 721ad3d87d9Sralph if (opts & VERIFY) { 7226d401060Sralph ack(); 723d49851feSralph return; 724d49851feSralph } 7252cb25675Sralph if (lstat(target, &stb) == 0) { 7266d401060Sralph if (ISDIR(stb.st_mode)) { 727e980046fSralph if ((stb.st_mode & 07777) == mode) { 7286d401060Sralph ack(); 729978e44c9Sralph return; 730d49851feSralph } 7313e1cad88Sralph buf[0] = '\0'; 7323e1cad88Sralph (void) sprintf(buf + 1, 733d66beb1aSlepreau "%s: Warning: remote mode %o != local mode %o\n", 734d66beb1aSlepreau target, stb.st_mode & 07777, mode); 7353e1cad88Sralph (void) write(rem, buf, strlen(buf + 1) + 1); 7363e1cad88Sralph return; 7373e1cad88Sralph } 738e980046fSralph errno = ENOTDIR; 739e980046fSralph } else if (errno == ENOENT && (mkdir(target, mode) == 0 || 740e980046fSralph chkparent(target) == 0 && mkdir(target, mode) == 0)) { 741e980046fSralph if (chog(target, owner, group, mode) == 0) 7426d401060Sralph ack(); 7436d401060Sralph return; 7446d401060Sralph } 745e980046fSralph error("%s:%s: %s\n", host, target, sys_errlist[errno]); 7466d401060Sralph tp = stp[--catname]; 7476d401060Sralph *tp = '\0'; 748978e44c9Sralph return; 749978e44c9Sralph } 750978e44c9Sralph 751978e44c9Sralph if (catname) 752978e44c9Sralph (void) sprintf(tp, "/%s", cp); 753978e44c9Sralph cp = rindex(target, '/'); 754978e44c9Sralph if (cp == NULL) 755e980046fSralph strcpy(new, tmpname); 756e980046fSralph else if (cp == target) 757e980046fSralph (void) sprintf(new, "/%s", tmpname); 758e980046fSralph else { 759978e44c9Sralph *cp = '\0'; 760e980046fSralph (void) sprintf(new, "%s/%s", target, tmpname); 761d49851feSralph *cp = '/'; 762e980046fSralph } 7632cb25675Sralph 7642cb25675Sralph if (type == S_IFLNK) { 7652cb25675Sralph int j; 7662cb25675Sralph 7672cb25675Sralph ack(); 7682cb25675Sralph cp = buf; 7692cb25675Sralph for (i = 0; i < size; i += j) { 7702cb25675Sralph if ((j = read(rem, cp, size - i)) <= 0) 7712cb25675Sralph cleanup(); 7722cb25675Sralph cp += j; 7732cb25675Sralph } 7742cb25675Sralph *cp = '\0'; 775e980046fSralph if (response() < 0) { 776e980046fSralph err(); 777e980046fSralph return; 778e980046fSralph } 77975527c89Sralph if (symlink(buf, new) < 0) { 78075527c89Sralph if (errno != ENOENT || chkparent(new) < 0 || 78175527c89Sralph symlink(buf, new) < 0) 782e980046fSralph goto badn; 78375527c89Sralph } 7842cb25675Sralph mode &= 0777; 7852cb25675Sralph if (opts & COMPARE) { 7862cb25675Sralph char tbuf[BUFSIZ]; 7872cb25675Sralph 78875527c89Sralph if ((i = readlink(target, tbuf, BUFSIZ)) >= 0 && 78975527c89Sralph i == size && strncmp(buf, tbuf, size) == 0) { 7902cb25675Sralph (void) unlink(new); 7912cb25675Sralph ack(); 7922cb25675Sralph return; 7932cb25675Sralph } 79415867ad7Sralph if (opts & VERIFY) 79515867ad7Sralph goto differ; 7962cb25675Sralph } 7972cb25675Sralph goto fixup; 7982cb25675Sralph } 7992cb25675Sralph 800e980046fSralph if ((f = creat(new, mode)) < 0) { 801e980046fSralph if (errno != ENOENT || chkparent(new) < 0 || 802e980046fSralph (f = creat(new, mode)) < 0) 80375527c89Sralph goto badn; 804e980046fSralph } 805e980046fSralph 8066d401060Sralph ack(); 807978e44c9Sralph wrerr = 0; 808978e44c9Sralph for (i = 0; i < size; i += BUFSIZ) { 809978e44c9Sralph int amt = BUFSIZ; 810978e44c9Sralph 81165a0d230Sralph cp = buf; 812978e44c9Sralph if (i + amt > size) 813978e44c9Sralph amt = size - i; 814978e44c9Sralph do { 815978e44c9Sralph int j = read(rem, cp, amt); 816978e44c9Sralph 817d49851feSralph if (j <= 0) { 818d49851feSralph (void) close(f); 819d49851feSralph (void) unlink(new); 820978e44c9Sralph cleanup(); 821d49851feSralph } 822978e44c9Sralph amt -= j; 823978e44c9Sralph cp += j; 824978e44c9Sralph } while (amt > 0); 825978e44c9Sralph amt = BUFSIZ; 826978e44c9Sralph if (i + amt > size) 827978e44c9Sralph amt = size - i; 828978e44c9Sralph if (wrerr == 0 && write(f, buf, amt) != amt) { 829978e44c9Sralph olderrno = errno; 830978e44c9Sralph wrerr++; 831978e44c9Sralph } 832978e44c9Sralph } 833156664fbSralph (void) close(f); 834e980046fSralph if (response() < 0) { 835e980046fSralph err(); 836e980046fSralph (void) unlink(new); 837e980046fSralph return; 838e980046fSralph } 839978e44c9Sralph if (wrerr) { 840ed12aba6Sralph error("%s:%s: %s\n", host, new, sys_errlist[olderrno]); 841d49851feSralph (void) unlink(new); 842978e44c9Sralph return; 843978e44c9Sralph } 844156664fbSralph if (opts & COMPARE) { 845156664fbSralph FILE *f1, *f2; 846156664fbSralph int c; 847156664fbSralph 848156664fbSralph if ((f1 = fopen(target, "r")) == NULL) 849e980046fSralph goto badt; 85026ce117eSsklower if ((f2 = fopen(new, "r")) == NULL) { 85126ce117eSsklower badn: 85226ce117eSsklower error("%s:%s: %s\n", host, new, sys_errlist[errno]); 85326ce117eSsklower (void) unlink(new); 85426ce117eSsklower return; 85526ce117eSsklower } 856156664fbSralph while ((c = getc(f1)) == getc(f2)) 857156664fbSralph if (c == EOF) { 858156664fbSralph (void) fclose(f1); 859156664fbSralph (void) fclose(f2); 860156664fbSralph (void) unlink(new); 8616d401060Sralph ack(); 862156664fbSralph return; 863156664fbSralph } 864156664fbSralph (void) fclose(f1); 865156664fbSralph (void) fclose(f2); 866156664fbSralph if (opts & VERIFY) { 8672cb25675Sralph differ: 868156664fbSralph (void) unlink(new); 869156664fbSralph buf[0] = '\0'; 870e980046fSralph (void) sprintf(buf + 1, "need to update: %s\n",target); 871156664fbSralph (void) write(rem, buf, strlen(buf + 1) + 1); 872156664fbSralph return; 873156664fbSralph } 874156664fbSralph } 875978e44c9Sralph 876978e44c9Sralph /* 877978e44c9Sralph * Set last modified time 878978e44c9Sralph */ 8792cb25675Sralph tvp[0].tv_sec = stb.st_atime; /* old atime from target */ 880978e44c9Sralph tvp[0].tv_usec = 0; 881978e44c9Sralph tvp[1].tv_sec = mtime; 882978e44c9Sralph tvp[1].tv_usec = 0; 88398722ed6Sralph if (utimes(new, tvp) < 0) { 88426ce117eSsklower note("%s:utimes failed %s: %s\n", host, new, sys_errlist[errno]); 88598722ed6Sralph } 88698722ed6Sralph if (chog(new, owner, group, mode) < 0) { 887d49851feSralph (void) unlink(new); 888978e44c9Sralph return; 889978e44c9Sralph } 89075527c89Sralph fixup: 891978e44c9Sralph if (rename(new, target) < 0) { 892e980046fSralph badt: 8932cb25675Sralph error("%s:%s: %s\n", host, target, sys_errlist[errno]); 894d49851feSralph (void) unlink(new); 895978e44c9Sralph return; 896978e44c9Sralph } 897156664fbSralph if (opts & COMPARE) { 898156664fbSralph buf[0] = '\0'; 899d66beb1aSlepreau (void) sprintf(buf + 1, "updated %s\n", target); 900156664fbSralph (void) write(rem, buf, strlen(buf + 1) + 1); 901156664fbSralph } else 9026d401060Sralph ack(); 903978e44c9Sralph } 904978e44c9Sralph 905978e44c9Sralph /* 9062cb25675Sralph * Creat a hard link to existing file. 9072cb25675Sralph */ 9082cb25675Sralph hardlink(cmd) 9092cb25675Sralph char *cmd; 9102cb25675Sralph { 9112cb25675Sralph register char *cp; 9122cb25675Sralph struct stat stb; 9132cb25675Sralph char *oldname; 9142cb25675Sralph int opts, exists = 0; 9152cb25675Sralph 9162cb25675Sralph cp = cmd; 9172cb25675Sralph opts = 0; 9182cb25675Sralph while (*cp >= '0' && *cp <= '7') 9192cb25675Sralph opts = (opts << 3) | (*cp++ - '0'); 9202cb25675Sralph if (*cp++ != ' ') { 9212cb25675Sralph error("hardlink: options not delimited\n"); 9222cb25675Sralph return; 9232cb25675Sralph } 9242cb25675Sralph oldname = cp; 9252cb25675Sralph while (*cp && *cp != ' ') 9262cb25675Sralph cp++; 9272cb25675Sralph if (*cp != ' ') { 9282cb25675Sralph error("hardlink: oldname name not delimited\n"); 9292cb25675Sralph return; 9302cb25675Sralph } 9312cb25675Sralph *cp++ = '\0'; 9322cb25675Sralph 93326ce117eSsklower if (catname) { 9342cb25675Sralph (void) sprintf(tp, "/%s", cp); 93526ce117eSsklower } 9362cb25675Sralph if (lstat(target, &stb) == 0) { 93726ce117eSsklower int mode = stb.st_mode & S_IFMT; 93826ce117eSsklower if (mode != S_IFREG && mode != S_IFLNK) { 9392cb25675Sralph error("%s:%s: not a regular file\n", host, target); 9402cb25675Sralph return; 9412cb25675Sralph } 9422cb25675Sralph exists = 1; 9432cb25675Sralph } 94426ce117eSsklower if (chkparent(target) < 0 ) { 94526ce117eSsklower error("%s:%s: %s (no parent)\n", 94626ce117eSsklower host, target, sys_errlist[errno]); 94726ce117eSsklower return; 94826ce117eSsklower } 94926ce117eSsklower if (exists && (unlink(target) < 0)) { 95026ce117eSsklower error("%s:%s: %s (unlink)\n", 95126ce117eSsklower host, target, sys_errlist[errno]); 95226ce117eSsklower return; 95326ce117eSsklower } 95426ce117eSsklower if (link(oldname, target) < 0) { 95526ce117eSsklower error("%s:can't link %s to %s\n", 95626ce117eSsklower host, target, oldname); 9572cb25675Sralph return; 9582cb25675Sralph } 9592cb25675Sralph ack(); 9602cb25675Sralph } 9612cb25675Sralph 9622cb25675Sralph /* 963e980046fSralph * Check to see if parent directory exists and create one if not. 96465a0d230Sralph */ 96565a0d230Sralph chkparent(name) 96665a0d230Sralph char *name; 96765a0d230Sralph { 968e980046fSralph register char *cp; 969e980046fSralph struct stat stb; 97065a0d230Sralph 97165a0d230Sralph cp = rindex(name, '/'); 972e980046fSralph if (cp == NULL || cp == name) 973e980046fSralph return(0); 97465a0d230Sralph *cp = '\0'; 975e980046fSralph if (lstat(name, &stb) < 0) { 976e980046fSralph if (errno == ENOENT && chkparent(name) >= 0 && 977e980046fSralph mkdir(name, 0777 & ~oumask) >= 0) { 97865a0d230Sralph *cp = '/'; 97965a0d230Sralph return(0); 98065a0d230Sralph } 981e980046fSralph } else if (ISDIR(stb.st_mode)) { 98265a0d230Sralph *cp = '/'; 98365a0d230Sralph return(0); 98465a0d230Sralph } 98565a0d230Sralph *cp = '/'; 98665a0d230Sralph return(-1); 98765a0d230Sralph } 98865a0d230Sralph 98965a0d230Sralph /* 9906d401060Sralph * Change owner, group and mode of file. 991978e44c9Sralph */ 992d49851feSralph chog(file, owner, group, mode) 993978e44c9Sralph char *file, *owner, *group; 994d49851feSralph int mode; 995978e44c9Sralph { 996978e44c9Sralph register int i; 997978e44c9Sralph int uid, gid; 998e980046fSralph extern char user[]; 999e980046fSralph extern int userid; 1000978e44c9Sralph 1001978e44c9Sralph uid = userid; 1002978e44c9Sralph if (userid == 0) { 100326ce117eSsklower if (*owner == ':') { 100426ce117eSsklower uid = atoi(owner + 1); 100526ce117eSsklower } else if (pw == NULL || strcmp(owner, pw->pw_name) != 0) { 100601de96ecSralph if ((pw = getpwnam(owner)) == NULL) { 1007d49851feSralph if (mode & 04000) { 100826ce117eSsklower note("%s:%s: unknown login name, clearing setuid", 10092cb25675Sralph host, owner); 101026ce117eSsklower mode &= ~04000; 101126ce117eSsklower uid = 0; 1012978e44c9Sralph } 1013d49851feSralph } else 101401de96ecSralph uid = pw->pw_uid; 1015d49851feSralph } else 101601de96ecSralph uid = pw->pw_uid; 101726ce117eSsklower if (*group == ':') { 101826ce117eSsklower gid = atoi(group + 1); 101926ce117eSsklower goto ok; 102026ce117eSsklower } 10216d401060Sralph } else if ((mode & 04000) && strcmp(user, owner) != 0) 10226d401060Sralph mode &= ~04000; 1023e980046fSralph gid = -1; 102401de96ecSralph if (gr == NULL || strcmp(group, gr->gr_name) != 0) { 102526ce117eSsklower if ((*group == ':' && (getgrgid(gid = atoi(group + 1)) == NULL)) 102626ce117eSsklower || ((gr = getgrnam(group)) == NULL)) { 1027d49851feSralph if (mode & 02000) { 102826ce117eSsklower note("%s:%s: unknown group", host, group); 102926ce117eSsklower mode &= ~02000; 1030978e44c9Sralph } 1031d49851feSralph } else 103201de96ecSralph gid = gr->gr_gid; 1033d49851feSralph } else 103401de96ecSralph gid = gr->gr_gid; 1035e980046fSralph if (userid && gid >= 0) { 103626ce117eSsklower if (gr) for (i = 0; gr->gr_mem[i] != NULL; i++) 103701de96ecSralph if (!(strcmp(user, gr->gr_mem[i]))) 1038978e44c9Sralph goto ok; 10396d401060Sralph mode &= ~02000; 1040e980046fSralph gid = -1; 1041978e44c9Sralph } 1042978e44c9Sralph ok: 1043e980046fSralph if (userid) 1044e980046fSralph setreuid(userid, 0); 1045e980046fSralph if (chown(file, uid, gid) < 0 || 1046e980046fSralph (mode & 06000) && chmod(file, mode) < 0) { 104726ce117eSsklower note("%s: chown or chmod failed: file %s: %s", 104826ce117eSsklower host, file, sys_errlist[errno]); 1049978e44c9Sralph } 1050e980046fSralph if (userid) 1051e980046fSralph setreuid(0, userid); 1052978e44c9Sralph return(0); 1053978e44c9Sralph } 1054978e44c9Sralph 1055c27256c0Sralph /* 1056c27256c0Sralph * Check for files on the machine being updated that are not on the master 1057c27256c0Sralph * machine and remove them. 1058c27256c0Sralph */ 10596d401060Sralph rmchk(opts) 1060c27256c0Sralph int opts; 1061c27256c0Sralph { 106201de96ecSralph register char *cp, *s; 1063c27256c0Sralph struct stat stb; 1064c27256c0Sralph 1065c27256c0Sralph if (debug) 10666d401060Sralph printf("rmchk()\n"); 1067156664fbSralph 1068c27256c0Sralph /* 1069c27256c0Sralph * Tell the remote to clean the files from the last directory sent. 1070c27256c0Sralph */ 10716d401060Sralph (void) sprintf(buf, "C%o\n", opts & VERIFY); 1072c27256c0Sralph if (debug) 1073c27256c0Sralph printf("buf = %s", buf); 1074c27256c0Sralph (void) write(rem, buf, strlen(buf)); 1075c27256c0Sralph if (response() < 0) 1076c27256c0Sralph return; 1077c27256c0Sralph for (;;) { 107801de96ecSralph cp = s = buf; 1079c27256c0Sralph do { 1080c27256c0Sralph if (read(rem, cp, 1) != 1) 1081d58796b1Sralph lostconn(); 1082c27256c0Sralph } while (*cp++ != '\n' && cp < &buf[BUFSIZ]); 1083c27256c0Sralph 108401de96ecSralph switch (*s++) { 10856d401060Sralph case 'Q': /* Query if file should be removed */ 1086156664fbSralph /* 1087156664fbSralph * Return the following codes to remove query. 10886d401060Sralph * N\n -- file exists - DON'T remove. 10896d401060Sralph * Y\n -- file doesn't exist - REMOVE. 1090156664fbSralph */ 1091c27256c0Sralph *--cp = '\0'; 109201de96ecSralph (void) sprintf(tp, "/%s", s); 1093c27256c0Sralph if (debug) 1094c27256c0Sralph printf("check %s\n", target); 109558fc31f7Sralph if (except(target)) 1096c27256c0Sralph (void) write(rem, "N\n", 2); 10972cb25675Sralph else if (lstat(target, &stb) < 0) 1098c27256c0Sralph (void) write(rem, "Y\n", 2); 10996d401060Sralph else 11006d401060Sralph (void) write(rem, "N\n", 2); 1101c27256c0Sralph break; 1102c27256c0Sralph 1103c27256c0Sralph case '\0': 1104c27256c0Sralph *--cp = '\0'; 110501de96ecSralph if (*s != '\0') 110601de96ecSralph log(lfp, "%s\n", s); 1107c27256c0Sralph break; 1108c27256c0Sralph 11096d401060Sralph case 'E': 11106d401060Sralph *tp = '\0'; 11116d401060Sralph ack(); 11126d401060Sralph return; 11136d401060Sralph 1114c27256c0Sralph case '\1': 1115c27256c0Sralph case '\2': 1116aca7acf4Sralph nerrs++; 111701de96ecSralph if (*s != '\n') { 1118c27256c0Sralph if (!iamremote) { 1119c27256c0Sralph fflush(stdout); 112001de96ecSralph (void) write(2, s, cp - s); 1121c27256c0Sralph } 1122c27256c0Sralph if (lfp != NULL) 112301de96ecSralph (void) fwrite(s, 1, cp - s, lfp); 1124c27256c0Sralph } 1125c27256c0Sralph if (buf[0] == '\2') 1126d58796b1Sralph lostconn(); 1127c27256c0Sralph break; 1128c27256c0Sralph 1129c27256c0Sralph default: 11306d401060Sralph error("rmchk: unexpected response '%s'\n", buf); 11316d401060Sralph err(); 1132c27256c0Sralph } 1133c27256c0Sralph } 1134c27256c0Sralph } 1135c27256c0Sralph 1136c27256c0Sralph /* 11376d401060Sralph * Check the current directory (initialized by the 'T' command to server()) 1138156664fbSralph * for extraneous files and remove them. 1139c27256c0Sralph */ 114000fd8e74Sralph clean(cp) 114100fd8e74Sralph register char *cp; 1142c27256c0Sralph { 1143c27256c0Sralph DIR *d; 11446d401060Sralph register struct direct *dp; 1145c27256c0Sralph struct stat stb; 11466d401060Sralph char *otp; 11476d401060Sralph int len, opts; 1148c27256c0Sralph 11496d401060Sralph opts = 0; 11506d401060Sralph while (*cp >= '0' && *cp <= '7') 11516d401060Sralph opts = (opts << 3) | (*cp++ - '0'); 11526d401060Sralph if (*cp != '\0') { 11536d401060Sralph error("clean: options not delimited\n"); 1154c27256c0Sralph return; 1155c27256c0Sralph } 1156e980046fSralph if ((d = opendir(target)) == NULL) { 11572cb25675Sralph error("%s:%s: %s\n", host, target, sys_errlist[errno]); 115801de96ecSralph return; 115901de96ecSralph } 11606d401060Sralph ack(); 1161c27256c0Sralph 1162c27256c0Sralph otp = tp; 1163c27256c0Sralph len = tp - target; 1164c27256c0Sralph while (dp = readdir(d)) { 1165c27256c0Sralph if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 1166c27256c0Sralph continue; 1167c27256c0Sralph if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { 11682cb25675Sralph error("%s:%s/%s: Name too long\n", 11692cb25675Sralph host, target, dp->d_name); 1170c27256c0Sralph continue; 1171c27256c0Sralph } 1172c27256c0Sralph tp = otp; 1173c27256c0Sralph *tp++ = '/'; 1174c27256c0Sralph cp = dp->d_name;; 1175c27256c0Sralph while (*tp++ = *cp++) 1176c27256c0Sralph ; 1177c27256c0Sralph tp--; 11782cb25675Sralph if (lstat(target, &stb) < 0) { 11792cb25675Sralph error("%s:%s: %s\n", host, target, sys_errlist[errno]); 1180c27256c0Sralph continue; 1181c27256c0Sralph } 11826d401060Sralph (void) sprintf(buf, "Q%s\n", dp->d_name); 1183c27256c0Sralph (void) write(rem, buf, strlen(buf)); 1184c27256c0Sralph cp = buf; 1185c27256c0Sralph do { 1186c27256c0Sralph if (read(rem, cp, 1) != 1) 1187aca7acf4Sralph cleanup(); 1188c27256c0Sralph } while (*cp++ != '\n' && cp < &buf[BUFSIZ]); 1189c27256c0Sralph *--cp = '\0'; 1190c27256c0Sralph cp = buf; 11916d401060Sralph if (*cp != 'Y') 1192c27256c0Sralph continue; 119301de96ecSralph if (opts & VERIFY) { 119401de96ecSralph cp = buf; 119501de96ecSralph *cp++ = '\0'; 1196e980046fSralph (void) sprintf(cp, "need to remove: %s\n", target); 119701de96ecSralph (void) write(rem, buf, strlen(cp) + 1); 119801de96ecSralph } else 1199c27256c0Sralph remove(&stb); 1200c27256c0Sralph } 1201c27256c0Sralph closedir(d); 1202c27256c0Sralph (void) write(rem, "E\n", 2); 1203c27256c0Sralph (void) response(); 12046d401060Sralph tp = otp; 120501de96ecSralph *tp = '\0'; 1206c27256c0Sralph } 1207c27256c0Sralph 120801de96ecSralph /* 120901de96ecSralph * Remove a file or directory (recursively) and send back an acknowledge 121001de96ecSralph * or an error message. 121101de96ecSralph */ 12122cb25675Sralph remove(stp) 12132cb25675Sralph struct stat *stp; 1214c27256c0Sralph { 1215c27256c0Sralph DIR *d; 1216c27256c0Sralph struct direct *dp; 1217c27256c0Sralph register char *cp; 1218c27256c0Sralph struct stat stb; 1219c27256c0Sralph char *otp; 1220c27256c0Sralph int len; 1221c27256c0Sralph 12222cb25675Sralph switch (stp->st_mode & S_IFMT) { 1223c27256c0Sralph case S_IFREG: 12242cb25675Sralph case S_IFLNK: 1225c27256c0Sralph if (unlink(target) < 0) 1226c27256c0Sralph goto bad; 1227c27256c0Sralph goto removed; 1228c27256c0Sralph 1229c27256c0Sralph case S_IFDIR: 1230c27256c0Sralph break; 1231c27256c0Sralph 1232c27256c0Sralph default: 12332cb25675Sralph error("%s:%s: not a plain file\n", host, target); 1234c27256c0Sralph return; 1235c27256c0Sralph } 1236c27256c0Sralph 1237e980046fSralph if ((d = opendir(target)) == NULL) 1238c27256c0Sralph goto bad; 1239c27256c0Sralph 1240c27256c0Sralph otp = tp; 1241c27256c0Sralph len = tp - target; 1242c27256c0Sralph while (dp = readdir(d)) { 1243c27256c0Sralph if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 1244c27256c0Sralph continue; 1245c27256c0Sralph if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { 12462cb25675Sralph error("%s:%s/%s: Name too long\n", 12472cb25675Sralph host, target, dp->d_name); 1248c27256c0Sralph continue; 1249c27256c0Sralph } 1250c27256c0Sralph tp = otp; 1251c27256c0Sralph *tp++ = '/'; 1252c27256c0Sralph cp = dp->d_name;; 1253c27256c0Sralph while (*tp++ = *cp++) 1254c27256c0Sralph ; 1255c27256c0Sralph tp--; 12562cb25675Sralph if (lstat(target, &stb) < 0) { 12572cb25675Sralph error("%s:%s: %s\n", host, target, sys_errlist[errno]); 1258c27256c0Sralph continue; 1259c27256c0Sralph } 1260c27256c0Sralph remove(&stb); 1261c27256c0Sralph } 1262c27256c0Sralph closedir(d); 1263c27256c0Sralph tp = otp; 1264c27256c0Sralph *tp = '\0'; 1265c27256c0Sralph if (rmdir(target) < 0) { 1266c27256c0Sralph bad: 12672cb25675Sralph error("%s:%s: %s\n", host, target, sys_errlist[errno]); 1268c27256c0Sralph return; 1269c27256c0Sralph } 1270c27256c0Sralph removed: 1271c27256c0Sralph cp = buf; 1272c27256c0Sralph *cp++ = '\0'; 1273c27256c0Sralph (void) sprintf(cp, "removed %s\n", target); 1274c27256c0Sralph (void) write(rem, buf, strlen(cp) + 1); 1275c27256c0Sralph } 1276c27256c0Sralph 12776d401060Sralph /* 12786d401060Sralph * Execute a shell command to handle special cases. 12796d401060Sralph */ 12806d401060Sralph dospecial(cmd) 12816d401060Sralph char *cmd; 12826d401060Sralph { 12836d401060Sralph int fd[2], status, pid, i; 12846d401060Sralph register char *cp, *s; 12856d401060Sralph char sbuf[BUFSIZ]; 1286e980046fSralph extern int userid, groupid; 12876d401060Sralph 12886d401060Sralph if (pipe(fd) < 0) { 12896d401060Sralph error("%s\n", sys_errlist[errno]); 12906d401060Sralph return; 12916d401060Sralph } 12926d401060Sralph if ((pid = fork()) == 0) { 12936d401060Sralph /* 12946d401060Sralph * Return everything the shell commands print. 12956d401060Sralph */ 12966d401060Sralph (void) close(0); 12976d401060Sralph (void) close(1); 12986d401060Sralph (void) close(2); 12996d401060Sralph (void) open("/dev/null", 0); 13006d401060Sralph (void) dup(fd[1]); 13016d401060Sralph (void) dup(fd[1]); 13026d401060Sralph (void) close(fd[0]); 13036d401060Sralph (void) close(fd[1]); 1304e980046fSralph setgid(groupid); 1305a5437550Sralph setuid(userid); 13066d401060Sralph execl("/bin/sh", "sh", "-c", cmd, 0); 13076d401060Sralph _exit(127); 13086d401060Sralph } 13096d401060Sralph (void) close(fd[1]); 13106d401060Sralph s = sbuf; 13116d401060Sralph *s++ = '\0'; 13126d401060Sralph while ((i = read(fd[0], buf, sizeof(buf))) > 0) { 13136d401060Sralph cp = buf; 13146d401060Sralph do { 13156d401060Sralph *s++ = *cp++; 13166d401060Sralph if (cp[-1] != '\n') { 13176d401060Sralph if (s < &sbuf[sizeof(sbuf)-1]) 13186d401060Sralph continue; 13196d401060Sralph *s++ = '\n'; 13206d401060Sralph } 13216d401060Sralph /* 13226d401060Sralph * Throw away blank lines. 13236d401060Sralph */ 13246d401060Sralph if (s == &sbuf[2]) { 13256d401060Sralph s--; 13266d401060Sralph continue; 13276d401060Sralph } 13286d401060Sralph (void) write(rem, sbuf, s - sbuf); 13296d401060Sralph s = &sbuf[1]; 13306d401060Sralph } while (--i); 13316d401060Sralph } 13326d401060Sralph if (s > &sbuf[1]) { 13336d401060Sralph *s++ = '\n'; 13346d401060Sralph (void) write(rem, sbuf, s - sbuf); 13356d401060Sralph } 13366d401060Sralph while ((i = wait(&status)) != pid && i != -1) 13376d401060Sralph ; 13386d401060Sralph if (i == -1) 13396d401060Sralph status = -1; 1340e980046fSralph (void) close(fd[0]); 13416d401060Sralph if (status) 13426d401060Sralph error("shell returned %d\n", status); 13436d401060Sralph else 13446d401060Sralph ack(); 13456d401060Sralph } 13466d401060Sralph 134765a0d230Sralph /*VARARGS2*/ 1348d49851feSralph log(fp, fmt, a1, a2, a3) 1349d49851feSralph FILE *fp; 1350978e44c9Sralph char *fmt; 1351978e44c9Sralph int a1, a2, a3; 1352978e44c9Sralph { 1353978e44c9Sralph /* Print changes locally if not quiet mode */ 1354978e44c9Sralph if (!qflag) 1355978e44c9Sralph printf(fmt, a1, a2, a3); 1356978e44c9Sralph 1357978e44c9Sralph /* Save changes (for mailing) if really updating files */ 1358ad3d87d9Sralph if (!(options & VERIFY) && fp != NULL) 1359d49851feSralph fprintf(fp, fmt, a1, a2, a3); 1360978e44c9Sralph } 1361978e44c9Sralph 136265a0d230Sralph /*VARARGS1*/ 1363978e44c9Sralph error(fmt, a1, a2, a3) 1364978e44c9Sralph char *fmt; 1365978e44c9Sralph int a1, a2, a3; 1366978e44c9Sralph { 1367aca7acf4Sralph nerrs++; 1368978e44c9Sralph strcpy(buf, "\1rdist: "); 1369978e44c9Sralph (void) sprintf(buf+8, fmt, a1, a2, a3); 1370d49851feSralph if (!iamremote) { 1371d49851feSralph fflush(stdout); 1372978e44c9Sralph (void) write(2, buf+1, strlen(buf+1)); 13736d401060Sralph } else 13746d401060Sralph (void) write(rem, buf, strlen(buf)); 1375978e44c9Sralph if (lfp != NULL) 1376978e44c9Sralph (void) fwrite(buf+1, 1, strlen(buf+1), lfp); 1377978e44c9Sralph } 1378978e44c9Sralph 137965a0d230Sralph /*VARARGS1*/ 1380978e44c9Sralph fatal(fmt, a1, a2,a3) 1381978e44c9Sralph char *fmt; 1382978e44c9Sralph int a1, a2, a3; 1383978e44c9Sralph { 1384aca7acf4Sralph nerrs++; 1385978e44c9Sralph strcpy(buf, "\2rdist: "); 1386978e44c9Sralph (void) sprintf(buf+8, fmt, a1, a2, a3); 1387d49851feSralph if (!iamremote) { 1388d49851feSralph fflush(stdout); 1389978e44c9Sralph (void) write(2, buf+1, strlen(buf+1)); 13906d401060Sralph } else 13916d401060Sralph (void) write(rem, buf, strlen(buf)); 1392978e44c9Sralph if (lfp != NULL) 1393978e44c9Sralph (void) fwrite(buf+1, 1, strlen(buf+1), lfp); 1394978e44c9Sralph cleanup(); 1395978e44c9Sralph } 1396978e44c9Sralph 1397978e44c9Sralph response() 1398978e44c9Sralph { 1399156664fbSralph char *cp, *s; 140015867ad7Sralph char resp[BUFSIZ]; 1401978e44c9Sralph 1402978e44c9Sralph if (debug) 1403978e44c9Sralph printf("response()\n"); 1404978e44c9Sralph 140515867ad7Sralph cp = s = resp; 1406978e44c9Sralph do { 1407978e44c9Sralph if (read(rem, cp, 1) != 1) 1408d58796b1Sralph lostconn(); 140915867ad7Sralph } while (*cp++ != '\n' && cp < &resp[BUFSIZ]); 1410156664fbSralph 1411156664fbSralph switch (*s++) { 1412156664fbSralph case '\0': 1413156664fbSralph *--cp = '\0'; 14146d401060Sralph if (*s != '\0') { 1415156664fbSralph log(lfp, "%s\n", s); 14166d401060Sralph return(1); 14176d401060Sralph } 1418156664fbSralph return(0); 141926ce117eSsklower case '\3': 142026ce117eSsklower *--cp = '\0'; 142126ce117eSsklower log(lfp, "Note: %s\n",s); 142226ce117eSsklower return(response()); 1423156664fbSralph 1424156664fbSralph default: 1425156664fbSralph s--; 1426156664fbSralph /* fall into... */ 1427156664fbSralph case '\1': 1428156664fbSralph case '\2': 1429aca7acf4Sralph nerrs++; 1430156664fbSralph if (*s != '\n') { 1431d49851feSralph if (!iamremote) { 1432d49851feSralph fflush(stdout); 1433156664fbSralph (void) write(2, s, cp - s); 1434d49851feSralph } 1435978e44c9Sralph if (lfp != NULL) 1436156664fbSralph (void) fwrite(s, 1, cp - s, lfp); 1437978e44c9Sralph } 143815867ad7Sralph if (resp[0] == '\2') 1439d58796b1Sralph lostconn(); 144001de96ecSralph return(-1); 1441978e44c9Sralph } 1442978e44c9Sralph } 1443978e44c9Sralph 1444aca7acf4Sralph /* 1445aca7acf4Sralph * Remove temporary files and do any cleanup operations before exiting. 1446aca7acf4Sralph */ 1447aca7acf4Sralph cleanup() 1448978e44c9Sralph { 1449aca7acf4Sralph (void) unlink(tmpfile); 1450aca7acf4Sralph exit(1); 1451978e44c9Sralph } 145226ce117eSsklower 145326ce117eSsklower note(fmt, a1, a2, a3) 145426ce117eSsklower { 145526ce117eSsklower static char buf[BUFSIZ]; 145626ce117eSsklower sprintf(buf, fmt, a1, a2, a3); 145726ce117eSsklower comment(buf); 145826ce117eSsklower } 145926ce117eSsklower 146026ce117eSsklower comment(s) 146126ce117eSsklower char *s; 146226ce117eSsklower { 146326ce117eSsklower char c = '\3'; 146426ce117eSsklower write(rem, &c, 1); 146526ce117eSsklower write(rem, s, strlen(s)); 146626ce117eSsklower c = '\n'; 146726ce117eSsklower write(rem, &c, 1); 146826ce117eSsklower } 1469