17c478bd9Sstevel@tonic-gate /* 2*56fbdff6SChandan * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 37c478bd9Sstevel@tonic-gate * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate */ 57c478bd9Sstevel@tonic-gate 67c478bd9Sstevel@tonic-gate /* 77c478bd9Sstevel@tonic-gate * Copyright (c) 1983 Regents of the University of California. 87c478bd9Sstevel@tonic-gate * All rights reserved. 97c478bd9Sstevel@tonic-gate * 107c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted 117c478bd9Sstevel@tonic-gate * provided that the above copyright notice and this paragraph are 127c478bd9Sstevel@tonic-gate * duplicated in all such forms and that any documentation, 137c478bd9Sstevel@tonic-gate * advertising materials, and other materials related to such 147c478bd9Sstevel@tonic-gate * distribution and use acknowledge that the software was developed 157c478bd9Sstevel@tonic-gate * by the University of California, Berkeley. The name of the 167c478bd9Sstevel@tonic-gate * University may not be used to endorse or promote products derived 177c478bd9Sstevel@tonic-gate * from this software without specific prior written permission. 187c478bd9Sstevel@tonic-gate */ 197c478bd9Sstevel@tonic-gate 207c478bd9Sstevel@tonic-gate #include "defs.h" 217c478bd9Sstevel@tonic-gate #include <signal.h> 227c478bd9Sstevel@tonic-gate #include <string.h> 237c478bd9Sstevel@tonic-gate #include <errno.h> 247c478bd9Sstevel@tonic-gate #include <limits.h> 257c478bd9Sstevel@tonic-gate #include <ctype.h> 267c478bd9Sstevel@tonic-gate #include <krb5defs.h> 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * If we want to write *to* the client rdist program, *from* the server 307c478bd9Sstevel@tonic-gate * side (server-side child `rdist -Server' process exec'ed off of in.rshd), 317c478bd9Sstevel@tonic-gate * we write to stdout/stderr, since there is a pipe connecting stdout/stderr 327c478bd9Sstevel@tonic-gate * to the outside world (which is why we use `wrem' and not `rem'). 337c478bd9Sstevel@tonic-gate */ 347c478bd9Sstevel@tonic-gate int wrem = 1; 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate #define ack() (void) write(wrem, "\0\n", 2) 377c478bd9Sstevel@tonic-gate #define err() (void) write(wrem, "\1\n", 2) 387c478bd9Sstevel@tonic-gate 397c478bd9Sstevel@tonic-gate /* 407c478bd9Sstevel@tonic-gate * Set when a desread() is reqd. in response() 417c478bd9Sstevel@tonic-gate */ 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate struct linkbuf *ihead; /* list of files with more than one link */ 447c478bd9Sstevel@tonic-gate char buf[RDIST_BUFSIZ]; /* general purpose buffer */ 457c478bd9Sstevel@tonic-gate char source[RDIST_BUFSIZ]; /* base source directory name */ 467c478bd9Sstevel@tonic-gate char destination[RDIST_BUFSIZ]; /* base destination directory name */ 477c478bd9Sstevel@tonic-gate char target[RDIST_BUFSIZ]; /* target/source directory name */ 487c478bd9Sstevel@tonic-gate char *tp; /* pointer to end of target name */ 497c478bd9Sstevel@tonic-gate char *Tdest; /* pointer to last T dest */ 507c478bd9Sstevel@tonic-gate int catname; /* cat name to target name */ 517c478bd9Sstevel@tonic-gate char *stp[32]; /* stack of saved tp's for directories */ 527c478bd9Sstevel@tonic-gate int oumask; /* old umask for creating files */ 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate extern FILE *lfp; /* log file for mailing changes */ 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate void cleanup(); 577c478bd9Sstevel@tonic-gate struct linkbuf *savelink(); 587c478bd9Sstevel@tonic-gate char *strsub(); 597c478bd9Sstevel@tonic-gate 60740638c8Sbw static void comment(char *s); 61740638c8Sbw static void note(); 62740638c8Sbw static void hardlink(char *cmd); 63740638c8Sbw void error(); 64740638c8Sbw void log(); 65740638c8Sbw static void recursive_remove(struct stat *stp); 66740638c8Sbw static void recvf(char *cmd, int type); 67740638c8Sbw static void query(char *name); 68740638c8Sbw static void sendf(char *rname, int opts); 69740638c8Sbw static void rmchk(int opts); 70740638c8Sbw static void dospecial(char *cmd); 71740638c8Sbw static void clean(char *cp); 72740638c8Sbw 737c478bd9Sstevel@tonic-gate /* 747c478bd9Sstevel@tonic-gate * Server routine to read requests and process them. 757c478bd9Sstevel@tonic-gate * Commands are: 767c478bd9Sstevel@tonic-gate * Tname - Transmit file if out of date 777c478bd9Sstevel@tonic-gate * Vname - Verify if file out of date or not 787c478bd9Sstevel@tonic-gate * Qname - Query if file exists. Return mtime & size if it does. 797c478bd9Sstevel@tonic-gate */ 80740638c8Sbw void 817c478bd9Sstevel@tonic-gate server() 827c478bd9Sstevel@tonic-gate { 837c478bd9Sstevel@tonic-gate char cmdbuf[RDIST_BUFSIZ]; 847c478bd9Sstevel@tonic-gate register char *cp; 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate signal(SIGHUP, cleanup); 877c478bd9Sstevel@tonic-gate signal(SIGINT, cleanup); 887c478bd9Sstevel@tonic-gate signal(SIGQUIT, cleanup); 897c478bd9Sstevel@tonic-gate signal(SIGTERM, cleanup); 907c478bd9Sstevel@tonic-gate signal(SIGPIPE, cleanup); 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate rem = 0; 937c478bd9Sstevel@tonic-gate oumask = umask(0); 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate (void) sprintf(buf, "V%d\n", VERSION); 967c478bd9Sstevel@tonic-gate (void) write(wrem, buf, strlen(buf)); 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate for (;;) { 997c478bd9Sstevel@tonic-gate cp = cmdbuf; 1007c478bd9Sstevel@tonic-gate if (read(rem, cp, 1) <= 0) 1017c478bd9Sstevel@tonic-gate return; 1027c478bd9Sstevel@tonic-gate if (*cp++ == '\n') { 1037c478bd9Sstevel@tonic-gate error("server: expected control record\n"); 1047c478bd9Sstevel@tonic-gate continue; 1057c478bd9Sstevel@tonic-gate } 1067c478bd9Sstevel@tonic-gate do { 1077c478bd9Sstevel@tonic-gate if (read(rem, cp, 1) != 1) 1087c478bd9Sstevel@tonic-gate cleanup(); 1097c478bd9Sstevel@tonic-gate } while (*cp++ != '\n' && cp < &cmdbuf[RDIST_BUFSIZ]); 1107c478bd9Sstevel@tonic-gate *--cp = '\0'; 1117c478bd9Sstevel@tonic-gate cp = cmdbuf; 1127c478bd9Sstevel@tonic-gate switch (*cp++) { 1137c478bd9Sstevel@tonic-gate case 'T': /* init target file/directory name */ 1147c478bd9Sstevel@tonic-gate catname = 1; /* target should be directory */ 1157c478bd9Sstevel@tonic-gate goto dotarget; 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate case 't': /* init target file/directory name */ 1187c478bd9Sstevel@tonic-gate catname = 0; 1197c478bd9Sstevel@tonic-gate dotarget: 1207c478bd9Sstevel@tonic-gate if (exptilde(target, sizeof (target), cp) == NULL) 1217c478bd9Sstevel@tonic-gate continue; 1227c478bd9Sstevel@tonic-gate tp = target; 1237c478bd9Sstevel@tonic-gate while (*tp) 1247c478bd9Sstevel@tonic-gate tp++; 1257c478bd9Sstevel@tonic-gate ack(); 1267c478bd9Sstevel@tonic-gate continue; 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate case 'R': /* Transfer a regular file. */ 1297c478bd9Sstevel@tonic-gate recvf(cp, S_IFREG); 1307c478bd9Sstevel@tonic-gate continue; 1317c478bd9Sstevel@tonic-gate 1327c478bd9Sstevel@tonic-gate case 'D': /* Transfer a directory. */ 1337c478bd9Sstevel@tonic-gate recvf(cp, S_IFDIR); 1347c478bd9Sstevel@tonic-gate continue; 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate case 'K': /* Transfer symbolic link. */ 1377c478bd9Sstevel@tonic-gate recvf(cp, S_IFLNK); 1387c478bd9Sstevel@tonic-gate continue; 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate case 'k': /* Transfer hard link. */ 1417c478bd9Sstevel@tonic-gate hardlink(cp); 1427c478bd9Sstevel@tonic-gate continue; 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate case 'E': /* End. (of directory) */ 1457c478bd9Sstevel@tonic-gate *tp = '\0'; 1467c478bd9Sstevel@tonic-gate if (catname <= 0) { 1477c478bd9Sstevel@tonic-gate error("server: too many 'E's\n"); 1487c478bd9Sstevel@tonic-gate continue; 1497c478bd9Sstevel@tonic-gate } 1507c478bd9Sstevel@tonic-gate tp = stp[--catname]; 1517c478bd9Sstevel@tonic-gate *tp = '\0'; 1527c478bd9Sstevel@tonic-gate ack(); 1537c478bd9Sstevel@tonic-gate continue; 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate case 'C': /* Clean. Cleanup a directory */ 1567c478bd9Sstevel@tonic-gate clean(cp); 1577c478bd9Sstevel@tonic-gate continue; 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate case 'Q': /* Query. Does the file/directory exist? */ 1607c478bd9Sstevel@tonic-gate query(cp); 1617c478bd9Sstevel@tonic-gate continue; 1627c478bd9Sstevel@tonic-gate 1637c478bd9Sstevel@tonic-gate case 'S': /* Special. Execute commands */ 1647c478bd9Sstevel@tonic-gate dospecial(cp); 1657c478bd9Sstevel@tonic-gate continue; 1667c478bd9Sstevel@tonic-gate 1677c478bd9Sstevel@tonic-gate #ifdef notdef 1687c478bd9Sstevel@tonic-gate /* 1697c478bd9Sstevel@tonic-gate * These entries are reserved but not currently used. 1707c478bd9Sstevel@tonic-gate * The intent is to allow remote hosts to have master copies. 1717c478bd9Sstevel@tonic-gate * Currently, only the host rdist runs on can have masters. 1727c478bd9Sstevel@tonic-gate */ 1737c478bd9Sstevel@tonic-gate case 'X': /* start a new list of files to exclude */ 1747c478bd9Sstevel@tonic-gate except = bp = NULL; 1757c478bd9Sstevel@tonic-gate case 'x': /* add name to list of files to exclude */ 1767c478bd9Sstevel@tonic-gate if (*cp == '\0') { 1777c478bd9Sstevel@tonic-gate ack(); 1787c478bd9Sstevel@tonic-gate continue; 1797c478bd9Sstevel@tonic-gate } 1807c478bd9Sstevel@tonic-gate if (*cp == '~') { 1817c478bd9Sstevel@tonic-gate if (exptilde(buf, sizeof (buf), cp) == NULL) 1827c478bd9Sstevel@tonic-gate continue; 1837c478bd9Sstevel@tonic-gate cp = buf; 1847c478bd9Sstevel@tonic-gate } 1857c478bd9Sstevel@tonic-gate if (bp == NULL) 1867c478bd9Sstevel@tonic-gate except = bp = expand(makeblock(NAME, cp), 1877c478bd9Sstevel@tonic-gate E_VARS); 1887c478bd9Sstevel@tonic-gate else 1897c478bd9Sstevel@tonic-gate bp->b_next = expand(makeblock(NAME, cp), 1907c478bd9Sstevel@tonic-gate E_VARS); 1917c478bd9Sstevel@tonic-gate while (bp->b_next != NULL) 1927c478bd9Sstevel@tonic-gate bp = bp->b_next; 1937c478bd9Sstevel@tonic-gate ack(); 1947c478bd9Sstevel@tonic-gate continue; 1957c478bd9Sstevel@tonic-gate 1967c478bd9Sstevel@tonic-gate case 'I': /* Install. Transfer file if out of date. */ 1977c478bd9Sstevel@tonic-gate opts = 0; 1987c478bd9Sstevel@tonic-gate while (*cp >= '0' && *cp <= '7') 1997c478bd9Sstevel@tonic-gate opts = (opts << 3) | (*cp++ - '0'); 2007c478bd9Sstevel@tonic-gate if (*cp++ != ' ') { 2017c478bd9Sstevel@tonic-gate error("server: options not delimited\n"); 2027c478bd9Sstevel@tonic-gate return; 2037c478bd9Sstevel@tonic-gate } 2047c478bd9Sstevel@tonic-gate install(cp, opts); 2057c478bd9Sstevel@tonic-gate continue; 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate case 'L': /* Log. save message in log file */ 2087c478bd9Sstevel@tonic-gate log(lfp, cp); 2097c478bd9Sstevel@tonic-gate continue; 2107c478bd9Sstevel@tonic-gate #endif 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate case '\1': 2137c478bd9Sstevel@tonic-gate nerrs++; 2147c478bd9Sstevel@tonic-gate continue; 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate case '\2': 2177c478bd9Sstevel@tonic-gate return; 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate default: 2207c478bd9Sstevel@tonic-gate error("server: unknown command '%s'\n", cp); 2217c478bd9Sstevel@tonic-gate case '\0': 2227c478bd9Sstevel@tonic-gate continue; 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate } 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate /* 2287c478bd9Sstevel@tonic-gate * Update the file(s) if they are different. 2297c478bd9Sstevel@tonic-gate * destdir = 1 if destination should be a directory 2307c478bd9Sstevel@tonic-gate * (i.e., more than one source is being copied to the same destination). 2317c478bd9Sstevel@tonic-gate */ 232740638c8Sbw void 2337c478bd9Sstevel@tonic-gate install(src, dest, destdir, opts) 2347c478bd9Sstevel@tonic-gate char *src, *dest; 2357c478bd9Sstevel@tonic-gate int destdir, opts; 2367c478bd9Sstevel@tonic-gate { 2377c478bd9Sstevel@tonic-gate char *rname; 2387c478bd9Sstevel@tonic-gate char destcopy[RDIST_BUFSIZ]; 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate if (dest == NULL) { 2417c478bd9Sstevel@tonic-gate opts &= ~WHOLE; /* WHOLE mode only useful if renaming */ 2427c478bd9Sstevel@tonic-gate dest = src; 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate if (nflag || debug) { 2467c478bd9Sstevel@tonic-gate printf("%s%s%s%s%s %s %s\n", opts & VERIFY ? "verify":"install", 2477c478bd9Sstevel@tonic-gate opts & WHOLE ? " -w" : "", 2487c478bd9Sstevel@tonic-gate opts & YOUNGER ? " -y" : "", 2497c478bd9Sstevel@tonic-gate opts & COMPARE ? " -b" : "", 2507c478bd9Sstevel@tonic-gate opts & REMOVE ? " -R" : "", src, dest); 2517c478bd9Sstevel@tonic-gate if (nflag) 2527c478bd9Sstevel@tonic-gate return; 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate rname = exptilde(target, sizeof (target), src); 2567c478bd9Sstevel@tonic-gate if (rname == NULL) 2577c478bd9Sstevel@tonic-gate return; 2587c478bd9Sstevel@tonic-gate tp = target; 2597c478bd9Sstevel@tonic-gate while (*tp) 2607c478bd9Sstevel@tonic-gate tp++; 2617c478bd9Sstevel@tonic-gate /* 2627c478bd9Sstevel@tonic-gate * If we are renaming a directory and we want to preserve 2637c478bd9Sstevel@tonic-gate * the directory heirarchy (-w), we must strip off the leading 2647c478bd9Sstevel@tonic-gate * directory name and preserve the rest. 2657c478bd9Sstevel@tonic-gate */ 2667c478bd9Sstevel@tonic-gate if (opts & WHOLE) { 2677c478bd9Sstevel@tonic-gate while (*rname == '/') 2687c478bd9Sstevel@tonic-gate rname++; 2697c478bd9Sstevel@tonic-gate destdir = 1; 2707c478bd9Sstevel@tonic-gate } else { 2717c478bd9Sstevel@tonic-gate rname = rindex(target, '/'); 2727c478bd9Sstevel@tonic-gate if (rname == NULL) 2737c478bd9Sstevel@tonic-gate rname = target; 2747c478bd9Sstevel@tonic-gate else 2757c478bd9Sstevel@tonic-gate rname++; 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate if (debug) 2787c478bd9Sstevel@tonic-gate printf("target = %s, rname = %s\n", target, rname); 2797c478bd9Sstevel@tonic-gate /* 2807c478bd9Sstevel@tonic-gate * Pass the destination file/directory name to remote. 2817c478bd9Sstevel@tonic-gate */ 2827c478bd9Sstevel@tonic-gate if (snprintf(buf, sizeof (buf), "%c%s\n", destdir ? 'T' : 't', dest) >= 2837c478bd9Sstevel@tonic-gate sizeof (buf)) { 2847c478bd9Sstevel@tonic-gate error("%s: Name too long\n", dest); 2857c478bd9Sstevel@tonic-gate return; 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate if (debug) 2887c478bd9Sstevel@tonic-gate printf("buf = %s", buf); 2897c478bd9Sstevel@tonic-gate (void) deswrite(rem, buf, strlen(buf), 0); 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate if (response() < 0) 2927c478bd9Sstevel@tonic-gate return; 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate strcpy(source, src); 2957c478bd9Sstevel@tonic-gate if (destdir) { 2967c478bd9Sstevel@tonic-gate strcpy(destcopy, dest); 2977c478bd9Sstevel@tonic-gate Tdest = destcopy; 2987c478bd9Sstevel@tonic-gate strcpy(destination, rname); 2997c478bd9Sstevel@tonic-gate } else { 3007c478bd9Sstevel@tonic-gate strcpy(destination, dest); 3017c478bd9Sstevel@tonic-gate } 3027c478bd9Sstevel@tonic-gate sendf(rname, opts); 3037c478bd9Sstevel@tonic-gate Tdest = 0; 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate #define protoname() (pw ? pw->pw_name : user) 3077c478bd9Sstevel@tonic-gate #define protogroup() (gr ? gr->gr_name : group) 3087c478bd9Sstevel@tonic-gate /* 3097c478bd9Sstevel@tonic-gate * Transfer the file or directory in target[]. 3107c478bd9Sstevel@tonic-gate * rname is the name of the file on the remote host. 3117c478bd9Sstevel@tonic-gate */ 312740638c8Sbw void 3137c478bd9Sstevel@tonic-gate sendf(rname, opts) 3147c478bd9Sstevel@tonic-gate char *rname; 3157c478bd9Sstevel@tonic-gate int opts; 3167c478bd9Sstevel@tonic-gate { 3177c478bd9Sstevel@tonic-gate register struct subcmd *sc; 3187c478bd9Sstevel@tonic-gate struct stat stb; 3197c478bd9Sstevel@tonic-gate int sizerr, f, u, len; 3207c478bd9Sstevel@tonic-gate off_t i; 3217c478bd9Sstevel@tonic-gate DIR *d; 3227c478bd9Sstevel@tonic-gate struct dirent *dp; 3237c478bd9Sstevel@tonic-gate char *otp, *cp; 3247c478bd9Sstevel@tonic-gate extern struct subcmd *subcmds; 3257c478bd9Sstevel@tonic-gate static char user[15], group[15]; 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate if (debug) 3287c478bd9Sstevel@tonic-gate printf("sendf(%s, %x%s)\n", rname, opts, printb(opts, OBITS)); 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate if (except(target)) 3317c478bd9Sstevel@tonic-gate return; 3327c478bd9Sstevel@tonic-gate if ((opts & FOLLOW ? stat(target, &stb) : lstat(target, &stb)) < 0) { 3337c478bd9Sstevel@tonic-gate error("%s: %s\n", target, strerror(errno)); 3347c478bd9Sstevel@tonic-gate return; 3357c478bd9Sstevel@tonic-gate } 3367c478bd9Sstevel@tonic-gate if (index(rname, '\n')) { 3377c478bd9Sstevel@tonic-gate error("file name '%s' contains an embedded newline - " 3387c478bd9Sstevel@tonic-gate "can't update\n", rname); 3397c478bd9Sstevel@tonic-gate return; 3407c478bd9Sstevel@tonic-gate } 3417c478bd9Sstevel@tonic-gate if ((u = update(rname, opts, &stb)) == 0) { 3427c478bd9Sstevel@tonic-gate if ((stb.st_mode & S_IFMT) == S_IFREG && stb.st_nlink > 1) 3437c478bd9Sstevel@tonic-gate (void) savelink(&stb, opts); 3447c478bd9Sstevel@tonic-gate return; 3457c478bd9Sstevel@tonic-gate } 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate if (pw == NULL || pw->pw_uid != stb.st_uid) 3487c478bd9Sstevel@tonic-gate if ((pw = getpwuid(stb.st_uid)) == NULL) { 3497c478bd9Sstevel@tonic-gate log(lfp, "%s: no password entry for uid %d \n", 3507c478bd9Sstevel@tonic-gate target, stb.st_uid); 3517c478bd9Sstevel@tonic-gate pw = NULL; 3527c478bd9Sstevel@tonic-gate sprintf(user, ":%d", stb.st_uid); 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate if (gr == NULL || gr->gr_gid != stb.st_gid) 3557c478bd9Sstevel@tonic-gate if ((gr = getgrgid(stb.st_gid)) == NULL) { 3567c478bd9Sstevel@tonic-gate log(lfp, "%s: no name for group %d\n", 3577c478bd9Sstevel@tonic-gate target, stb.st_gid); 3587c478bd9Sstevel@tonic-gate gr = NULL; 3597c478bd9Sstevel@tonic-gate sprintf(group, ":%d", stb.st_gid); 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate if (u == 1) { 3627c478bd9Sstevel@tonic-gate if (opts & VERIFY) { 3637c478bd9Sstevel@tonic-gate log(lfp, "need to install: %s\n", target); 3647c478bd9Sstevel@tonic-gate goto dospecial; 3657c478bd9Sstevel@tonic-gate } 3667c478bd9Sstevel@tonic-gate log(lfp, "installing: %s\n", target); 3677c478bd9Sstevel@tonic-gate opts &= ~(COMPARE|REMOVE); 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate switch (stb.st_mode & S_IFMT) { 3717c478bd9Sstevel@tonic-gate case S_IFDIR: 3727c478bd9Sstevel@tonic-gate if ((d = opendir(target)) == NULL) { 3737c478bd9Sstevel@tonic-gate error("%s: %s\n", target, strerror(errno)); 3747c478bd9Sstevel@tonic-gate return; 3757c478bd9Sstevel@tonic-gate } 3767c478bd9Sstevel@tonic-gate if (snprintf(buf, sizeof (buf), "D%o %04o 0 0 %s %s %s\n", 3777c478bd9Sstevel@tonic-gate opts, stb.st_mode & 07777, protoname(), protogroup(), 3787c478bd9Sstevel@tonic-gate rname) >= sizeof (buf)) { 3797c478bd9Sstevel@tonic-gate error("%s: Name too long\n", rname); 3807c478bd9Sstevel@tonic-gate closedir(d); 3817c478bd9Sstevel@tonic-gate return; 3827c478bd9Sstevel@tonic-gate } 3837c478bd9Sstevel@tonic-gate if (debug) 3847c478bd9Sstevel@tonic-gate printf("buf = %s", buf); 3857c478bd9Sstevel@tonic-gate (void) deswrite(rem, buf, strlen(buf), 0); 3867c478bd9Sstevel@tonic-gate if (response() < 0) { 3877c478bd9Sstevel@tonic-gate closedir(d); 3887c478bd9Sstevel@tonic-gate return; 3897c478bd9Sstevel@tonic-gate } 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate if (opts & REMOVE) 3927c478bd9Sstevel@tonic-gate rmchk(opts); 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate otp = tp; 3957c478bd9Sstevel@tonic-gate len = tp - target; 3967c478bd9Sstevel@tonic-gate while (dp = readdir(d)) { 3977c478bd9Sstevel@tonic-gate if ((strcmp(dp->d_name, ".") == 0)|| 3987c478bd9Sstevel@tonic-gate (strcmp(dp->d_name, "..") == 0)) 3997c478bd9Sstevel@tonic-gate continue; 4007c478bd9Sstevel@tonic-gate if ((int)(len + 1 + strlen(dp->d_name)) >= 4017c478bd9Sstevel@tonic-gate (int)(RDIST_BUFSIZ - 1)) { 4027c478bd9Sstevel@tonic-gate error("%.*s/%s: Name too long\n", len, target, 4037c478bd9Sstevel@tonic-gate dp->d_name); 4047c478bd9Sstevel@tonic-gate continue; 4057c478bd9Sstevel@tonic-gate } 4067c478bd9Sstevel@tonic-gate tp = otp; 4077c478bd9Sstevel@tonic-gate *tp++ = '/'; 4087c478bd9Sstevel@tonic-gate cp = dp->d_name; 4097c478bd9Sstevel@tonic-gate while (*tp++ = *cp++) 4107c478bd9Sstevel@tonic-gate ; 4117c478bd9Sstevel@tonic-gate tp--; 4127c478bd9Sstevel@tonic-gate sendf(dp->d_name, opts); 4137c478bd9Sstevel@tonic-gate } 4147c478bd9Sstevel@tonic-gate closedir(d); 4157c478bd9Sstevel@tonic-gate (void) deswrite(rem, "E\n", 2, 0); 4167c478bd9Sstevel@tonic-gate (void) response(); 4177c478bd9Sstevel@tonic-gate tp = otp; 4187c478bd9Sstevel@tonic-gate *tp = '\0'; 4197c478bd9Sstevel@tonic-gate return; 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate case S_IFLNK: 4227c478bd9Sstevel@tonic-gate if (u != 1) 4237c478bd9Sstevel@tonic-gate opts |= COMPARE; 4247c478bd9Sstevel@tonic-gate if (stb.st_nlink > 1) { 4257c478bd9Sstevel@tonic-gate struct linkbuf *lp; 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate if ((lp = savelink(&stb, opts)) != NULL) { 4287c478bd9Sstevel@tonic-gate /* install link */ 4297c478bd9Sstevel@tonic-gate if (*lp->target == 0) 4307c478bd9Sstevel@tonic-gate len = snprintf(buf, sizeof (buf), 4317c478bd9Sstevel@tonic-gate "k%o %s %s\n", opts, lp->pathname, 4327c478bd9Sstevel@tonic-gate rname); 4337c478bd9Sstevel@tonic-gate else 4347c478bd9Sstevel@tonic-gate len = snprintf(buf, sizeof (buf), 4357c478bd9Sstevel@tonic-gate "k%o %s/%s %s\n", opts, lp->target, 4367c478bd9Sstevel@tonic-gate lp->pathname, rname); 4377c478bd9Sstevel@tonic-gate if (len >= sizeof (buf)) { 4387c478bd9Sstevel@tonic-gate error("%s: Name too long\n", rname); 4397c478bd9Sstevel@tonic-gate return; 4407c478bd9Sstevel@tonic-gate } 4417c478bd9Sstevel@tonic-gate if (debug) 4427c478bd9Sstevel@tonic-gate printf("buf = %s", buf); 4437c478bd9Sstevel@tonic-gate (void) deswrite(rem, buf, strlen(buf), 0); 4447c478bd9Sstevel@tonic-gate (void) response(); 4457c478bd9Sstevel@tonic-gate return; 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate } 4487c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "K%o %o %ld %ld %s %s %s\n", 4497c478bd9Sstevel@tonic-gate opts, stb.st_mode & 07777, stb.st_size, stb.st_mtime, 4507c478bd9Sstevel@tonic-gate protoname(), protogroup(), rname); 4517c478bd9Sstevel@tonic-gate if (debug) 4527c478bd9Sstevel@tonic-gate printf("buf = %s", buf); 4537c478bd9Sstevel@tonic-gate (void) deswrite(rem, buf, strlen(buf), 0); 4547c478bd9Sstevel@tonic-gate if (response() < 0) 4557c478bd9Sstevel@tonic-gate return; 4567c478bd9Sstevel@tonic-gate sizerr = (readlink(target, buf, RDIST_BUFSIZ) != stb.st_size); 4577c478bd9Sstevel@tonic-gate (void) deswrite(rem, buf, stb.st_size, 0); 4587c478bd9Sstevel@tonic-gate if (debug) 4597c478bd9Sstevel@tonic-gate printf("readlink = %.*s\n", (int)stb.st_size, buf); 4607c478bd9Sstevel@tonic-gate goto done; 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate case S_IFREG: 4637c478bd9Sstevel@tonic-gate break; 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate default: 4667c478bd9Sstevel@tonic-gate error("%s: not a file or directory\n", target); 4677c478bd9Sstevel@tonic-gate return; 4687c478bd9Sstevel@tonic-gate } 4697c478bd9Sstevel@tonic-gate 4707c478bd9Sstevel@tonic-gate if (u == 2) { 4717c478bd9Sstevel@tonic-gate if (opts & VERIFY) { 4727c478bd9Sstevel@tonic-gate log(lfp, "need to update: %s\n", target); 4737c478bd9Sstevel@tonic-gate goto dospecial; 4747c478bd9Sstevel@tonic-gate } 4757c478bd9Sstevel@tonic-gate log(lfp, "updating: %s\n", target); 4767c478bd9Sstevel@tonic-gate } 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate if (stb.st_nlink > 1) { 4797c478bd9Sstevel@tonic-gate struct linkbuf *lp; 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate if ((lp = savelink(&stb, opts)) != NULL) { 4827c478bd9Sstevel@tonic-gate /* install link */ 4837c478bd9Sstevel@tonic-gate if (*lp->target == 0) 4847c478bd9Sstevel@tonic-gate len = snprintf(buf, sizeof (buf), "k%o %s %s\n", 4857c478bd9Sstevel@tonic-gate opts, lp->pathname, rname); 4867c478bd9Sstevel@tonic-gate else 4877c478bd9Sstevel@tonic-gate len = snprintf(buf, sizeof (buf), 4887c478bd9Sstevel@tonic-gate "k%o %s/%s %s\n", opts, lp->target, 4897c478bd9Sstevel@tonic-gate lp->pathname, rname); 4907c478bd9Sstevel@tonic-gate if (len >= sizeof (buf)) { 4917c478bd9Sstevel@tonic-gate error("%s: Name too long\n", rname); 4927c478bd9Sstevel@tonic-gate return; 4937c478bd9Sstevel@tonic-gate } 4947c478bd9Sstevel@tonic-gate if (debug) 4957c478bd9Sstevel@tonic-gate printf("buf = %s", buf); 4967c478bd9Sstevel@tonic-gate (void) deswrite(rem, buf, strlen(buf), 0); 4977c478bd9Sstevel@tonic-gate (void) response(); 4987c478bd9Sstevel@tonic-gate return; 4997c478bd9Sstevel@tonic-gate } 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate if ((f = open(target, 0)) < 0) { 5037c478bd9Sstevel@tonic-gate error("%s: %s\n", target, strerror(errno)); 5047c478bd9Sstevel@tonic-gate return; 5057c478bd9Sstevel@tonic-gate } 5067c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "R%o %o %ld %ld %s %s %s\n", opts, 5077c478bd9Sstevel@tonic-gate stb.st_mode & 07777, stb.st_size, stb.st_mtime, 5087c478bd9Sstevel@tonic-gate protoname(), protogroup(), rname); 5097c478bd9Sstevel@tonic-gate if (debug) 5107c478bd9Sstevel@tonic-gate printf("buf = %s", buf); 5117c478bd9Sstevel@tonic-gate (void) deswrite(rem, buf, strlen(buf), 0); 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate if (response() < 0) { 5147c478bd9Sstevel@tonic-gate (void) close(f); 5157c478bd9Sstevel@tonic-gate return; 5167c478bd9Sstevel@tonic-gate } 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate sizerr = 0; 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate for (i = 0; i < stb.st_size; i += RDIST_BUFSIZ) { 5217c478bd9Sstevel@tonic-gate int amt = RDIST_BUFSIZ; 5227c478bd9Sstevel@tonic-gate if (i + amt > stb.st_size) 5237c478bd9Sstevel@tonic-gate amt = stb.st_size - i; 5247c478bd9Sstevel@tonic-gate if (sizerr == 0 && read(f, buf, amt) != amt) 5257c478bd9Sstevel@tonic-gate sizerr = 1; 5267c478bd9Sstevel@tonic-gate (void) deswrite(rem, buf, amt, 0); 5277c478bd9Sstevel@tonic-gate } 5287c478bd9Sstevel@tonic-gate (void) close(f); 5297c478bd9Sstevel@tonic-gate done: 5307c478bd9Sstevel@tonic-gate if (sizerr) { 5317c478bd9Sstevel@tonic-gate error("%s: file changed size\n", target); 5327c478bd9Sstevel@tonic-gate (void) deswrite(rem, "\1\n", 2, 0); 5337c478bd9Sstevel@tonic-gate } else 5347c478bd9Sstevel@tonic-gate (void) deswrite(rem, "\0\n", 2, 0); 5357c478bd9Sstevel@tonic-gate f = response(); 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate if (f < 0 || f == 0 && (opts & COMPARE)) 5387c478bd9Sstevel@tonic-gate return; 5397c478bd9Sstevel@tonic-gate dospecial: 5407c478bd9Sstevel@tonic-gate for (sc = subcmds; sc != NULL; sc = sc->sc_next) { 5417c478bd9Sstevel@tonic-gate if (sc->sc_type != SPECIAL) 5427c478bd9Sstevel@tonic-gate continue; 5437c478bd9Sstevel@tonic-gate if (sc->sc_args != NULL && !inlist(sc->sc_args, target)) 5447c478bd9Sstevel@tonic-gate continue; 5457c478bd9Sstevel@tonic-gate log(lfp, "special \"%s\"\n", sc->sc_name); 5467c478bd9Sstevel@tonic-gate if (opts & VERIFY) 5477c478bd9Sstevel@tonic-gate continue; 5487c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "SFILE=%s;%s\n", target, 5497c478bd9Sstevel@tonic-gate sc->sc_name); 5507c478bd9Sstevel@tonic-gate if (debug) 5517c478bd9Sstevel@tonic-gate printf("buf = %s", buf); 5527c478bd9Sstevel@tonic-gate (void) deswrite(rem, buf, strlen(buf), 0); 5537c478bd9Sstevel@tonic-gate while (response() > 0) 5547c478bd9Sstevel@tonic-gate ; 5557c478bd9Sstevel@tonic-gate } 5567c478bd9Sstevel@tonic-gate } 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate struct linkbuf * 5597c478bd9Sstevel@tonic-gate savelink(stp, opts) 5607c478bd9Sstevel@tonic-gate struct stat *stp; 5617c478bd9Sstevel@tonic-gate int opts; 5627c478bd9Sstevel@tonic-gate { 5637c478bd9Sstevel@tonic-gate struct linkbuf *lp; 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate for (lp = ihead; lp != NULL; lp = lp->nextp) 5667c478bd9Sstevel@tonic-gate if (lp->inum == stp->st_ino && lp->devnum == stp->st_dev) { 5677c478bd9Sstevel@tonic-gate lp->count--; 5687c478bd9Sstevel@tonic-gate return (lp); 5697c478bd9Sstevel@tonic-gate } 5707c478bd9Sstevel@tonic-gate lp = (struct linkbuf *)malloc(sizeof (*lp)); 5717c478bd9Sstevel@tonic-gate if (lp == NULL) 5727c478bd9Sstevel@tonic-gate log(lfp, "out of memory, link information lost\n"); 5737c478bd9Sstevel@tonic-gate else { 5747c478bd9Sstevel@tonic-gate lp->nextp = ihead; 5757c478bd9Sstevel@tonic-gate ihead = lp; 5767c478bd9Sstevel@tonic-gate lp->inum = stp->st_ino; 5777c478bd9Sstevel@tonic-gate lp->devnum = stp->st_dev; 5787c478bd9Sstevel@tonic-gate lp->count = stp->st_nlink - 1; 579*56fbdff6SChandan 580*56fbdff6SChandan if (strlcpy(lp->pathname, 581*56fbdff6SChandan opts & WHOLE ? target : strsub(source, destination, target), 582*56fbdff6SChandan sizeof (lp->pathname)) >= sizeof (lp->pathname)) { 583*56fbdff6SChandan error("%s: target name too long\n", target); 584*56fbdff6SChandan } 585*56fbdff6SChandan 586*56fbdff6SChandan if (Tdest) { 587*56fbdff6SChandan if (strlcpy(lp->target, Tdest, 588*56fbdff6SChandan sizeof (lp->target)) >= sizeof (lp->target)) 589*56fbdff6SChandan error("%s: target name too long\n", Tdest); 590*56fbdff6SChandan } else 5917c478bd9Sstevel@tonic-gate *lp->target = 0; 5927c478bd9Sstevel@tonic-gate } 5937c478bd9Sstevel@tonic-gate return (NULL); 5947c478bd9Sstevel@tonic-gate } 5957c478bd9Sstevel@tonic-gate 5967c478bd9Sstevel@tonic-gate /* 5977c478bd9Sstevel@tonic-gate * Check to see if file needs to be updated on the remote machine. 5987c478bd9Sstevel@tonic-gate * Returns 0 if no update, 1 if remote doesn't exist, 2 if out of date 5997c478bd9Sstevel@tonic-gate * and 3 if comparing binaries to determine if out of date. 6007c478bd9Sstevel@tonic-gate */ 601740638c8Sbw int 6027c478bd9Sstevel@tonic-gate update(rname, opts, stp) 6037c478bd9Sstevel@tonic-gate char *rname; 6047c478bd9Sstevel@tonic-gate int opts; 6057c478bd9Sstevel@tonic-gate struct stat *stp; 6067c478bd9Sstevel@tonic-gate { 6077c478bd9Sstevel@tonic-gate register char *cp, *s; 6087c478bd9Sstevel@tonic-gate register off_t size; 6097c478bd9Sstevel@tonic-gate register time_t mtime; 6107c478bd9Sstevel@tonic-gate 6117c478bd9Sstevel@tonic-gate if (debug) 6127c478bd9Sstevel@tonic-gate printf("update(%s, %x%s, %x)\n", rname, opts, 6137c478bd9Sstevel@tonic-gate printb(opts, OBITS), stp); 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate /* 6167c478bd9Sstevel@tonic-gate * Check to see if the file exists on the remote machine. 6177c478bd9Sstevel@tonic-gate */ 6187c478bd9Sstevel@tonic-gate if (snprintf(buf, sizeof (buf), "Q%s\n", rname) >= sizeof (buf)) { 6197c478bd9Sstevel@tonic-gate error("%s: Name too long\n", rname); 6207c478bd9Sstevel@tonic-gate return (0); 6217c478bd9Sstevel@tonic-gate } 6227c478bd9Sstevel@tonic-gate if (debug) 6237c478bd9Sstevel@tonic-gate printf("buf = %s", buf); 6247c478bd9Sstevel@tonic-gate (void) deswrite(rem, buf, strlen(buf), 0); 6257c478bd9Sstevel@tonic-gate again: 6267c478bd9Sstevel@tonic-gate cp = s = buf; 6277c478bd9Sstevel@tonic-gate more: 6287c478bd9Sstevel@tonic-gate do { 6297c478bd9Sstevel@tonic-gate if (desread(rem, cp, 1, 0) != 1) 6307c478bd9Sstevel@tonic-gate lostconn(); 6317c478bd9Sstevel@tonic-gate } while (*cp++ != '\n' && cp < &buf[RDIST_BUFSIZ]); 6327c478bd9Sstevel@tonic-gate 6337c478bd9Sstevel@tonic-gate if (cp < &buf[RDIST_BUFSIZ]) 6347c478bd9Sstevel@tonic-gate *cp = '\0'; 6357c478bd9Sstevel@tonic-gate if (debug) { 6367c478bd9Sstevel@tonic-gate printf("update reply: "); 6377c478bd9Sstevel@tonic-gate switch (*s) { 6387c478bd9Sstevel@tonic-gate case 'Y': 6397c478bd9Sstevel@tonic-gate case 'N': 6407c478bd9Sstevel@tonic-gate putchar(*s); 6417c478bd9Sstevel@tonic-gate break; 6427c478bd9Sstevel@tonic-gate default: 6437c478bd9Sstevel@tonic-gate if (iscntrl(*s)) { 6447c478bd9Sstevel@tonic-gate putchar('^'); 6457c478bd9Sstevel@tonic-gate putchar('A' + *s - 1); 6467c478bd9Sstevel@tonic-gate } else 6477c478bd9Sstevel@tonic-gate printf("%#x", *s & 0xff); 6487c478bd9Sstevel@tonic-gate break; 6497c478bd9Sstevel@tonic-gate } 6507c478bd9Sstevel@tonic-gate printf("%s", &s[1]); 6517c478bd9Sstevel@tonic-gate } 6527c478bd9Sstevel@tonic-gate 6537c478bd9Sstevel@tonic-gate switch (*s++) { 6547c478bd9Sstevel@tonic-gate case 'Y': 6557c478bd9Sstevel@tonic-gate break; 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate case 'N': /* file doesn't exist so install it */ 6587c478bd9Sstevel@tonic-gate return (1); 6597c478bd9Sstevel@tonic-gate 6607c478bd9Sstevel@tonic-gate case '\1': 6617c478bd9Sstevel@tonic-gate nerrs++; 6627c478bd9Sstevel@tonic-gate if (*s != '\n') { 6637c478bd9Sstevel@tonic-gate if (!iamremote) { 6647c478bd9Sstevel@tonic-gate fflush(stdout); 6657c478bd9Sstevel@tonic-gate (void) write(2, s, cp - s); 6667c478bd9Sstevel@tonic-gate } 6677c478bd9Sstevel@tonic-gate if (lfp != NULL) 6687c478bd9Sstevel@tonic-gate (void) fwrite(s, 1, cp - s, lfp); 6697c478bd9Sstevel@tonic-gate } 6707c478bd9Sstevel@tonic-gate if (cp == &buf[RDIST_BUFSIZ] && *(cp - 1) != '\n') { 6717c478bd9Sstevel@tonic-gate /* preserve status code */ 6727c478bd9Sstevel@tonic-gate cp = s; 6737c478bd9Sstevel@tonic-gate s = buf; 6747c478bd9Sstevel@tonic-gate goto more; 6757c478bd9Sstevel@tonic-gate } 6767c478bd9Sstevel@tonic-gate return (0); 6777c478bd9Sstevel@tonic-gate 6787c478bd9Sstevel@tonic-gate case '\3': 6797c478bd9Sstevel@tonic-gate *--cp = '\0'; 6807c478bd9Sstevel@tonic-gate if (lfp != NULL) 6817c478bd9Sstevel@tonic-gate log(lfp, "update: note: %s\n", s); 6827c478bd9Sstevel@tonic-gate goto again; 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate default: 6857c478bd9Sstevel@tonic-gate *--cp = '\0'; 6867c478bd9Sstevel@tonic-gate error("update: unexpected response '%s'\n", s); 6877c478bd9Sstevel@tonic-gate return (0); 6887c478bd9Sstevel@tonic-gate } 6897c478bd9Sstevel@tonic-gate 6907c478bd9Sstevel@tonic-gate if (*s == '\n') 6917c478bd9Sstevel@tonic-gate return (2); 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate if (opts & COMPARE) 6947c478bd9Sstevel@tonic-gate return (3); 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate size = 0; 6977c478bd9Sstevel@tonic-gate while (isdigit(*s)) 6987c478bd9Sstevel@tonic-gate size = size * 10 + (*s++ - '0'); 6997c478bd9Sstevel@tonic-gate if (*s++ != ' ') { 7007c478bd9Sstevel@tonic-gate error("update: size not delimited\n"); 7017c478bd9Sstevel@tonic-gate return (0); 7027c478bd9Sstevel@tonic-gate } 7037c478bd9Sstevel@tonic-gate mtime = 0; 7047c478bd9Sstevel@tonic-gate while (isdigit(*s)) 7057c478bd9Sstevel@tonic-gate mtime = mtime * 10 + (*s++ - '0'); 7067c478bd9Sstevel@tonic-gate if (*s != '\n') { 7077c478bd9Sstevel@tonic-gate error("update: mtime not delimited\n"); 7087c478bd9Sstevel@tonic-gate return (0); 7097c478bd9Sstevel@tonic-gate } 7107c478bd9Sstevel@tonic-gate /* 7117c478bd9Sstevel@tonic-gate * File needs to be updated? 7127c478bd9Sstevel@tonic-gate */ 7137c478bd9Sstevel@tonic-gate if (opts & YOUNGER) { 7147c478bd9Sstevel@tonic-gate if (stp->st_mtime == mtime) 7157c478bd9Sstevel@tonic-gate return (0); 7167c478bd9Sstevel@tonic-gate if (stp->st_mtime < mtime) { 7177c478bd9Sstevel@tonic-gate log(lfp, "Warning: %s: remote copy is newer\n", target); 7187c478bd9Sstevel@tonic-gate return (0); 7197c478bd9Sstevel@tonic-gate } 7207c478bd9Sstevel@tonic-gate } else if (stp->st_mtime == mtime && stp->st_size == size) 7217c478bd9Sstevel@tonic-gate return (0); 7227c478bd9Sstevel@tonic-gate return (2); 7237c478bd9Sstevel@tonic-gate } 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate /* 7267c478bd9Sstevel@tonic-gate * Query. Check to see if file exists. Return one of the following: 7277c478bd9Sstevel@tonic-gate * N\n - doesn't exist 7287c478bd9Sstevel@tonic-gate * Ysize mtime\n - exists and its a regular file (size & mtime of file) 7297c478bd9Sstevel@tonic-gate * Y\n - exists and its a directory or symbolic link 7307c478bd9Sstevel@tonic-gate * ^Aerror message\n 7317c478bd9Sstevel@tonic-gate */ 732740638c8Sbw static void 7337c478bd9Sstevel@tonic-gate query(name) 7347c478bd9Sstevel@tonic-gate char *name; 7357c478bd9Sstevel@tonic-gate { 7367c478bd9Sstevel@tonic-gate struct stat stb; 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate if (catname) { 7397c478bd9Sstevel@tonic-gate if (sizeof (target) - (tp - target) >= strlen(name) + 2) { 7407c478bd9Sstevel@tonic-gate (void) sprintf(tp, "/%s", name); 7417c478bd9Sstevel@tonic-gate } else { 7427c478bd9Sstevel@tonic-gate error("%.*s/%s: Name too long\n", tp - target, 7437c478bd9Sstevel@tonic-gate target, name); 7447c478bd9Sstevel@tonic-gate return; 7457c478bd9Sstevel@tonic-gate } 7467c478bd9Sstevel@tonic-gate } 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate if (lstat(target, &stb) < 0) { 7497c478bd9Sstevel@tonic-gate if (errno == ENOENT) 7507c478bd9Sstevel@tonic-gate (void) write(wrem, "N\n", 2); 7517c478bd9Sstevel@tonic-gate else 7527c478bd9Sstevel@tonic-gate error("%s:%s: %s\n", host, target, strerror(errno)); 7537c478bd9Sstevel@tonic-gate *tp = '\0'; 7547c478bd9Sstevel@tonic-gate return; 7557c478bd9Sstevel@tonic-gate } 7567c478bd9Sstevel@tonic-gate 7577c478bd9Sstevel@tonic-gate switch (stb.st_mode & S_IFMT) { 7587c478bd9Sstevel@tonic-gate case S_IFREG: 7597c478bd9Sstevel@tonic-gate (void) sprintf(buf, "Y%ld %ld\n", stb.st_size, stb.st_mtime); 7607c478bd9Sstevel@tonic-gate (void) write(wrem, buf, strlen(buf)); 7617c478bd9Sstevel@tonic-gate break; 7627c478bd9Sstevel@tonic-gate 7637c478bd9Sstevel@tonic-gate case S_IFLNK: 7647c478bd9Sstevel@tonic-gate case S_IFDIR: 7657c478bd9Sstevel@tonic-gate (void) write(wrem, "Y\n", 2); 7667c478bd9Sstevel@tonic-gate break; 7677c478bd9Sstevel@tonic-gate 7687c478bd9Sstevel@tonic-gate default: 7697c478bd9Sstevel@tonic-gate error("%s: not a file or directory\n", name); 7707c478bd9Sstevel@tonic-gate break; 7717c478bd9Sstevel@tonic-gate } 7727c478bd9Sstevel@tonic-gate *tp = '\0'; 7737c478bd9Sstevel@tonic-gate } 7747c478bd9Sstevel@tonic-gate 775740638c8Sbw static void 7767c478bd9Sstevel@tonic-gate recvf(cmd, type) 7777c478bd9Sstevel@tonic-gate char *cmd; 7787c478bd9Sstevel@tonic-gate int type; 7797c478bd9Sstevel@tonic-gate { 7807c478bd9Sstevel@tonic-gate register char *cp; 7817c478bd9Sstevel@tonic-gate int f, mode, opts, wrerr, olderrno; 7827c478bd9Sstevel@tonic-gate off_t i, size; 7837c478bd9Sstevel@tonic-gate time_t mtime; 7847c478bd9Sstevel@tonic-gate struct stat stb; 7857c478bd9Sstevel@tonic-gate struct timeval tvp[2]; 7867c478bd9Sstevel@tonic-gate char *owner, *group; 7877c478bd9Sstevel@tonic-gate char new[RDIST_BUFSIZ]; 7887c478bd9Sstevel@tonic-gate extern char *tmpname; 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate cp = cmd; 7917c478bd9Sstevel@tonic-gate opts = 0; 7927c478bd9Sstevel@tonic-gate while (*cp >= '0' && *cp <= '7') 7937c478bd9Sstevel@tonic-gate opts = (opts << 3) | (*cp++ - '0'); 7947c478bd9Sstevel@tonic-gate if (*cp++ != ' ') { 7957c478bd9Sstevel@tonic-gate error("recvf: options not delimited\n"); 7967c478bd9Sstevel@tonic-gate return; 7977c478bd9Sstevel@tonic-gate } 7987c478bd9Sstevel@tonic-gate mode = 0; 7997c478bd9Sstevel@tonic-gate while (*cp >= '0' && *cp <= '7') 8007c478bd9Sstevel@tonic-gate mode = (mode << 3) | (*cp++ - '0'); 8017c478bd9Sstevel@tonic-gate if (*cp++ != ' ') { 8027c478bd9Sstevel@tonic-gate error("recvf: mode not delimited\n"); 8037c478bd9Sstevel@tonic-gate return; 8047c478bd9Sstevel@tonic-gate } 8057c478bd9Sstevel@tonic-gate size = 0; 8067c478bd9Sstevel@tonic-gate while (isdigit(*cp)) 8077c478bd9Sstevel@tonic-gate size = size * 10 + (*cp++ - '0'); 8087c478bd9Sstevel@tonic-gate if (*cp++ != ' ') { 8097c478bd9Sstevel@tonic-gate error("recvf: size not delimited\n"); 8107c478bd9Sstevel@tonic-gate return; 8117c478bd9Sstevel@tonic-gate } 8127c478bd9Sstevel@tonic-gate mtime = 0; 8137c478bd9Sstevel@tonic-gate while (isdigit(*cp)) 8147c478bd9Sstevel@tonic-gate mtime = mtime * 10 + (*cp++ - '0'); 8157c478bd9Sstevel@tonic-gate if (*cp++ != ' ') { 8167c478bd9Sstevel@tonic-gate error("recvf: mtime not delimited\n"); 8177c478bd9Sstevel@tonic-gate return; 8187c478bd9Sstevel@tonic-gate } 8197c478bd9Sstevel@tonic-gate owner = cp; 8207c478bd9Sstevel@tonic-gate while (*cp && *cp != ' ') 8217c478bd9Sstevel@tonic-gate cp++; 8227c478bd9Sstevel@tonic-gate if (*cp != ' ') { 8237c478bd9Sstevel@tonic-gate error("recvf: owner name not delimited\n"); 8247c478bd9Sstevel@tonic-gate return; 8257c478bd9Sstevel@tonic-gate } 8267c478bd9Sstevel@tonic-gate *cp++ = '\0'; 8277c478bd9Sstevel@tonic-gate group = cp; 8287c478bd9Sstevel@tonic-gate while (*cp && *cp != ' ') 8297c478bd9Sstevel@tonic-gate cp++; 8307c478bd9Sstevel@tonic-gate if (*cp != ' ') { 8317c478bd9Sstevel@tonic-gate error("recvf: group name not delimited\n"); 8327c478bd9Sstevel@tonic-gate return; 8337c478bd9Sstevel@tonic-gate } 8347c478bd9Sstevel@tonic-gate *cp++ = '\0'; 8357c478bd9Sstevel@tonic-gate 8367c478bd9Sstevel@tonic-gate if (type == S_IFDIR) { 8377c478bd9Sstevel@tonic-gate int isdot; 8387c478bd9Sstevel@tonic-gate 8397c478bd9Sstevel@tonic-gate if (strcmp(cp, ".") == 0) 8407c478bd9Sstevel@tonic-gate isdot = 1; 8417c478bd9Sstevel@tonic-gate else 8427c478bd9Sstevel@tonic-gate isdot = 0; 8437c478bd9Sstevel@tonic-gate if (catname >= sizeof (stp) / sizeof (stp[0])) { 8447c478bd9Sstevel@tonic-gate error("%s:%s: too many directory levels\n", 8457c478bd9Sstevel@tonic-gate host, target); 8467c478bd9Sstevel@tonic-gate return; 8477c478bd9Sstevel@tonic-gate } 8487c478bd9Sstevel@tonic-gate stp[catname] = tp; 8497c478bd9Sstevel@tonic-gate if (catname++) { 8507c478bd9Sstevel@tonic-gate *tp++ = '/'; 8517c478bd9Sstevel@tonic-gate while (*tp++ = *cp++) 8527c478bd9Sstevel@tonic-gate ; 8537c478bd9Sstevel@tonic-gate tp--; 8547c478bd9Sstevel@tonic-gate } 8557c478bd9Sstevel@tonic-gate if (opts & VERIFY) { 8567c478bd9Sstevel@tonic-gate ack(); 8577c478bd9Sstevel@tonic-gate return; 8587c478bd9Sstevel@tonic-gate } 8597c478bd9Sstevel@tonic-gate if (lstat(target, &stb) == 0) { 8607c478bd9Sstevel@tonic-gate if (ISDIR(stb.st_mode)) { 8617c478bd9Sstevel@tonic-gate if ((stb.st_mode & 07777) == mode) { 8627c478bd9Sstevel@tonic-gate ack(); 8637c478bd9Sstevel@tonic-gate return; 8647c478bd9Sstevel@tonic-gate } 8657c478bd9Sstevel@tonic-gate sendrem("%s: Warning: remote mode %o != " 8667c478bd9Sstevel@tonic-gate "local mode %o", target, 8677c478bd9Sstevel@tonic-gate stb.st_mode & 07777, mode); 8687c478bd9Sstevel@tonic-gate return; 8697c478bd9Sstevel@tonic-gate } 8707c478bd9Sstevel@tonic-gate errno = ENOTDIR; 8717c478bd9Sstevel@tonic-gate } else if (errno == ENOENT && (mkdir(target, mode) == 0 || 8727c478bd9Sstevel@tonic-gate chkparent(target) == 0 && 8737c478bd9Sstevel@tonic-gate (isdot == 1 || mkdir(target, mode) == 0))) { 8747c478bd9Sstevel@tonic-gate if (chog(target, owner, group, mode) == 0) 8757c478bd9Sstevel@tonic-gate ack(); 8767c478bd9Sstevel@tonic-gate return; 8777c478bd9Sstevel@tonic-gate } 8787c478bd9Sstevel@tonic-gate error("%s:%s: %s\n", host, target, strerror(errno)); 8797c478bd9Sstevel@tonic-gate tp = stp[--catname]; 8807c478bd9Sstevel@tonic-gate *tp = '\0'; 8817c478bd9Sstevel@tonic-gate return; 8827c478bd9Sstevel@tonic-gate } 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate if (catname) { 8857c478bd9Sstevel@tonic-gate if (sizeof (target) - (tp - target) >= strlen(cp) + 2) { 8867c478bd9Sstevel@tonic-gate (void) sprintf(tp, "/%s", cp); 8877c478bd9Sstevel@tonic-gate } else { 8887c478bd9Sstevel@tonic-gate error("%.*s/%s: Name too long\n", tp - target, 8897c478bd9Sstevel@tonic-gate target, cp); 8907c478bd9Sstevel@tonic-gate return; 8917c478bd9Sstevel@tonic-gate } 8927c478bd9Sstevel@tonic-gate } 8937c478bd9Sstevel@tonic-gate cp = rindex(target, '/'); 8947c478bd9Sstevel@tonic-gate if (cp == NULL) 8957c478bd9Sstevel@tonic-gate strcpy(new, tmpname); 8967c478bd9Sstevel@tonic-gate else if (cp == target) 8977c478bd9Sstevel@tonic-gate (void) sprintf(new, "/%s", tmpname); 8987c478bd9Sstevel@tonic-gate else { 8997c478bd9Sstevel@tonic-gate *cp = '\0'; 900*56fbdff6SChandan 901*56fbdff6SChandan /* 902*56fbdff6SChandan * sizeof (target) = RDIST_BUFSIZ and sizeof (tmpname) = 11 903*56fbdff6SChandan * RDIST_BUFSIZ = 50*1024 is much greater than PATH_MAX that is 904*56fbdff6SChandan * allowed by the kernel, so it's safe to call snprintf() here 905*56fbdff6SChandan */ 906*56fbdff6SChandan (void) snprintf(new, sizeof (new), "%s/%s", target, tmpname); 9077c478bd9Sstevel@tonic-gate *cp = '/'; 9087c478bd9Sstevel@tonic-gate } 9097c478bd9Sstevel@tonic-gate 9107c478bd9Sstevel@tonic-gate if (type == S_IFLNK) { 9117c478bd9Sstevel@tonic-gate int j; 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate ack(); 9147c478bd9Sstevel@tonic-gate cp = buf; 9157c478bd9Sstevel@tonic-gate for (i = 0; i < size; i += j) { 9167c478bd9Sstevel@tonic-gate if ((j = read(rem, cp, size - i)) <= 0) 9177c478bd9Sstevel@tonic-gate cleanup(); 9187c478bd9Sstevel@tonic-gate cp += j; 9197c478bd9Sstevel@tonic-gate } 9207c478bd9Sstevel@tonic-gate *cp = '\0'; 9217c478bd9Sstevel@tonic-gate if (response() < 0) { 9227c478bd9Sstevel@tonic-gate err(); 9237c478bd9Sstevel@tonic-gate return; 9247c478bd9Sstevel@tonic-gate } 9257c478bd9Sstevel@tonic-gate if (symlink(buf, new) < 0) { 9267c478bd9Sstevel@tonic-gate if (errno != ENOENT || chkparent(new) < 0 || 9277c478bd9Sstevel@tonic-gate symlink(buf, new) < 0) 9287c478bd9Sstevel@tonic-gate goto badn; 9297c478bd9Sstevel@tonic-gate } 9307c478bd9Sstevel@tonic-gate mode &= 0777; 9317c478bd9Sstevel@tonic-gate if (opts & COMPARE) { 9327c478bd9Sstevel@tonic-gate char tbuf[MAXPATHLEN]; 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate if ((i = readlink(target, tbuf, MAXPATHLEN)) >= 0 && 9357c478bd9Sstevel@tonic-gate i == size && strncmp(buf, tbuf, size) == 0) { 9367c478bd9Sstevel@tonic-gate (void) unlink(new); 9377c478bd9Sstevel@tonic-gate ack(); 9387c478bd9Sstevel@tonic-gate return; 9397c478bd9Sstevel@tonic-gate } 9407c478bd9Sstevel@tonic-gate if (opts & VERIFY) 9417c478bd9Sstevel@tonic-gate goto differ; 9427c478bd9Sstevel@tonic-gate } 9437c478bd9Sstevel@tonic-gate goto fixup; 9447c478bd9Sstevel@tonic-gate } 9457c478bd9Sstevel@tonic-gate 9467c478bd9Sstevel@tonic-gate if ((f = creat(new, mode & ~06000)) < 0) { 9477c478bd9Sstevel@tonic-gate if (errno != ENOENT || chkparent(new) < 0 || 9487c478bd9Sstevel@tonic-gate (f = creat(new, mode & ~06000)) < 0) 9497c478bd9Sstevel@tonic-gate goto badn; 9507c478bd9Sstevel@tonic-gate } 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate ack(); 9537c478bd9Sstevel@tonic-gate wrerr = 0; 9547c478bd9Sstevel@tonic-gate for (i = 0; i < size; i += RDIST_BUFSIZ) { 9557c478bd9Sstevel@tonic-gate int amt = RDIST_BUFSIZ; 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate cp = buf; 9587c478bd9Sstevel@tonic-gate if (i + amt > size) 9597c478bd9Sstevel@tonic-gate amt = size - i; 9607c478bd9Sstevel@tonic-gate do { 9617c478bd9Sstevel@tonic-gate int j = read(rem, cp, amt); 9627c478bd9Sstevel@tonic-gate if (j <= 0) { 9637c478bd9Sstevel@tonic-gate (void) close(f); 9647c478bd9Sstevel@tonic-gate (void) unlink(new); 9657c478bd9Sstevel@tonic-gate cleanup(); 9667c478bd9Sstevel@tonic-gate } 9677c478bd9Sstevel@tonic-gate amt -= j; 9687c478bd9Sstevel@tonic-gate cp += j; 9697c478bd9Sstevel@tonic-gate } while (amt > 0); 9707c478bd9Sstevel@tonic-gate amt = RDIST_BUFSIZ; 9717c478bd9Sstevel@tonic-gate if (i + amt > size) 9727c478bd9Sstevel@tonic-gate amt = size - i; 9737c478bd9Sstevel@tonic-gate if (wrerr == 0 && write(f, buf, amt) != amt) { 9747c478bd9Sstevel@tonic-gate olderrno = errno; 9757c478bd9Sstevel@tonic-gate wrerr++; 9767c478bd9Sstevel@tonic-gate } 9777c478bd9Sstevel@tonic-gate } 9787c478bd9Sstevel@tonic-gate (void) close(f); 9797c478bd9Sstevel@tonic-gate 9807c478bd9Sstevel@tonic-gate if (response() < 0) { 9817c478bd9Sstevel@tonic-gate err(); 9827c478bd9Sstevel@tonic-gate (void) unlink(new); 9837c478bd9Sstevel@tonic-gate return; 9847c478bd9Sstevel@tonic-gate } 9857c478bd9Sstevel@tonic-gate if (wrerr) { 9867c478bd9Sstevel@tonic-gate error("%s:%s: %s\n", host, new, strerror(olderrno)); 9877c478bd9Sstevel@tonic-gate (void) unlink(new); 9887c478bd9Sstevel@tonic-gate return; 9897c478bd9Sstevel@tonic-gate } 9907c478bd9Sstevel@tonic-gate if (opts & COMPARE) { 9917c478bd9Sstevel@tonic-gate FILE *f1, *f2; 9927c478bd9Sstevel@tonic-gate int c; 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate if ((f1 = fopen(target, "r")) == NULL) 9957c478bd9Sstevel@tonic-gate goto badt; 9967c478bd9Sstevel@tonic-gate if ((f2 = fopen(new, "r")) == NULL) { 9977c478bd9Sstevel@tonic-gate badn: 9987c478bd9Sstevel@tonic-gate error("%s:%s: %s\n", host, new, strerror(errno)); 9997c478bd9Sstevel@tonic-gate (void) unlink(new); 10007c478bd9Sstevel@tonic-gate return; 10017c478bd9Sstevel@tonic-gate } 10027c478bd9Sstevel@tonic-gate while ((c = getc(f1)) == getc(f2)) 10037c478bd9Sstevel@tonic-gate if (c == EOF) { 10047c478bd9Sstevel@tonic-gate (void) fclose(f1); 10057c478bd9Sstevel@tonic-gate (void) fclose(f2); 10067c478bd9Sstevel@tonic-gate (void) unlink(new); 10077c478bd9Sstevel@tonic-gate ack(); 10087c478bd9Sstevel@tonic-gate return; 10097c478bd9Sstevel@tonic-gate } 10107c478bd9Sstevel@tonic-gate (void) fclose(f1); 10117c478bd9Sstevel@tonic-gate (void) fclose(f2); 10127c478bd9Sstevel@tonic-gate if (opts & VERIFY) { 10137c478bd9Sstevel@tonic-gate differ: 10147c478bd9Sstevel@tonic-gate (void) unlink(new); 10157c478bd9Sstevel@tonic-gate sendrem("need to update: %s", target); 10167c478bd9Sstevel@tonic-gate return; 10177c478bd9Sstevel@tonic-gate } 10187c478bd9Sstevel@tonic-gate } 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate /* 10217c478bd9Sstevel@tonic-gate * Set last modified time. For type == S_IFDIR, the lstat above filled 10227c478bd9Sstevel@tonic-gate * in stb. Otherwise, do it now. 10237c478bd9Sstevel@tonic-gate */ 10247c478bd9Sstevel@tonic-gate if (type != S_IFDIR) 10257c478bd9Sstevel@tonic-gate (void) lstat(new, &stb); 10267c478bd9Sstevel@tonic-gate tvp[0].tv_sec = stb.st_atime; /* old atime from target */ 10277c478bd9Sstevel@tonic-gate tvp[0].tv_usec = 0; 10287c478bd9Sstevel@tonic-gate tvp[1].tv_sec = mtime; 10297c478bd9Sstevel@tonic-gate tvp[1].tv_usec = 0; 10307c478bd9Sstevel@tonic-gate if (utimes(new, tvp) < 0) { 10317c478bd9Sstevel@tonic-gate note("%s:utimes failed %s: %s", host, new, strerror(errno)); 10327c478bd9Sstevel@tonic-gate } 10337c478bd9Sstevel@tonic-gate if (chog(new, owner, group, mode) < 0) { 10347c478bd9Sstevel@tonic-gate (void) unlink(new); 10357c478bd9Sstevel@tonic-gate return; 10367c478bd9Sstevel@tonic-gate } 10377c478bd9Sstevel@tonic-gate fixup: 10387c478bd9Sstevel@tonic-gate if (rename(new, target) < 0) { 10397c478bd9Sstevel@tonic-gate badt: 10407c478bd9Sstevel@tonic-gate error("%s:%s: %s\n", host, target, strerror(errno)); 10417c478bd9Sstevel@tonic-gate (void) unlink(new); 10427c478bd9Sstevel@tonic-gate return; 10437c478bd9Sstevel@tonic-gate } 10447c478bd9Sstevel@tonic-gate if (opts & COMPARE) { 10457c478bd9Sstevel@tonic-gate sendrem("updated %s", target); 10467c478bd9Sstevel@tonic-gate } else 10477c478bd9Sstevel@tonic-gate ack(); 10487c478bd9Sstevel@tonic-gate } 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate /* 10517c478bd9Sstevel@tonic-gate * Creat a hard link to existing file. 10527c478bd9Sstevel@tonic-gate */ 1053740638c8Sbw static void 10547c478bd9Sstevel@tonic-gate hardlink(cmd) 10557c478bd9Sstevel@tonic-gate char *cmd; 10567c478bd9Sstevel@tonic-gate { 10577c478bd9Sstevel@tonic-gate register char *cp; 10587c478bd9Sstevel@tonic-gate struct stat stb; 10597c478bd9Sstevel@tonic-gate char *oldname; 10607c478bd9Sstevel@tonic-gate int opts, exists = 0; 10617c478bd9Sstevel@tonic-gate char oldnamebuf[RDIST_BUFSIZ]; 10627c478bd9Sstevel@tonic-gate 10637c478bd9Sstevel@tonic-gate cp = cmd; 10647c478bd9Sstevel@tonic-gate opts = 0; 10657c478bd9Sstevel@tonic-gate while (*cp >= '0' && *cp <= '7') 10667c478bd9Sstevel@tonic-gate opts = (opts << 3) | (*cp++ - '0'); 10677c478bd9Sstevel@tonic-gate if (*cp++ != ' ') { 10687c478bd9Sstevel@tonic-gate error("hardlink: options not delimited\n"); 10697c478bd9Sstevel@tonic-gate return; 10707c478bd9Sstevel@tonic-gate } 10717c478bd9Sstevel@tonic-gate oldname = cp; 10727c478bd9Sstevel@tonic-gate while (*cp && *cp != ' ') 10737c478bd9Sstevel@tonic-gate cp++; 10747c478bd9Sstevel@tonic-gate if (*cp != ' ') { 10757c478bd9Sstevel@tonic-gate error("hardlink: oldname name not delimited\n"); 10767c478bd9Sstevel@tonic-gate return; 10777c478bd9Sstevel@tonic-gate } 10787c478bd9Sstevel@tonic-gate *cp++ = '\0'; 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate if (catname) { 10817c478bd9Sstevel@tonic-gate if (sizeof (target) - (tp - target) >= strlen(cp) + 2) { 10827c478bd9Sstevel@tonic-gate (void) sprintf(tp, "/%s", cp); 10837c478bd9Sstevel@tonic-gate } else { 10847c478bd9Sstevel@tonic-gate error("%.*s/%s: Name too long\n", tp - target, 10857c478bd9Sstevel@tonic-gate target, cp); 10867c478bd9Sstevel@tonic-gate return; 10877c478bd9Sstevel@tonic-gate } 10887c478bd9Sstevel@tonic-gate } 10897c478bd9Sstevel@tonic-gate if (lstat(target, &stb) == 0) { 10907c478bd9Sstevel@tonic-gate int mode = stb.st_mode & S_IFMT; 10917c478bd9Sstevel@tonic-gate if (mode != S_IFREG && mode != S_IFLNK) { 10927c478bd9Sstevel@tonic-gate error("%s:%s: not a regular file\n", host, target); 10937c478bd9Sstevel@tonic-gate return; 10947c478bd9Sstevel@tonic-gate } 10957c478bd9Sstevel@tonic-gate exists = 1; 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate if (chkparent(target) < 0) { 10987c478bd9Sstevel@tonic-gate error("%s:%s: %s (no parent)\n", 10997c478bd9Sstevel@tonic-gate host, target, strerror(errno)); 11007c478bd9Sstevel@tonic-gate return; 11017c478bd9Sstevel@tonic-gate } 11027c478bd9Sstevel@tonic-gate if (opts & VERIFY) { 11037c478bd9Sstevel@tonic-gate struct stat nstb; 11047c478bd9Sstevel@tonic-gate 11057c478bd9Sstevel@tonic-gate if (exists && lstat(oldname, &nstb) == 0 && 11067c478bd9Sstevel@tonic-gate nstb.st_mode == stb.st_mode && 11077c478bd9Sstevel@tonic-gate nstb.st_ino == stb.st_ino && 11087c478bd9Sstevel@tonic-gate nstb.st_dev == stb.st_dev) { 11097c478bd9Sstevel@tonic-gate ack(); 11107c478bd9Sstevel@tonic-gate return; 11117c478bd9Sstevel@tonic-gate } else { 11127c478bd9Sstevel@tonic-gate sendrem("need to update: %s", target); 11137c478bd9Sstevel@tonic-gate return; 11147c478bd9Sstevel@tonic-gate } 11157c478bd9Sstevel@tonic-gate } 11167c478bd9Sstevel@tonic-gate if (exists && (unlink(target) < 0)) { 11177c478bd9Sstevel@tonic-gate error("%s:%s: %s (unlink)\n", 11187c478bd9Sstevel@tonic-gate host, target, strerror(errno)); 11197c478bd9Sstevel@tonic-gate return; 11207c478bd9Sstevel@tonic-gate } 11217c478bd9Sstevel@tonic-gate if (*oldname == '~') 11227c478bd9Sstevel@tonic-gate oldname = exptilde(oldnamebuf, sizeof (oldnamebuf), oldname); 11237c478bd9Sstevel@tonic-gate if (link(oldname, target) < 0) { 11247c478bd9Sstevel@tonic-gate error("%s:can't link %s to %s\n", 11257c478bd9Sstevel@tonic-gate host, target, oldname); 11267c478bd9Sstevel@tonic-gate return; 11277c478bd9Sstevel@tonic-gate } 11287c478bd9Sstevel@tonic-gate ack(); 11297c478bd9Sstevel@tonic-gate } 11307c478bd9Sstevel@tonic-gate 11317c478bd9Sstevel@tonic-gate /* 11327c478bd9Sstevel@tonic-gate * Check to see if parent directory exists and create one if not. 11337c478bd9Sstevel@tonic-gate */ 1134740638c8Sbw int 11357c478bd9Sstevel@tonic-gate chkparent(name) 11367c478bd9Sstevel@tonic-gate char *name; 11377c478bd9Sstevel@tonic-gate { 11387c478bd9Sstevel@tonic-gate register char *cp; 11397c478bd9Sstevel@tonic-gate struct stat stb; 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate cp = rindex(name, '/'); 11427c478bd9Sstevel@tonic-gate if (cp == NULL || cp == name) 11437c478bd9Sstevel@tonic-gate return (0); 11447c478bd9Sstevel@tonic-gate *cp = '\0'; 11457c478bd9Sstevel@tonic-gate if (lstat(name, &stb) < 0) { 11467c478bd9Sstevel@tonic-gate if (errno == ENOENT && chkparent(name) >= 0 && 11477c478bd9Sstevel@tonic-gate mkdir(name, 0777 & ~oumask) >= 0) { 11487c478bd9Sstevel@tonic-gate *cp = '/'; 11497c478bd9Sstevel@tonic-gate return (0); 11507c478bd9Sstevel@tonic-gate } 11517c478bd9Sstevel@tonic-gate } else if (ISDIR(stb.st_mode)) { 11527c478bd9Sstevel@tonic-gate *cp = '/'; 11537c478bd9Sstevel@tonic-gate return (0); 11547c478bd9Sstevel@tonic-gate } 11557c478bd9Sstevel@tonic-gate *cp = '/'; 11567c478bd9Sstevel@tonic-gate return (-1); 11577c478bd9Sstevel@tonic-gate } 11587c478bd9Sstevel@tonic-gate 11597c478bd9Sstevel@tonic-gate /* 11607c478bd9Sstevel@tonic-gate * Change owner, group and mode of file. 11617c478bd9Sstevel@tonic-gate */ 1162740638c8Sbw int 11637c478bd9Sstevel@tonic-gate chog(file, owner, group, mode) 11647c478bd9Sstevel@tonic-gate char *file, *owner, *group; 11657c478bd9Sstevel@tonic-gate int mode; 11667c478bd9Sstevel@tonic-gate { 11677c478bd9Sstevel@tonic-gate register int i; 11687c478bd9Sstevel@tonic-gate uid_t uid, gid; 11697c478bd9Sstevel@tonic-gate extern char user[]; 11707c478bd9Sstevel@tonic-gate 11717c478bd9Sstevel@tonic-gate /* 11727c478bd9Sstevel@tonic-gate * by default, set uid of file to the uid of the person running 11737c478bd9Sstevel@tonic-gate * this program. 11747c478bd9Sstevel@tonic-gate */ 11757c478bd9Sstevel@tonic-gate uid = getuid(); 11767c478bd9Sstevel@tonic-gate 11777c478bd9Sstevel@tonic-gate /* 11787c478bd9Sstevel@tonic-gate * We'll use available privileges so we just try to do what 11797c478bd9Sstevel@tonic-gate * the client specifies. If the chown() fails we'll not 11807c478bd9Sstevel@tonic-gate * add the set-[ug]id bits; and if we want to add the set-[ug]id 11817c478bd9Sstevel@tonic-gate * bits and we're not permitted to do so, the OS will prevent us 11827c478bd9Sstevel@tonic-gate * from doing so. 11837c478bd9Sstevel@tonic-gate */ 11847c478bd9Sstevel@tonic-gate if (*owner == ':') { 11857c478bd9Sstevel@tonic-gate uid = atoi(owner + 1); 11867c478bd9Sstevel@tonic-gate } else if (pw == NULL || strcmp(owner, pw->pw_name) != 0) { 11877c478bd9Sstevel@tonic-gate if ((pw = getpwnam(owner)) == NULL) { 11887c478bd9Sstevel@tonic-gate if (mode & 04000) { 11897c478bd9Sstevel@tonic-gate note("%s:%s: unknown login name, " 11907c478bd9Sstevel@tonic-gate "clearing setuid", host, owner); 11917c478bd9Sstevel@tonic-gate mode &= ~04000; 11927c478bd9Sstevel@tonic-gate } 11937c478bd9Sstevel@tonic-gate } else { 11947c478bd9Sstevel@tonic-gate uid = pw->pw_uid; 11957c478bd9Sstevel@tonic-gate } 11967c478bd9Sstevel@tonic-gate } else { 11977c478bd9Sstevel@tonic-gate uid = pw->pw_uid; 11987c478bd9Sstevel@tonic-gate } 11997c478bd9Sstevel@tonic-gate 12007c478bd9Sstevel@tonic-gate if (*group == ':') { 12017c478bd9Sstevel@tonic-gate gid = atoi(group + 1); 12027c478bd9Sstevel@tonic-gate goto ok; 12037c478bd9Sstevel@tonic-gate } 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate gid = -1; 12067c478bd9Sstevel@tonic-gate if (gr == NULL || strcmp(group, gr->gr_name) != 0) { 12077c478bd9Sstevel@tonic-gate if ((*group == ':' && 12087c478bd9Sstevel@tonic-gate (getgrgid(gid = atoi(group + 1)) == NULL)) || 12097c478bd9Sstevel@tonic-gate ((gr = getgrnam(group)) == NULL)) { 12107c478bd9Sstevel@tonic-gate if (mode & 02000) { 12117c478bd9Sstevel@tonic-gate note("%s:%s: unknown group", host, group); 12127c478bd9Sstevel@tonic-gate mode &= ~02000; 12137c478bd9Sstevel@tonic-gate } 12147c478bd9Sstevel@tonic-gate } else 12157c478bd9Sstevel@tonic-gate gid = gr->gr_gid; 12167c478bd9Sstevel@tonic-gate } else 12177c478bd9Sstevel@tonic-gate gid = gr->gr_gid; 12187c478bd9Sstevel@tonic-gate ok: 12197c478bd9Sstevel@tonic-gate if (chown(file, uid, gid) < 0 || 12207c478bd9Sstevel@tonic-gate (mode & 07000) && chmod(file, mode) < 0) { 12217c478bd9Sstevel@tonic-gate note("%s: chown or chmod failed: file %s: %s", 12227c478bd9Sstevel@tonic-gate host, file, strerror(errno)); 12237c478bd9Sstevel@tonic-gate } 12247c478bd9Sstevel@tonic-gate return (0); 12257c478bd9Sstevel@tonic-gate } 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate /* 12287c478bd9Sstevel@tonic-gate * Check for files on the machine being updated that are not on the master 12297c478bd9Sstevel@tonic-gate * machine and remove them. 12307c478bd9Sstevel@tonic-gate */ 1231740638c8Sbw static void 12327c478bd9Sstevel@tonic-gate rmchk(opts) 12337c478bd9Sstevel@tonic-gate int opts; 12347c478bd9Sstevel@tonic-gate { 12357c478bd9Sstevel@tonic-gate register char *cp, *s; 12367c478bd9Sstevel@tonic-gate struct stat stb; 12377c478bd9Sstevel@tonic-gate 12387c478bd9Sstevel@tonic-gate if (debug) 12397c478bd9Sstevel@tonic-gate printf("rmchk()\n"); 12407c478bd9Sstevel@tonic-gate 12417c478bd9Sstevel@tonic-gate /* 12427c478bd9Sstevel@tonic-gate * Tell the remote to clean the files from the last directory sent. 12437c478bd9Sstevel@tonic-gate */ 12447c478bd9Sstevel@tonic-gate (void) sprintf(buf, "C%o\n", opts & VERIFY); 12457c478bd9Sstevel@tonic-gate if (debug) 12467c478bd9Sstevel@tonic-gate printf("buf = %s", buf); 12477c478bd9Sstevel@tonic-gate (void) deswrite(rem, buf, strlen(buf), 0); 12487c478bd9Sstevel@tonic-gate if (response() < 0) 12497c478bd9Sstevel@tonic-gate return; 12507c478bd9Sstevel@tonic-gate for (;;) { 12517c478bd9Sstevel@tonic-gate cp = s = buf; 12527c478bd9Sstevel@tonic-gate do { 12537c478bd9Sstevel@tonic-gate if (desread(rem, cp, 1, 0) != 1) 12547c478bd9Sstevel@tonic-gate lostconn(); 12557c478bd9Sstevel@tonic-gate } while (*cp++ != '\n' && cp < &buf[RDIST_BUFSIZ]); 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate switch (*s++) { 12587c478bd9Sstevel@tonic-gate case 'Q': /* Query if file should be removed */ 12597c478bd9Sstevel@tonic-gate /* 12607c478bd9Sstevel@tonic-gate * Return the following codes to remove query. 12617c478bd9Sstevel@tonic-gate * N\n -- file exists - DON'T remove. 12627c478bd9Sstevel@tonic-gate * Y\n -- file doesn't exist - REMOVE. 12637c478bd9Sstevel@tonic-gate */ 12647c478bd9Sstevel@tonic-gate *--cp = '\0'; 12657c478bd9Sstevel@tonic-gate (void) sprintf(tp, "/%s", s); 12667c478bd9Sstevel@tonic-gate if (debug) 12677c478bd9Sstevel@tonic-gate printf("check %s\n", target); 12687c478bd9Sstevel@tonic-gate if (except(target)) 12697c478bd9Sstevel@tonic-gate (void) deswrite(rem, "N\n", 2, 0); 12707c478bd9Sstevel@tonic-gate else if (lstat(target, &stb) < 0) 12717c478bd9Sstevel@tonic-gate (void) deswrite(rem, "Y\n", 2, 0); 12727c478bd9Sstevel@tonic-gate else 12737c478bd9Sstevel@tonic-gate (void) deswrite(rem, "N\n", 2, 0); 12747c478bd9Sstevel@tonic-gate break; 12757c478bd9Sstevel@tonic-gate 12767c478bd9Sstevel@tonic-gate case '\0': 12777c478bd9Sstevel@tonic-gate *--cp = '\0'; 12787c478bd9Sstevel@tonic-gate if (*s != '\0') 12797c478bd9Sstevel@tonic-gate log(lfp, "%s\n", s); 12807c478bd9Sstevel@tonic-gate break; 12817c478bd9Sstevel@tonic-gate 12827c478bd9Sstevel@tonic-gate case 'E': 12837c478bd9Sstevel@tonic-gate *tp = '\0'; 12847c478bd9Sstevel@tonic-gate (void) deswrite(rem, "\0\n", 2, 0); 12857c478bd9Sstevel@tonic-gate return; 12867c478bd9Sstevel@tonic-gate 12877c478bd9Sstevel@tonic-gate case '\1': 12887c478bd9Sstevel@tonic-gate case '\2': 12897c478bd9Sstevel@tonic-gate nerrs++; 12907c478bd9Sstevel@tonic-gate if (*s != '\n') { 12917c478bd9Sstevel@tonic-gate if (!iamremote) { 12927c478bd9Sstevel@tonic-gate fflush(stdout); 12937c478bd9Sstevel@tonic-gate (void) write(2, s, cp - s); 12947c478bd9Sstevel@tonic-gate } 12957c478bd9Sstevel@tonic-gate if (lfp != NULL) 12967c478bd9Sstevel@tonic-gate (void) fwrite(s, 1, cp - s, lfp); 12977c478bd9Sstevel@tonic-gate } 12987c478bd9Sstevel@tonic-gate if (buf[0] == '\2') 12997c478bd9Sstevel@tonic-gate lostconn(); 13007c478bd9Sstevel@tonic-gate break; 13017c478bd9Sstevel@tonic-gate 13027c478bd9Sstevel@tonic-gate default: 13037c478bd9Sstevel@tonic-gate error("rmchk: unexpected response '%s'\n", buf); 13047c478bd9Sstevel@tonic-gate (void) deswrite(rem, "\1\n", 2, 0); 13057c478bd9Sstevel@tonic-gate } 13067c478bd9Sstevel@tonic-gate } 13077c478bd9Sstevel@tonic-gate } 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate /* 13107c478bd9Sstevel@tonic-gate * Check the current directory (initialized by the 'T' command to server()) 13117c478bd9Sstevel@tonic-gate * for extraneous files and remove them. 13127c478bd9Sstevel@tonic-gate */ 1313740638c8Sbw static void 13147c478bd9Sstevel@tonic-gate clean(cp) 13157c478bd9Sstevel@tonic-gate register char *cp; 13167c478bd9Sstevel@tonic-gate { 13177c478bd9Sstevel@tonic-gate DIR *d; 13187c478bd9Sstevel@tonic-gate register struct dirent *dp; 13197c478bd9Sstevel@tonic-gate struct stat stb; 13207c478bd9Sstevel@tonic-gate char *otp; 13217c478bd9Sstevel@tonic-gate int len, opts; 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate opts = 0; 13247c478bd9Sstevel@tonic-gate while (*cp >= '0' && *cp <= '7') 13257c478bd9Sstevel@tonic-gate opts = (opts << 3) | (*cp++ - '0'); 13267c478bd9Sstevel@tonic-gate if (*cp != '\0') { 13277c478bd9Sstevel@tonic-gate error("clean: options not delimited\n"); 13287c478bd9Sstevel@tonic-gate return; 13297c478bd9Sstevel@tonic-gate } 13307c478bd9Sstevel@tonic-gate if ((d = opendir(target)) == NULL) { 13317c478bd9Sstevel@tonic-gate error("%s:%s: %s\n", host, target, strerror(errno)); 13327c478bd9Sstevel@tonic-gate return; 13337c478bd9Sstevel@tonic-gate } 13347c478bd9Sstevel@tonic-gate ack(); 13357c478bd9Sstevel@tonic-gate 13367c478bd9Sstevel@tonic-gate otp = tp; 13377c478bd9Sstevel@tonic-gate len = tp - target; 13387c478bd9Sstevel@tonic-gate while (dp = readdir(d)) { 13397c478bd9Sstevel@tonic-gate if ((strcmp(dp->d_name, ".") == 0) || 13407c478bd9Sstevel@tonic-gate (strcmp(dp->d_name, "..") == 0)) 13417c478bd9Sstevel@tonic-gate continue; 13427c478bd9Sstevel@tonic-gate if ((int)(len + 1 + strlen(dp->d_name)) >= 13437c478bd9Sstevel@tonic-gate (int)(RDIST_BUFSIZ - 1)) { 13447c478bd9Sstevel@tonic-gate error("%s:%s/%s: Name too long\n", 13457c478bd9Sstevel@tonic-gate host, target, dp->d_name); 13467c478bd9Sstevel@tonic-gate continue; 13477c478bd9Sstevel@tonic-gate } 13487c478bd9Sstevel@tonic-gate tp = otp; 13497c478bd9Sstevel@tonic-gate *tp++ = '/'; 13507c478bd9Sstevel@tonic-gate cp = dp->d_name; 13517c478bd9Sstevel@tonic-gate while (*tp++ = *cp++) 13527c478bd9Sstevel@tonic-gate ; 13537c478bd9Sstevel@tonic-gate tp--; 13547c478bd9Sstevel@tonic-gate if (lstat(target, &stb) < 0) { 13557c478bd9Sstevel@tonic-gate error("%s:%s: %s\n", host, target, strerror(errno)); 13567c478bd9Sstevel@tonic-gate continue; 13577c478bd9Sstevel@tonic-gate } 13587c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "Q%s\n", dp->d_name); 13597c478bd9Sstevel@tonic-gate (void) write(wrem, buf, strlen(buf)); 13607c478bd9Sstevel@tonic-gate cp = buf; 13617c478bd9Sstevel@tonic-gate do { 13627c478bd9Sstevel@tonic-gate if (read(rem, cp, 1) != 1) 13637c478bd9Sstevel@tonic-gate cleanup(); 13647c478bd9Sstevel@tonic-gate } while (*cp++ != '\n' && cp < &buf[RDIST_BUFSIZ]); 13657c478bd9Sstevel@tonic-gate *--cp = '\0'; 13667c478bd9Sstevel@tonic-gate cp = buf; 13677c478bd9Sstevel@tonic-gate if (*cp != 'Y') 13687c478bd9Sstevel@tonic-gate continue; 13697c478bd9Sstevel@tonic-gate if (opts & VERIFY) { 13707c478bd9Sstevel@tonic-gate sendrem("need to remove: %s", target); 13717c478bd9Sstevel@tonic-gate } else 13727c478bd9Sstevel@tonic-gate (void) recursive_remove(&stb); 13737c478bd9Sstevel@tonic-gate } 13747c478bd9Sstevel@tonic-gate closedir(d); 13757c478bd9Sstevel@tonic-gate (void) write(wrem, "E\n", 2); 13767c478bd9Sstevel@tonic-gate (void) response(); 13777c478bd9Sstevel@tonic-gate tp = otp; 13787c478bd9Sstevel@tonic-gate *tp = '\0'; 13797c478bd9Sstevel@tonic-gate } 13807c478bd9Sstevel@tonic-gate 13817c478bd9Sstevel@tonic-gate /* 13827c478bd9Sstevel@tonic-gate * Remove a file or directory (recursively) and send back an acknowledge 13837c478bd9Sstevel@tonic-gate * or an error message. 13847c478bd9Sstevel@tonic-gate */ 1385740638c8Sbw static void 13867c478bd9Sstevel@tonic-gate recursive_remove(stp) 13877c478bd9Sstevel@tonic-gate struct stat *stp; 13887c478bd9Sstevel@tonic-gate { 13897c478bd9Sstevel@tonic-gate DIR *d; 13907c478bd9Sstevel@tonic-gate struct dirent *dp; 13917c478bd9Sstevel@tonic-gate register char *cp; 13927c478bd9Sstevel@tonic-gate struct stat stb; 13937c478bd9Sstevel@tonic-gate char *otp; 13947c478bd9Sstevel@tonic-gate int len; 13957c478bd9Sstevel@tonic-gate 13967c478bd9Sstevel@tonic-gate switch (stp->st_mode & S_IFMT) { 13977c478bd9Sstevel@tonic-gate case S_IFREG: 13987c478bd9Sstevel@tonic-gate case S_IFLNK: 13997c478bd9Sstevel@tonic-gate if (unlink(target) < 0) 14007c478bd9Sstevel@tonic-gate goto bad; 14017c478bd9Sstevel@tonic-gate goto removed; 14027c478bd9Sstevel@tonic-gate 14037c478bd9Sstevel@tonic-gate case S_IFDIR: 14047c478bd9Sstevel@tonic-gate break; 14057c478bd9Sstevel@tonic-gate 14067c478bd9Sstevel@tonic-gate default: 14077c478bd9Sstevel@tonic-gate error("%s:%s: not a plain file\n", host, target); 14087c478bd9Sstevel@tonic-gate return; 14097c478bd9Sstevel@tonic-gate } 14107c478bd9Sstevel@tonic-gate 14117c478bd9Sstevel@tonic-gate if ((d = opendir(target)) == NULL) 14127c478bd9Sstevel@tonic-gate goto bad; 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate otp = tp; 14157c478bd9Sstevel@tonic-gate len = tp - target; 14167c478bd9Sstevel@tonic-gate while (dp = readdir(d)) { 14177c478bd9Sstevel@tonic-gate if ((strcmp(dp->d_name, ".") == 0) || 14187c478bd9Sstevel@tonic-gate (strcmp(dp->d_name, "..") == 0)) 14197c478bd9Sstevel@tonic-gate continue; 14207c478bd9Sstevel@tonic-gate if ((int)(len + 1 + strlen(dp->d_name)) >= 14217c478bd9Sstevel@tonic-gate (int)(RDIST_BUFSIZ - 1)) { 14227c478bd9Sstevel@tonic-gate error("%s:%s/%s: Name too long\n", 14237c478bd9Sstevel@tonic-gate host, target, dp->d_name); 14247c478bd9Sstevel@tonic-gate continue; 14257c478bd9Sstevel@tonic-gate } 14267c478bd9Sstevel@tonic-gate tp = otp; 14277c478bd9Sstevel@tonic-gate *tp++ = '/'; 14287c478bd9Sstevel@tonic-gate cp = dp->d_name; 14297c478bd9Sstevel@tonic-gate while (*tp++ = *cp++) 14307c478bd9Sstevel@tonic-gate ; 14317c478bd9Sstevel@tonic-gate tp--; 14327c478bd9Sstevel@tonic-gate if (lstat(target, &stb) < 0) { 14337c478bd9Sstevel@tonic-gate error("%s:%s: %s\n", host, target, strerror(errno)); 14347c478bd9Sstevel@tonic-gate continue; 14357c478bd9Sstevel@tonic-gate } 14367c478bd9Sstevel@tonic-gate recursive_remove(&stb); 14377c478bd9Sstevel@tonic-gate } 14387c478bd9Sstevel@tonic-gate closedir(d); 14397c478bd9Sstevel@tonic-gate tp = otp; 14407c478bd9Sstevel@tonic-gate *tp = '\0'; 14417c478bd9Sstevel@tonic-gate if (rmdir(target) < 0) { 14427c478bd9Sstevel@tonic-gate bad: 14437c478bd9Sstevel@tonic-gate error("%s:%s: %s\n", host, target, strerror(errno)); 14447c478bd9Sstevel@tonic-gate return; 14457c478bd9Sstevel@tonic-gate } 14467c478bd9Sstevel@tonic-gate removed: 14477c478bd9Sstevel@tonic-gate sendrem("removed %s", target); 14487c478bd9Sstevel@tonic-gate } 14497c478bd9Sstevel@tonic-gate 14507c478bd9Sstevel@tonic-gate /* 14517c478bd9Sstevel@tonic-gate * Execute a shell command to handle special cases. 14527c478bd9Sstevel@tonic-gate */ 1453740638c8Sbw static void 14547c478bd9Sstevel@tonic-gate dospecial(cmd) 14557c478bd9Sstevel@tonic-gate char *cmd; 14567c478bd9Sstevel@tonic-gate { 14577c478bd9Sstevel@tonic-gate int fd[2], status, pid, i; 14587c478bd9Sstevel@tonic-gate register char *cp, *s; 14597c478bd9Sstevel@tonic-gate char sbuf[RDIST_BUFSIZ]; 14607c478bd9Sstevel@tonic-gate 14617c478bd9Sstevel@tonic-gate if (pipe(fd) < 0) { 14627c478bd9Sstevel@tonic-gate error("%s\n", strerror(errno)); 14637c478bd9Sstevel@tonic-gate return; 14647c478bd9Sstevel@tonic-gate } 14657c478bd9Sstevel@tonic-gate if ((pid = fork()) == 0) { 14667c478bd9Sstevel@tonic-gate /* 14677c478bd9Sstevel@tonic-gate * Return everything the shell commands print. 14687c478bd9Sstevel@tonic-gate */ 14697c478bd9Sstevel@tonic-gate (void) close(0); 14707c478bd9Sstevel@tonic-gate (void) close(1); 14717c478bd9Sstevel@tonic-gate (void) close(2); 14727c478bd9Sstevel@tonic-gate (void) open("/dev/null", 0); 14737c478bd9Sstevel@tonic-gate (void) dup(fd[1]); 14747c478bd9Sstevel@tonic-gate (void) dup(fd[1]); 14757c478bd9Sstevel@tonic-gate (void) close(fd[0]); 14767c478bd9Sstevel@tonic-gate (void) close(fd[1]); 14777c478bd9Sstevel@tonic-gate execl("/bin/sh", "sh", "-c", cmd, 0); 14787c478bd9Sstevel@tonic-gate _exit(127); 14797c478bd9Sstevel@tonic-gate } 14807c478bd9Sstevel@tonic-gate (void) close(fd[1]); 14817c478bd9Sstevel@tonic-gate s = sbuf; 14827c478bd9Sstevel@tonic-gate *s++ = '\0'; 14837c478bd9Sstevel@tonic-gate while ((i = read(fd[0], buf, RDIST_BUFSIZ)) > 0) { 14847c478bd9Sstevel@tonic-gate cp = buf; 14857c478bd9Sstevel@tonic-gate do { 14867c478bd9Sstevel@tonic-gate *s++ = *cp++; 14877c478bd9Sstevel@tonic-gate if (cp[-1] != '\n') { 14887c478bd9Sstevel@tonic-gate if (s < &sbuf[RDIST_BUFSIZ - 1]) 14897c478bd9Sstevel@tonic-gate continue; 14907c478bd9Sstevel@tonic-gate *s++ = '\n'; 14917c478bd9Sstevel@tonic-gate } 14927c478bd9Sstevel@tonic-gate /* 14937c478bd9Sstevel@tonic-gate * Throw away blank lines. 14947c478bd9Sstevel@tonic-gate */ 14957c478bd9Sstevel@tonic-gate if (s == &sbuf[2]) { 14967c478bd9Sstevel@tonic-gate s--; 14977c478bd9Sstevel@tonic-gate continue; 14987c478bd9Sstevel@tonic-gate } 14997c478bd9Sstevel@tonic-gate (void) write(wrem, sbuf, s - sbuf); 15007c478bd9Sstevel@tonic-gate s = &sbuf[1]; 15017c478bd9Sstevel@tonic-gate } while (--i); 15027c478bd9Sstevel@tonic-gate } 15037c478bd9Sstevel@tonic-gate if (s > &sbuf[1]) { 15047c478bd9Sstevel@tonic-gate *s++ = '\n'; 15057c478bd9Sstevel@tonic-gate (void) write(wrem, sbuf, s - sbuf); 15067c478bd9Sstevel@tonic-gate } 15077c478bd9Sstevel@tonic-gate while ((i = wait(&status)) != pid && i != -1) 15087c478bd9Sstevel@tonic-gate ; 15097c478bd9Sstevel@tonic-gate if (i == -1) 15107c478bd9Sstevel@tonic-gate status = -1; 15117c478bd9Sstevel@tonic-gate (void) close(fd[0]); 15127c478bd9Sstevel@tonic-gate if (status) 15137c478bd9Sstevel@tonic-gate error("shell returned %d\n", status); 15147c478bd9Sstevel@tonic-gate else 15157c478bd9Sstevel@tonic-gate ack(); 15167c478bd9Sstevel@tonic-gate } 15177c478bd9Sstevel@tonic-gate 15187c478bd9Sstevel@tonic-gate /*VARARGS2*/ 1519740638c8Sbw void 15207c478bd9Sstevel@tonic-gate log(fp, fmt, a1, a2, a3) 15217c478bd9Sstevel@tonic-gate FILE *fp; 15227c478bd9Sstevel@tonic-gate char *fmt; 15237c478bd9Sstevel@tonic-gate int a1, a2, a3; 15247c478bd9Sstevel@tonic-gate { 15257c478bd9Sstevel@tonic-gate /* Print changes locally if not quiet mode */ 15267c478bd9Sstevel@tonic-gate if (!qflag) 15277c478bd9Sstevel@tonic-gate printf(fmt, a1, a2, a3); 15287c478bd9Sstevel@tonic-gate 15297c478bd9Sstevel@tonic-gate /* Save changes (for mailing) if really updating files */ 15307c478bd9Sstevel@tonic-gate if (!(options & VERIFY) && fp != NULL) 15317c478bd9Sstevel@tonic-gate fprintf(fp, fmt, a1, a2, a3); 15327c478bd9Sstevel@tonic-gate } 15337c478bd9Sstevel@tonic-gate 15347c478bd9Sstevel@tonic-gate /*VARARGS1*/ 1535740638c8Sbw void 15367c478bd9Sstevel@tonic-gate error(fmt, a1, a2, a3) 15377c478bd9Sstevel@tonic-gate char *fmt; 15387c478bd9Sstevel@tonic-gate int a1, a2, a3; 15397c478bd9Sstevel@tonic-gate { 15407c478bd9Sstevel@tonic-gate static FILE *fp; 15417c478bd9Sstevel@tonic-gate 15427c478bd9Sstevel@tonic-gate nerrs++; 15437c478bd9Sstevel@tonic-gate if (!fp && !(fp = fdopen(rem, "w"))) 15447c478bd9Sstevel@tonic-gate return; 15457c478bd9Sstevel@tonic-gate if (iamremote) { 15467c478bd9Sstevel@tonic-gate (void) fprintf(fp, "%crdist: ", 0x01); 15477c478bd9Sstevel@tonic-gate (void) fprintf(fp, fmt, a1, a2, a3); 15487c478bd9Sstevel@tonic-gate fflush(fp); 15497c478bd9Sstevel@tonic-gate } else { 15507c478bd9Sstevel@tonic-gate fflush(stdout); 15517c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "rdist: "); 15527c478bd9Sstevel@tonic-gate (void) fprintf(stderr, fmt, a1, a2, a3); 15537c478bd9Sstevel@tonic-gate fflush(stderr); 15547c478bd9Sstevel@tonic-gate } 15557c478bd9Sstevel@tonic-gate if (lfp != NULL) { 15567c478bd9Sstevel@tonic-gate (void) fprintf(lfp, "rdist: "); 15577c478bd9Sstevel@tonic-gate (void) fprintf(lfp, fmt, a1, a2, a3); 15587c478bd9Sstevel@tonic-gate fflush(lfp); 15597c478bd9Sstevel@tonic-gate } 15607c478bd9Sstevel@tonic-gate } 15617c478bd9Sstevel@tonic-gate 15627c478bd9Sstevel@tonic-gate /*VARARGS1*/ 1563740638c8Sbw void 15647c478bd9Sstevel@tonic-gate fatal(fmt, a1, a2, a3) 15657c478bd9Sstevel@tonic-gate char *fmt; 15667c478bd9Sstevel@tonic-gate int a1, a2, a3; 15677c478bd9Sstevel@tonic-gate { 15687c478bd9Sstevel@tonic-gate static FILE *fp; 15697c478bd9Sstevel@tonic-gate 15707c478bd9Sstevel@tonic-gate nerrs++; 15717c478bd9Sstevel@tonic-gate if (!fp && !(fp = fdopen(rem, "w"))) 15727c478bd9Sstevel@tonic-gate return; 15737c478bd9Sstevel@tonic-gate if (iamremote) { 15747c478bd9Sstevel@tonic-gate (void) fprintf(fp, "%crdist: ", 0x02); 15757c478bd9Sstevel@tonic-gate (void) fprintf(fp, fmt, a1, a2, a3); 15767c478bd9Sstevel@tonic-gate fflush(fp); 15777c478bd9Sstevel@tonic-gate } else { 15787c478bd9Sstevel@tonic-gate fflush(stdout); 15797c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "rdist: "); 15807c478bd9Sstevel@tonic-gate (void) fprintf(stderr, fmt, a1, a2, a3); 15817c478bd9Sstevel@tonic-gate fflush(stderr); 15827c478bd9Sstevel@tonic-gate } 15837c478bd9Sstevel@tonic-gate if (lfp != NULL) { 15847c478bd9Sstevel@tonic-gate (void) fprintf(lfp, "rdist: "); 15857c478bd9Sstevel@tonic-gate (void) fprintf(lfp, fmt, a1, a2, a3); 15867c478bd9Sstevel@tonic-gate fflush(lfp); 15877c478bd9Sstevel@tonic-gate } 15887c478bd9Sstevel@tonic-gate cleanup(); 15897c478bd9Sstevel@tonic-gate } 15907c478bd9Sstevel@tonic-gate 1591740638c8Sbw int 15927c478bd9Sstevel@tonic-gate response() 15937c478bd9Sstevel@tonic-gate { 15947c478bd9Sstevel@tonic-gate char *cp, *s; 15957c478bd9Sstevel@tonic-gate char resp[RDIST_BUFSIZ]; 15967c478bd9Sstevel@tonic-gate 15977c478bd9Sstevel@tonic-gate if (debug) 15987c478bd9Sstevel@tonic-gate printf("response()\n"); 15997c478bd9Sstevel@tonic-gate 16007c478bd9Sstevel@tonic-gate cp = s = resp; 16017c478bd9Sstevel@tonic-gate more: 16027c478bd9Sstevel@tonic-gate do { 16037c478bd9Sstevel@tonic-gate if (desread(rem, cp, 1, 0) != 1) 16047c478bd9Sstevel@tonic-gate lostconn(); 16057c478bd9Sstevel@tonic-gate } while (*cp++ != '\n' && cp < &resp[RDIST_BUFSIZ]); 16067c478bd9Sstevel@tonic-gate 16077c478bd9Sstevel@tonic-gate switch (*s++) { 16087c478bd9Sstevel@tonic-gate case '\0': 16097c478bd9Sstevel@tonic-gate *--cp = '\0'; 16107c478bd9Sstevel@tonic-gate if (*s != '\0') { 16117c478bd9Sstevel@tonic-gate log(lfp, "%s\n", s); 16127c478bd9Sstevel@tonic-gate return (1); 16137c478bd9Sstevel@tonic-gate } 16147c478bd9Sstevel@tonic-gate return (0); 16157c478bd9Sstevel@tonic-gate case '\3': 16167c478bd9Sstevel@tonic-gate *--cp = '\0'; 16177c478bd9Sstevel@tonic-gate log(lfp, "Note: %s\n", s); 16187c478bd9Sstevel@tonic-gate return (response()); 16197c478bd9Sstevel@tonic-gate 16207c478bd9Sstevel@tonic-gate default: 16217c478bd9Sstevel@tonic-gate s--; 16227c478bd9Sstevel@tonic-gate /* fall into... */ 16237c478bd9Sstevel@tonic-gate case '\1': 16247c478bd9Sstevel@tonic-gate case '\2': 16257c478bd9Sstevel@tonic-gate nerrs++; 16267c478bd9Sstevel@tonic-gate if (*s != '\n') { 16277c478bd9Sstevel@tonic-gate if (!iamremote) { 16287c478bd9Sstevel@tonic-gate fflush(stdout); 16297c478bd9Sstevel@tonic-gate (void) write(2, s, cp - s); 16307c478bd9Sstevel@tonic-gate } 16317c478bd9Sstevel@tonic-gate if (lfp != NULL) 16327c478bd9Sstevel@tonic-gate (void) fwrite(s, 1, cp - s, lfp); 16337c478bd9Sstevel@tonic-gate } 16347c478bd9Sstevel@tonic-gate if (cp == &resp[RDIST_BUFSIZ] && *(cp - 1) != '\n') { 16357c478bd9Sstevel@tonic-gate /* preserve status code */ 16367c478bd9Sstevel@tonic-gate cp = s; 16377c478bd9Sstevel@tonic-gate s = resp; 16387c478bd9Sstevel@tonic-gate goto more; 16397c478bd9Sstevel@tonic-gate } 16407c478bd9Sstevel@tonic-gate if (resp[0] == '\2') 16417c478bd9Sstevel@tonic-gate lostconn(); 16427c478bd9Sstevel@tonic-gate return (-1); 16437c478bd9Sstevel@tonic-gate } 16447c478bd9Sstevel@tonic-gate } 16457c478bd9Sstevel@tonic-gate 16467c478bd9Sstevel@tonic-gate /* 16477c478bd9Sstevel@tonic-gate * Remove temporary files and do any cleanup operations before exiting. 16487c478bd9Sstevel@tonic-gate */ 16497c478bd9Sstevel@tonic-gate void 16507c478bd9Sstevel@tonic-gate cleanup() 16517c478bd9Sstevel@tonic-gate { 16527c478bd9Sstevel@tonic-gate (void) unlink(Tmpfile); 16537c478bd9Sstevel@tonic-gate exit(1); 16547c478bd9Sstevel@tonic-gate } 16557c478bd9Sstevel@tonic-gate 1656740638c8Sbw static void 16577c478bd9Sstevel@tonic-gate note(fmt, a1, a2, a3) 16587c478bd9Sstevel@tonic-gate char *fmt; 16597c478bd9Sstevel@tonic-gate int a1, a2, a3; 16607c478bd9Sstevel@tonic-gate { 16617c478bd9Sstevel@tonic-gate static char buf[RDIST_BUFSIZ]; 16627c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf) - 1, fmt, a1, a2, a3); 16637c478bd9Sstevel@tonic-gate comment(buf); 16647c478bd9Sstevel@tonic-gate } 16657c478bd9Sstevel@tonic-gate 1666740638c8Sbw static void 16677c478bd9Sstevel@tonic-gate comment(s) 16687c478bd9Sstevel@tonic-gate char *s; 16697c478bd9Sstevel@tonic-gate { 16707c478bd9Sstevel@tonic-gate char three = '\3'; 16717c478bd9Sstevel@tonic-gate char nl = '\n'; 16727c478bd9Sstevel@tonic-gate struct iovec iov[3]; 16737c478bd9Sstevel@tonic-gate 16747c478bd9Sstevel@tonic-gate iov[0].iov_base = &three; 16757c478bd9Sstevel@tonic-gate iov[0].iov_len = sizeof (char); 16767c478bd9Sstevel@tonic-gate iov[1].iov_base = s; 16777c478bd9Sstevel@tonic-gate iov[1].iov_len = strlen(s); 16787c478bd9Sstevel@tonic-gate iov[2].iov_base = &nl; 16797c478bd9Sstevel@tonic-gate iov[2].iov_len = sizeof (char); 16807c478bd9Sstevel@tonic-gate (void) writev(rem, iov, 3); 16817c478bd9Sstevel@tonic-gate } 16827c478bd9Sstevel@tonic-gate 16837c478bd9Sstevel@tonic-gate /* 16847c478bd9Sstevel@tonic-gate * Send message to other end. 16857c478bd9Sstevel@tonic-gate * N.B.: uses buf[]. 16867c478bd9Sstevel@tonic-gate */ 16877c478bd9Sstevel@tonic-gate void 16887c478bd9Sstevel@tonic-gate sendrem(fmt, a1, a2, a3) 16897c478bd9Sstevel@tonic-gate char *fmt; 16907c478bd9Sstevel@tonic-gate int a1, a2, a3; 16917c478bd9Sstevel@tonic-gate { 16927c478bd9Sstevel@tonic-gate register int len; 16937c478bd9Sstevel@tonic-gate 16947c478bd9Sstevel@tonic-gate buf[0] = '\0'; 16957c478bd9Sstevel@tonic-gate len = snprintf(buf + 1, sizeof (buf) - 1, fmt, a1, a2, a3) + 2; 16967c478bd9Sstevel@tonic-gate if (len > sizeof (buf)) 16977c478bd9Sstevel@tonic-gate len = sizeof (buf); 16987c478bd9Sstevel@tonic-gate buf[len - 1] = '\n'; 16997c478bd9Sstevel@tonic-gate (void) write(wrem, buf, len); 17007c478bd9Sstevel@tonic-gate } 17017c478bd9Sstevel@tonic-gate 17027c478bd9Sstevel@tonic-gate /* 17037c478bd9Sstevel@tonic-gate * strsub(old, new, s) 17047c478bd9Sstevel@tonic-gate * 17057c478bd9Sstevel@tonic-gate * Return a pointer to a new string created by replacing substring old 17067c478bd9Sstevel@tonic-gate * with substring new in string s. String s is assumed to begin with 17077c478bd9Sstevel@tonic-gate * substring old. 17087c478bd9Sstevel@tonic-gate */ 17097c478bd9Sstevel@tonic-gate char * 17107c478bd9Sstevel@tonic-gate strsub(old, new, s) 17117c478bd9Sstevel@tonic-gate char *old, *new, *s; 17127c478bd9Sstevel@tonic-gate { 17137c478bd9Sstevel@tonic-gate static char pbuf[PATH_MAX]; 17147c478bd9Sstevel@tonic-gate register char *p, *q, *r, *plim; 17157c478bd9Sstevel@tonic-gate 17167c478bd9Sstevel@tonic-gate /* prepend new to pbuf */ 17177c478bd9Sstevel@tonic-gate for (p = pbuf, q = new, plim = pbuf + sizeof (pbuf) - 1; 17187c478bd9Sstevel@tonic-gate /* CSTYLED */ 17197c478bd9Sstevel@tonic-gate *q && (p < plim);) 17207c478bd9Sstevel@tonic-gate *p++ = *q++; 17217c478bd9Sstevel@tonic-gate /* p now points to the byte in pbuf where more copying should begin */ 17227c478bd9Sstevel@tonic-gate 17237c478bd9Sstevel@tonic-gate /* skip over the part of s which begins with old */ 17247c478bd9Sstevel@tonic-gate for (r = old, q = s; *r; q++, r++) 17257c478bd9Sstevel@tonic-gate ; 17267c478bd9Sstevel@tonic-gate /* q now points to the byte in s where more copying should begin */ 17277c478bd9Sstevel@tonic-gate 17287c478bd9Sstevel@tonic-gate while (*q && (p < plim)) 17297c478bd9Sstevel@tonic-gate *p++ = *q++; 17307c478bd9Sstevel@tonic-gate *p = '\0'; 17317c478bd9Sstevel@tonic-gate 17327c478bd9Sstevel@tonic-gate return (pbuf); 17337c478bd9Sstevel@tonic-gate } 1734