1978e44c9Sralph #ifndef lint 2*d49851feSralph static char *sccsid = "@(#)server.c 4.2 (Berkeley) 83/09/27"; 3978e44c9Sralph #endif 4978e44c9Sralph 5978e44c9Sralph #include "defs.h" 6978e44c9Sralph 7978e44c9Sralph #define ga() (void) write(rem, "", 1) 8978e44c9Sralph 9*d49851feSralph char buf[BUFSIZ]; /* general purpose buffer */ 10978e44c9Sralph char target[BUFSIZ]; /* target/source directory name */ 11978e44c9Sralph char *tp; /* pointer to end of target name */ 12978e44c9Sralph int catname; /* cat name to target name */ 13978e44c9Sralph 14*d49851feSralph static struct passwd *p = NULL; 15*d49851feSralph static struct group *g = NULL; 16*d49851feSralph 17*d49851feSralph extern FILE *lfp; /* log file for mailing changes */ 18*d49851feSralph 19978e44c9Sralph /* 20978e44c9Sralph * Server routine to read requests and process them. 21978e44c9Sralph * Commands are: 22978e44c9Sralph * Tname - Transmit file if out of date 23978e44c9Sralph * Vname - Verify if file out of date or not 24978e44c9Sralph * Qname - Query if file exists. Return mtime & size if it does. 25978e44c9Sralph */ 26978e44c9Sralph server() 27978e44c9Sralph { 28978e44c9Sralph char cmdbuf[BUFSIZ]; 29978e44c9Sralph register char *cp; 30978e44c9Sralph register struct block *bp, *last = NULL; 31978e44c9Sralph register int n; 32978e44c9Sralph static struct block cmdblk = { EXCEPT }; 33978e44c9Sralph 34978e44c9Sralph (void) umask(0); 35978e44c9Sralph ga(); 36978e44c9Sralph 37978e44c9Sralph for (;;) { 38978e44c9Sralph cp = cmdbuf; 39978e44c9Sralph if (read(rem, cp, 1) <= 0) 40978e44c9Sralph return; 41978e44c9Sralph if (*cp++ == '\n') { 42978e44c9Sralph error("expected control record\n"); 43978e44c9Sralph continue; 44978e44c9Sralph } 45978e44c9Sralph do { 46978e44c9Sralph if (read(rem, cp, 1) != 1) 47978e44c9Sralph lostconn(); 48*d49851feSralph } while (*cp++ != '\n' && cp < &cmdbuf[BUFSIZ]); 49978e44c9Sralph *--cp = '\0'; 50978e44c9Sralph cp = cmdbuf; 51978e44c9Sralph switch (*cp++) { 52978e44c9Sralph case 'X': /* add name to list of files to exclude */ 53978e44c9Sralph if (*cp == '\0') 54978e44c9Sralph continue; 55978e44c9Sralph bp = ALLOC(block); 56978e44c9Sralph if (bp == NULL) 57978e44c9Sralph fatal("ran out of memory\n"); 58978e44c9Sralph bp->b_type = NAME; 59978e44c9Sralph bp->b_next = bp->b_args = NULL; 60978e44c9Sralph bp->b_name = cp = (char *) malloc(strlen(cp) + 1); 61978e44c9Sralph if (cp == NULL) 62978e44c9Sralph fatal("ran out of memory\n"); 63978e44c9Sralph strcpy(cp, &cmdbuf[1]); 64978e44c9Sralph if (last == NULL) { 65978e44c9Sralph except = &cmdblk; 66978e44c9Sralph cmdblk.b_args = last = bp; 67978e44c9Sralph } else { 68978e44c9Sralph last->b_next = bp; 69978e44c9Sralph last = bp; 70978e44c9Sralph } 71978e44c9Sralph continue; 72978e44c9Sralph 73978e44c9Sralph case 'T': /* init target file/directory name */ 74*d49851feSralph catname = 1; /* target should be directory */ 75*d49851feSralph goto dotarget; 76*d49851feSralph 77*d49851feSralph case 't': /* init target file/directory name */ 78978e44c9Sralph catname = 0; 79*d49851feSralph dotarget: 80*d49851feSralph exptilde(target, cp); 81978e44c9Sralph tp = target; 82978e44c9Sralph while (*tp) 83978e44c9Sralph tp++; 84978e44c9Sralph continue; 85978e44c9Sralph 86978e44c9Sralph case 'S': /* Send. Transfer file if out of date. */ 87978e44c9Sralph tp = NULL; 88978e44c9Sralph sendf(cp, 0); 89978e44c9Sralph continue; 90978e44c9Sralph 91978e44c9Sralph case 'V': /* Verify. See if file is out of date. */ 92978e44c9Sralph tp = NULL; 93978e44c9Sralph sendf(cp, 1); 94978e44c9Sralph continue; 95978e44c9Sralph 96978e44c9Sralph case 'R': /* Receive. Transfer file. */ 97978e44c9Sralph recvf(cp, 0); 98978e44c9Sralph continue; 99978e44c9Sralph 100978e44c9Sralph case 'D': /* Directory. Transfer file. */ 101978e44c9Sralph recvf(cp, 1); 102978e44c9Sralph continue; 103978e44c9Sralph 104978e44c9Sralph case 'E': /* End. (of directory) */ 105978e44c9Sralph *tp = '\0'; 106*d49851feSralph if (--catname < 0) { 107978e44c9Sralph error("too many 'E's\n"); 108978e44c9Sralph continue; 109978e44c9Sralph } 110*d49851feSralph cp = rindex(target, '/'); 111*d49851feSralph if (cp == NULL) 112*d49851feSralph tp = NULL; 113*d49851feSralph else { 114978e44c9Sralph *cp = '\0'; 115978e44c9Sralph tp = cp; 116*d49851feSralph } 117978e44c9Sralph ga(); 118978e44c9Sralph continue; 119978e44c9Sralph 120978e44c9Sralph case 'Q': /* Query. Does file exist? */ 121978e44c9Sralph query(cp); 122978e44c9Sralph continue; 123978e44c9Sralph 124978e44c9Sralph case 'L': /* Log. save message in log file */ 125978e44c9Sralph query(cp); 126978e44c9Sralph continue; 127978e44c9Sralph 128*d49851feSralph case '\1': 129*d49851feSralph errs++; 130*d49851feSralph continue; 131*d49851feSralph 132*d49851feSralph case '\2': 133*d49851feSralph return; 134*d49851feSralph 135978e44c9Sralph default: 136978e44c9Sralph error("unknown command type %s\n", cp); 137978e44c9Sralph case '\0': 138978e44c9Sralph continue; 139978e44c9Sralph } 140978e44c9Sralph } 141978e44c9Sralph } 142978e44c9Sralph 143978e44c9Sralph /* 144978e44c9Sralph * Transfer the file or directory 'name'. 145978e44c9Sralph */ 146978e44c9Sralph sendf(name, verify) 147978e44c9Sralph char *name; 148978e44c9Sralph int verify; 149978e44c9Sralph { 150978e44c9Sralph register char *last; 151978e44c9Sralph struct stat stb; 152*d49851feSralph int sizerr, f, u; 153978e44c9Sralph off_t i; 154978e44c9Sralph 155978e44c9Sralph if (debug) 156978e44c9Sralph printf("sendf(%s, %d)\n", name, verify); 157978e44c9Sralph 158978e44c9Sralph if (exclude(name)) 159978e44c9Sralph return; 160978e44c9Sralph 161*d49851feSralph /* 162*d49851feSralph * first time sendf() is called? 163*d49851feSralph */ 164*d49851feSralph if (tp == NULL) { 165*d49851feSralph exptilde(target, name); 166*d49851feSralph tp = name = target; 167*d49851feSralph while (*tp) 168*d49851feSralph tp++; 169*d49851feSralph } 170978e44c9Sralph if (access(name, 4) < 0 || stat(name, &stb) < 0) { 171978e44c9Sralph error("%s: %s\n", name, sys_errlist[errno]); 172978e44c9Sralph return; 173978e44c9Sralph } 174978e44c9Sralph last = rindex(name, '/'); 175978e44c9Sralph if (last == NULL) 176978e44c9Sralph last = name; 177978e44c9Sralph else 178978e44c9Sralph last++; 179*d49851feSralph if ((u = update(last, &stb)) == 0) 180978e44c9Sralph return; 181978e44c9Sralph 182*d49851feSralph if (p == NULL || p->pw_uid != stb.st_uid) 183978e44c9Sralph if ((p = getpwuid(stb.st_uid)) == NULL) { 184978e44c9Sralph error("no password entry for uid %d\n", stb.st_uid); 185978e44c9Sralph return; 186978e44c9Sralph } 187*d49851feSralph if (g == NULL || g->gr_gid != stb.st_gid) 188978e44c9Sralph if ((g = getgrgid(stb.st_gid)) == NULL) { 189978e44c9Sralph error("no name for group %d\n", stb.st_gid); 190978e44c9Sralph return; 191978e44c9Sralph } 192978e44c9Sralph 193978e44c9Sralph switch (stb.st_mode & S_IFMT) { 194978e44c9Sralph case S_IFREG: 195978e44c9Sralph break; 196978e44c9Sralph 197978e44c9Sralph case S_IFDIR: 198978e44c9Sralph rsendf(name, verify, &stb, p->pw_name, g->gr_name); 199978e44c9Sralph return; 200978e44c9Sralph 201978e44c9Sralph default: 202978e44c9Sralph error("%s: not a plain file\n", name); 203978e44c9Sralph return; 204978e44c9Sralph } 205978e44c9Sralph 206*d49851feSralph log(lfp, "%s: %s\n", u == 2 ? "updating" : "installing", name); 207978e44c9Sralph 208978e44c9Sralph if (verify || vflag) 209978e44c9Sralph return; 210978e44c9Sralph 211*d49851feSralph if ((f = open(name, 0)) < 0) { 212*d49851feSralph error("%s: %s\n", name, sys_errlist[errno]); 213*d49851feSralph return; 214*d49851feSralph } 215978e44c9Sralph (void) sprintf(buf, "R%04o %D %D %s %s %s\n", stb.st_mode & 07777, 216978e44c9Sralph stb.st_size, stb.st_mtime, p->pw_name, g->gr_name, last); 217978e44c9Sralph if (debug) 218978e44c9Sralph printf("buf = %s", buf); 219978e44c9Sralph (void) write(rem, buf, strlen(buf)); 220978e44c9Sralph if (response() < 0) { 221978e44c9Sralph (void) close(f); 222978e44c9Sralph return; 223978e44c9Sralph } 224978e44c9Sralph sizerr = 0; 225978e44c9Sralph for (i = 0; i < stb.st_size; i += BUFSIZ) { 226978e44c9Sralph int amt = BUFSIZ; 227978e44c9Sralph if (i + amt > stb.st_size) 228978e44c9Sralph amt = stb.st_size - i; 229978e44c9Sralph if (sizerr == 0 && read(f, buf, amt) != amt) 230978e44c9Sralph sizerr = 1; 231978e44c9Sralph (void) write(rem, buf, amt); 232978e44c9Sralph } 233978e44c9Sralph (void) close(f); 234978e44c9Sralph if (sizerr) 235978e44c9Sralph error("%s: file changed size\n", name); 236978e44c9Sralph else 237978e44c9Sralph ga(); 238978e44c9Sralph (void) response(); 239978e44c9Sralph } 240978e44c9Sralph 241978e44c9Sralph rsendf(name, verify, st, owner, group) 242978e44c9Sralph char *name; 243978e44c9Sralph int verify; 244978e44c9Sralph struct stat *st; 245978e44c9Sralph char *owner, *group; 246978e44c9Sralph { 247978e44c9Sralph DIR *d; 248978e44c9Sralph struct direct *dp; 249978e44c9Sralph register char *last; 250978e44c9Sralph char *otp; 251*d49851feSralph int len; 252978e44c9Sralph 253978e44c9Sralph if (debug) 254978e44c9Sralph printf("rsendf(%s, %d, %x, %s, %s)\n", name, verify, st, 255978e44c9Sralph owner, group); 256978e44c9Sralph 257978e44c9Sralph if ((d = opendir(name)) == NULL) { 258978e44c9Sralph error("%s: %s\n", name, sys_errlist[errno]); 259978e44c9Sralph return; 260978e44c9Sralph } 261978e44c9Sralph last = rindex(name, '/'); 262978e44c9Sralph if (last == NULL) 263978e44c9Sralph last = name; 264978e44c9Sralph else 265978e44c9Sralph last++; 266978e44c9Sralph (void) sprintf(buf, "D%04o 0 0 %s %s %s\n", st->st_mode & 07777, 267978e44c9Sralph owner, group, last); 268978e44c9Sralph if (debug) 269978e44c9Sralph printf("buf = %s", buf); 270978e44c9Sralph (void) write(rem, buf, strlen(buf)); 271978e44c9Sralph if (response() < 0) { 272978e44c9Sralph closedir(d); 273978e44c9Sralph return; 274978e44c9Sralph } 275978e44c9Sralph otp = tp; 276*d49851feSralph len = tp - target; 277978e44c9Sralph while (dp = readdir(d)) { 278978e44c9Sralph if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 279978e44c9Sralph continue; 280*d49851feSralph if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { 281978e44c9Sralph error("%s/%s: Name too long\n", name, dp->d_name); 282978e44c9Sralph continue; 283978e44c9Sralph } 284978e44c9Sralph tp = otp; 285978e44c9Sralph *tp++ = '/'; 286978e44c9Sralph last = dp->d_name; 287978e44c9Sralph while (*tp++ = *last++) 288978e44c9Sralph ; 289978e44c9Sralph tp--; 290978e44c9Sralph sendf(target, verify); 291978e44c9Sralph } 292978e44c9Sralph closedir(d); 293978e44c9Sralph (void) write(rem, "E\n", 2); 294978e44c9Sralph (void) response(); 295978e44c9Sralph tp = otp; 296978e44c9Sralph *tp = '\0'; 297978e44c9Sralph } 298978e44c9Sralph 299978e44c9Sralph /* 300978e44c9Sralph * Check to see if file needs to be updated on the remote machine. 301*d49851feSralph * Returns 0 if no update, 1 if remote doesn't exist, and 2 if out of date. 302978e44c9Sralph */ 303978e44c9Sralph update(name, st) 304978e44c9Sralph char *name; 305978e44c9Sralph struct stat *st; 306978e44c9Sralph { 307978e44c9Sralph register char *cp; 308978e44c9Sralph register off_t size; 309978e44c9Sralph register time_t mtime; 310978e44c9Sralph 311978e44c9Sralph if (debug) 312978e44c9Sralph printf("update(%s, %x)\n", name, st); 313978e44c9Sralph 314978e44c9Sralph /* 315978e44c9Sralph * Check to see if the file exists on the remote machine. 316978e44c9Sralph */ 317978e44c9Sralph (void) sprintf(buf, "Q%s\n", name); 318978e44c9Sralph if (debug) 319978e44c9Sralph printf("buf = %s", buf); 320978e44c9Sralph (void) write(rem, buf, strlen(buf)); 321978e44c9Sralph cp = buf; 322978e44c9Sralph do { 323978e44c9Sralph if (read(rem, cp, 1) != 1) 324978e44c9Sralph lostconn(); 325*d49851feSralph } while (*cp++ != '\n' && cp < &buf[BUFSIZ]); 326978e44c9Sralph *--cp = '\0'; 327978e44c9Sralph cp = buf; 328978e44c9Sralph if (debug) 329978e44c9Sralph printf("resp = %s\n", cp); 330978e44c9Sralph 331978e44c9Sralph switch (*cp++) { 332978e44c9Sralph case 'Y': 333978e44c9Sralph break; 334978e44c9Sralph 335*d49851feSralph case 'N': /* file doesn't exist so install it */ 336978e44c9Sralph return(1); 337978e44c9Sralph 338978e44c9Sralph case '\1': 339*d49851feSralph errs++; 340*d49851feSralph if (*cp != '\0') { 341*d49851feSralph if (!iamremote) { 342*d49851feSralph fflush(stdout); 343*d49851feSralph (void) write(2, cp, strlen(cp)); 344*d49851feSralph } 345*d49851feSralph if (lfp != NULL) 346*d49851feSralph (void) fwrite(cp, 1, strlen(cp), lfp); 347*d49851feSralph } 348978e44c9Sralph return(0); 349978e44c9Sralph 350978e44c9Sralph default: 351978e44c9Sralph error("unexpected response '%c' to query\n", *--cp); 352978e44c9Sralph return(0); 353978e44c9Sralph } 354978e44c9Sralph 355978e44c9Sralph if (*cp == '\0') { 356978e44c9Sralph if ((st->st_mode & S_IFMT) == S_IFDIR) 357*d49851feSralph return(2); 358978e44c9Sralph return(1); 359978e44c9Sralph } 360978e44c9Sralph 361978e44c9Sralph size = 0; 362978e44c9Sralph while (isdigit(*cp)) 363978e44c9Sralph size = size * 10 + (*cp++ - '0'); 364978e44c9Sralph if (*cp++ != ' ') { 365978e44c9Sralph error("size not delimited\n"); 366978e44c9Sralph return(0); 367978e44c9Sralph } 368978e44c9Sralph mtime = 0; 369978e44c9Sralph while (isdigit(*cp)) 370978e44c9Sralph mtime = mtime * 10 + (*cp++ - '0'); 371978e44c9Sralph if (*cp != '\0') { 372978e44c9Sralph error("mtime not delimited\n"); 373978e44c9Sralph return(0); 374978e44c9Sralph } 375978e44c9Sralph /* 376978e44c9Sralph * File needs to be updated? 377978e44c9Sralph */ 378978e44c9Sralph if (st->st_mtime == mtime && st->st_size == size || 379*d49851feSralph yflag && st->st_mtime < mtime) 380978e44c9Sralph return(0); 381*d49851feSralph return(2); 382978e44c9Sralph } 383978e44c9Sralph 384978e44c9Sralph /* 385978e44c9Sralph * Query. Check to see if file exists. Return one of the following: 386978e44c9Sralph * N\n - doesn't exist 387978e44c9Sralph * Ysize mtime\n - exists and its a regular file (size & mtime of file) 388978e44c9Sralph * Y\n - exists and its a directory 389978e44c9Sralph * ^Aerror message\n 390978e44c9Sralph */ 391978e44c9Sralph query(name) 392978e44c9Sralph char *name; 393978e44c9Sralph { 394978e44c9Sralph struct stat stb; 395978e44c9Sralph 396978e44c9Sralph if (catname) 397978e44c9Sralph (void) sprintf(tp, "/%s", name); 398978e44c9Sralph if (stat(target, &stb) < 0) { 399978e44c9Sralph (void) write(rem, "N\n", 2); 400978e44c9Sralph *tp = '\0'; 401978e44c9Sralph return; 402978e44c9Sralph } 403978e44c9Sralph 404978e44c9Sralph switch (stb.st_mode & S_IFMT) { 405978e44c9Sralph case S_IFREG: 406978e44c9Sralph (void) sprintf(buf, "Y%D %D\n", stb.st_size, stb.st_mtime); 407978e44c9Sralph (void) write(rem, buf, strlen(buf)); 408978e44c9Sralph break; 409978e44c9Sralph 410978e44c9Sralph case S_IFDIR: 411978e44c9Sralph (void) write(rem, "Y\n", 2); 412978e44c9Sralph break; 413978e44c9Sralph 414978e44c9Sralph default: 415978e44c9Sralph error("%s: not a plain file\n", name); 416978e44c9Sralph break; 417978e44c9Sralph } 418978e44c9Sralph *tp = '\0'; 419978e44c9Sralph } 420978e44c9Sralph 421978e44c9Sralph recvf(cmd, isdir) 422978e44c9Sralph char *cmd; 423978e44c9Sralph int isdir; 424978e44c9Sralph { 425978e44c9Sralph register char *cp; 426978e44c9Sralph int f, mode, wrerr, exists, olderrno; 427978e44c9Sralph off_t i, size; 428978e44c9Sralph time_t mtime; 429978e44c9Sralph struct stat stb; 430978e44c9Sralph struct timeval tvp[2]; 431978e44c9Sralph char *owner, *group, *dir; 432978e44c9Sralph char new[BUFSIZ]; 433*d49851feSralph extern char *tmpname; 434978e44c9Sralph 435978e44c9Sralph mode = 0; 436978e44c9Sralph for (cp = cmd; cp < cmd+4; cp++) { 437978e44c9Sralph if (*cp < '0' || *cp > '7') { 438978e44c9Sralph error("bad mode\n"); 439978e44c9Sralph return; 440978e44c9Sralph } 441978e44c9Sralph mode = (mode << 3) | (*cp - '0'); 442978e44c9Sralph } 443978e44c9Sralph if (*cp++ != ' ') { 444978e44c9Sralph error("mode not delimited\n"); 445978e44c9Sralph return; 446978e44c9Sralph } 447978e44c9Sralph size = 0; 448978e44c9Sralph while (isdigit(*cp)) 449978e44c9Sralph size = size * 10 + (*cp++ - '0'); 450978e44c9Sralph if (*cp++ != ' ') { 451978e44c9Sralph error("size not delimited\n"); 452978e44c9Sralph return; 453978e44c9Sralph } 454978e44c9Sralph mtime = 0; 455978e44c9Sralph while (isdigit(*cp)) 456978e44c9Sralph mtime = mtime * 10 + (*cp++ - '0'); 457978e44c9Sralph if (*cp++ != ' ') { 458978e44c9Sralph error("mtime not delimited\n"); 459978e44c9Sralph return; 460978e44c9Sralph } 461978e44c9Sralph owner = cp; 462978e44c9Sralph while (*cp && *cp != ' ') 463978e44c9Sralph cp++; 464978e44c9Sralph if (*cp != ' ') { 465978e44c9Sralph error("owner name not delimited\n"); 466978e44c9Sralph return; 467978e44c9Sralph } 468978e44c9Sralph *cp++ = '\0'; 469978e44c9Sralph group = cp; 470978e44c9Sralph while (*cp && *cp != ' ') 471978e44c9Sralph cp++; 472978e44c9Sralph if (*cp != ' ') { 473978e44c9Sralph error("group name not delimited\n"); 474978e44c9Sralph return; 475978e44c9Sralph } 476978e44c9Sralph *cp++ = '\0'; 477978e44c9Sralph 478*d49851feSralph new[0] = '\0'; 479978e44c9Sralph if (isdir) { 480978e44c9Sralph if (catname++) { 481978e44c9Sralph *tp++ = '/'; 482978e44c9Sralph while (*tp++ = *cp++) 483978e44c9Sralph ; 484978e44c9Sralph tp--; 485978e44c9Sralph } 486*d49851feSralph if (vflag) { 487*d49851feSralph ga(); 488*d49851feSralph return; 489*d49851feSralph } 490978e44c9Sralph if (stat(target, &stb) == 0) { 491978e44c9Sralph if ((stb.st_mode & S_IFMT) != S_IFDIR) { 492978e44c9Sralph errno = ENOTDIR; 493978e44c9Sralph goto bad; 494978e44c9Sralph } 495978e44c9Sralph } else { 496978e44c9Sralph /* 497978e44c9Sralph * Check parent directory for write permission. 498978e44c9Sralph */ 499978e44c9Sralph cp = rindex(target, '/'); 500978e44c9Sralph if (cp == NULL) 501978e44c9Sralph dir = "."; 502978e44c9Sralph else if (cp == target) { 503978e44c9Sralph dir = "/"; 504978e44c9Sralph cp = NULL; 505978e44c9Sralph } else { 506978e44c9Sralph dir = target; 507978e44c9Sralph *cp = '\0'; 508978e44c9Sralph } 509*d49851feSralph if (access(dir, 2) < 0) 510*d49851feSralph goto bad2; 511978e44c9Sralph if (cp != NULL) 512978e44c9Sralph *cp = '/'; 513978e44c9Sralph if (mkdir(target, mode) < 0) 514978e44c9Sralph goto bad; 515*d49851feSralph if (chog(target, owner, group, mode) < 0) 516978e44c9Sralph return; 517*d49851feSralph } 518978e44c9Sralph ga(); 519978e44c9Sralph return; 520978e44c9Sralph } 521978e44c9Sralph 522978e44c9Sralph if (catname) 523978e44c9Sralph (void) sprintf(tp, "/%s", cp); 524978e44c9Sralph if (stat(target, &stb) == 0) { 525978e44c9Sralph switch (stb.st_mode & S_IFMT) { 526978e44c9Sralph case S_IFREG: 527978e44c9Sralph break; 528978e44c9Sralph 529978e44c9Sralph case S_IFDIR: 530978e44c9Sralph if (!catname) { 531978e44c9Sralph (void) sprintf(tp, "/%s", cp); 532978e44c9Sralph break; 533978e44c9Sralph } 534978e44c9Sralph 535978e44c9Sralph default: 536978e44c9Sralph error("%s: not a regular file\n", target); 537978e44c9Sralph return; 538978e44c9Sralph } 539978e44c9Sralph } 540978e44c9Sralph /* 541978e44c9Sralph * Check parent directory for write permission. 542978e44c9Sralph */ 543978e44c9Sralph cp = rindex(target, '/'); 544978e44c9Sralph if (cp == NULL) 545978e44c9Sralph dir = "."; 546978e44c9Sralph else if (cp == target) { 547978e44c9Sralph dir = "/"; 548978e44c9Sralph cp = NULL; 549978e44c9Sralph } else { 550978e44c9Sralph dir = target; 551978e44c9Sralph *cp = '\0'; 552978e44c9Sralph } 553*d49851feSralph if (access(dir, 2) < 0) { 554*d49851feSralph bad2: 555*d49851feSralph error("%s: %s\n", dir, sys_errlist[errno]); 556978e44c9Sralph if (cp != NULL) 557978e44c9Sralph *cp = '/'; 558*d49851feSralph return; 559*d49851feSralph } 560*d49851feSralph (void) sprintf(new, "%s/%s", dir, tmpname); 561*d49851feSralph if (cp != NULL) 562*d49851feSralph *cp = '/'; 563978e44c9Sralph if ((f = creat(new, mode)) < 0) 564978e44c9Sralph goto bad1; 565*d49851feSralph if (chog(new, owner, group, mode) < 0) { 566*d49851feSralph (void) close(f); 567*d49851feSralph (void) unlink(new); 568978e44c9Sralph return; 569*d49851feSralph } 570978e44c9Sralph ga(); 571978e44c9Sralph 572978e44c9Sralph wrerr = 0; 573978e44c9Sralph for (i = 0; i < size; i += BUFSIZ) { 574978e44c9Sralph int amt = BUFSIZ; 575978e44c9Sralph char *cp = buf; 576978e44c9Sralph 577978e44c9Sralph if (i + amt > size) 578978e44c9Sralph amt = size - i; 579978e44c9Sralph do { 580978e44c9Sralph int j = read(rem, cp, amt); 581978e44c9Sralph 582*d49851feSralph if (j <= 0) { 583*d49851feSralph (void) close(f); 584*d49851feSralph (void) unlink(new); 585978e44c9Sralph cleanup(); 586*d49851feSralph } 587978e44c9Sralph amt -= j; 588978e44c9Sralph cp += j; 589978e44c9Sralph } while (amt > 0); 590978e44c9Sralph amt = BUFSIZ; 591978e44c9Sralph if (i + amt > size) 592978e44c9Sralph amt = size - i; 593978e44c9Sralph if (wrerr == 0 && write(f, buf, amt) != amt) { 594978e44c9Sralph olderrno = errno; 595978e44c9Sralph wrerr++; 596978e44c9Sralph } 597978e44c9Sralph } 598978e44c9Sralph (void) response(); 599978e44c9Sralph if (wrerr) { 600978e44c9Sralph error("%s: %s\n", cp, sys_errlist[olderrno]); 601*d49851feSralph (void) close(f); 602*d49851feSralph (void) unlink(new); 603978e44c9Sralph return; 604978e44c9Sralph } 605978e44c9Sralph 606978e44c9Sralph /* 607978e44c9Sralph * Set last modified time 608978e44c9Sralph */ 609978e44c9Sralph (void) fstat(f, &stb); 610978e44c9Sralph (void) close(f); 611978e44c9Sralph tvp[0].tv_sec = stb.st_atime; 612978e44c9Sralph tvp[0].tv_usec = 0; 613978e44c9Sralph tvp[1].tv_sec = mtime; 614978e44c9Sralph tvp[1].tv_usec = 0; 615978e44c9Sralph if (utimes(new, tvp) < 0) { 616978e44c9Sralph bad1: 617978e44c9Sralph error("%s: %s\n", new, sys_errlist[errno]); 618*d49851feSralph if (new[0]) 619*d49851feSralph (void) unlink(new); 620978e44c9Sralph return; 621978e44c9Sralph } 622978e44c9Sralph 623978e44c9Sralph if (rename(new, target) < 0) { 624978e44c9Sralph bad: 625978e44c9Sralph error("%s: %s\n", target, sys_errlist[errno]); 626*d49851feSralph if (new[0]) 627*d49851feSralph (void) unlink(new); 628978e44c9Sralph return; 629978e44c9Sralph } 630978e44c9Sralph ga(); 631978e44c9Sralph } 632978e44c9Sralph 633978e44c9Sralph /* 634978e44c9Sralph * Change owner and group of file. 635978e44c9Sralph */ 636*d49851feSralph chog(file, owner, group, mode) 637978e44c9Sralph char *file, *owner, *group; 638*d49851feSralph int mode; 639978e44c9Sralph { 640*d49851feSralph extern int userid, groupid; 641*d49851feSralph extern char user[]; 642978e44c9Sralph register int i; 643978e44c9Sralph int uid, gid; 644978e44c9Sralph 645978e44c9Sralph uid = userid; 646978e44c9Sralph if (userid == 0) { 647*d49851feSralph if (p == NULL || strcmp(owner, p->pw_name) != 0) { 648*d49851feSralph if ((p = getpwnam(owner)) == NULL) { 649*d49851feSralph if (mode & 04000) { 650978e44c9Sralph error("%s: unknown login name\n", owner); 651978e44c9Sralph return(-1); 652978e44c9Sralph } 653*d49851feSralph } else 654*d49851feSralph uid = p->pw_uid; 655*d49851feSralph } else 656978e44c9Sralph uid = p->pw_uid; 657978e44c9Sralph } 658*d49851feSralph gid = groupid; 659*d49851feSralph if (g == NULL || strcmp(group, g->gr_name) != 0) { 660*d49851feSralph if ((g = getgrnam(group)) == NULL) { 661*d49851feSralph if (mode & 02000) { 662978e44c9Sralph error("%s: unknown group\n", group); 663978e44c9Sralph return(-1); 664978e44c9Sralph } 665*d49851feSralph } else 666978e44c9Sralph gid = g->gr_gid; 667*d49851feSralph } else 668*d49851feSralph gid = g->gr_gid; 669*d49851feSralph if (userid && groupid != gid) { 670*d49851feSralph for (i = 0; g->gr_mem[i] != NULL; i++) 671978e44c9Sralph if (!(strcmp(user, g->gr_mem[i]))) 672978e44c9Sralph goto ok; 673*d49851feSralph gid = groupid; 674978e44c9Sralph } 675978e44c9Sralph ok: 676978e44c9Sralph if (chown(file, uid, gid) < 0) { 677978e44c9Sralph error("%s: %s\n", file, sys_errlist[errno]); 678978e44c9Sralph return(-1); 679978e44c9Sralph } 680978e44c9Sralph return(0); 681978e44c9Sralph } 682978e44c9Sralph 683978e44c9Sralph /*VARARGS*/ 684*d49851feSralph log(fp, fmt, a1, a2, a3) 685*d49851feSralph FILE *fp; 686978e44c9Sralph char *fmt; 687978e44c9Sralph int a1, a2, a3; 688978e44c9Sralph { 689978e44c9Sralph /* Print changes locally if not quiet mode */ 690978e44c9Sralph if (!qflag) 691978e44c9Sralph printf(fmt, a1, a2, a3); 692978e44c9Sralph 693978e44c9Sralph /* Save changes (for mailing) if really updating files */ 694*d49851feSralph if (!vflag && fp != NULL) 695*d49851feSralph fprintf(fp, fmt, a1, a2, a3); 696978e44c9Sralph } 697978e44c9Sralph 698978e44c9Sralph /*VARARGS*/ 699978e44c9Sralph error(fmt, a1, a2, a3) 700978e44c9Sralph char *fmt; 701978e44c9Sralph int a1, a2, a3; 702978e44c9Sralph { 703978e44c9Sralph errs++; 704978e44c9Sralph strcpy(buf, "\1rdist: "); 705978e44c9Sralph (void) sprintf(buf+8, fmt, a1, a2, a3); 706978e44c9Sralph (void) write(rem, buf, strlen(buf)); 707978e44c9Sralph if (buf[1] != '\0') { 708*d49851feSralph if (!iamremote) { 709*d49851feSralph fflush(stdout); 710978e44c9Sralph (void) write(2, buf+1, strlen(buf+1)); 711*d49851feSralph } 712978e44c9Sralph if (lfp != NULL) 713978e44c9Sralph (void) fwrite(buf+1, 1, strlen(buf+1), lfp); 714978e44c9Sralph } 715978e44c9Sralph } 716978e44c9Sralph 717978e44c9Sralph /*VARARGS*/ 718978e44c9Sralph fatal(fmt, a1, a2,a3) 719978e44c9Sralph char *fmt; 720978e44c9Sralph int a1, a2, a3; 721978e44c9Sralph { 722978e44c9Sralph errs++; 723978e44c9Sralph strcpy(buf, "\2rdist: "); 724978e44c9Sralph (void) sprintf(buf+8, fmt, a1, a2, a3); 725978e44c9Sralph (void) write(rem, buf, strlen(buf)); 726978e44c9Sralph if (buf[1] != '\0') { 727*d49851feSralph if (!iamremote) { 728*d49851feSralph fflush(stdout); 729978e44c9Sralph (void) write(2, buf+1, strlen(buf+1)); 730*d49851feSralph } 731978e44c9Sralph if (lfp != NULL) 732978e44c9Sralph (void) fwrite(buf+1, 1, strlen(buf+1), lfp); 733978e44c9Sralph } 734978e44c9Sralph cleanup(); 735978e44c9Sralph } 736978e44c9Sralph 737978e44c9Sralph response() 738978e44c9Sralph { 739978e44c9Sralph char resp, c, *cp = buf; 740978e44c9Sralph 741978e44c9Sralph if (debug) 742978e44c9Sralph printf("response()\n"); 743978e44c9Sralph 744978e44c9Sralph if (read(rem, &resp, 1) != 1) 745978e44c9Sralph lostconn(); 746978e44c9Sralph 747978e44c9Sralph switch (resp) { 748978e44c9Sralph case '\0': 749978e44c9Sralph return(0); 750978e44c9Sralph 751978e44c9Sralph default: 752978e44c9Sralph *cp++ = resp; 753978e44c9Sralph /* fall into... */ 754978e44c9Sralph case '\1': 755978e44c9Sralph case '\2': 756978e44c9Sralph errs++; 757978e44c9Sralph do { 758978e44c9Sralph if (read(rem, cp, 1) != 1) 759978e44c9Sralph lostconn(); 760*d49851feSralph } while (*cp++ != '\n' && cp < &buf[BUFSIZ]); 761*d49851feSralph if (buf[0] != '\n') { 762*d49851feSralph if (!iamremote) { 763*d49851feSralph fflush(stdout); 764978e44c9Sralph (void) write(2, buf, cp - buf); 765*d49851feSralph } 766978e44c9Sralph if (lfp != NULL) 767978e44c9Sralph (void) fwrite(buf, 1, cp - buf, lfp); 768978e44c9Sralph } 769978e44c9Sralph if (resp == '\1') 770978e44c9Sralph return(-1); 771978e44c9Sralph cleanup(); 772978e44c9Sralph } 773978e44c9Sralph /*NOTREACHED*/ 774978e44c9Sralph } 775978e44c9Sralph 776978e44c9Sralph lostconn() 777978e44c9Sralph { 778978e44c9Sralph if (!iamremote) 779978e44c9Sralph fprintf(stderr, "rdist: lost connection\n"); 780978e44c9Sralph cleanup(); 781978e44c9Sralph } 782