1 1.33 mrg /* $NetBSD: server.c,v 1.33 2019/02/03 03:19:29 mrg Exp $ */ 2 1.11 thorpej 3 1.1 cgd /* 4 1.5 cgd * Copyright (c) 1983, 1993 5 1.5 cgd * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.27 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.13 lukem #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.11 thorpej #if 0 35 1.11 thorpej static char sccsid[] = "@(#)server.c 8.1 (Berkeley) 6/9/93"; 36 1.11 thorpej #else 37 1.33 mrg __RCSID("$NetBSD: server.c,v 1.33 2019/02/03 03:19:29 mrg Exp $"); 38 1.11 thorpej #endif 39 1.1 cgd #endif /* not lint */ 40 1.1 cgd 41 1.12 mrg #include <sys/types.h> 42 1.5 cgd #include <sys/wait.h> 43 1.12 mrg 44 1.12 mrg #include <errno.h> 45 1.23 wiz #include <fcntl.h> 46 1.23 wiz #include <grp.h> 47 1.12 mrg #include <pwd.h> 48 1.23 wiz #include <stdarg.h> 49 1.12 mrg 50 1.1 cgd #include "defs.h" 51 1.1 cgd 52 1.18 mrg #define ack() do { if (write(rem, "\0\n", 2) < 0) error("ack failed: %s\n", strerror(errno)); } while (0) 53 1.18 mrg #define err() do { if (write(rem, "\1\n", 2) < 0) error("err failed: %s\n", strerror(errno)); } while (0) 54 1.1 cgd 55 1.1 cgd struct linkbuf *ihead; /* list of files with more than one link */ 56 1.1 cgd char buf[BUFSIZ]; /* general purpose buffer */ 57 1.1 cgd char target[BUFSIZ]; /* target/source directory name */ 58 1.1 cgd char *tp; /* pointer to end of target name */ 59 1.1 cgd char *Tdest; /* pointer to last T dest*/ 60 1.28 mycroft char *Destcopy; /* pointer to current dest */ 61 1.28 mycroft int Destcopylen; /* length of destination directory name */ 62 1.28 mycroft int Sourcelen; /* length of source directory name */ 63 1.1 cgd int catname; /* cat name to target name */ 64 1.1 cgd char *stp[32]; /* stack of saved tp's for directories */ 65 1.1 cgd int oumask; /* old umask for creating files */ 66 1.1 cgd 67 1.1 cgd extern FILE *lfp; /* log file for mailing changes */ 68 1.1 cgd 69 1.23 wiz static int chkparent(char *); 70 1.23 wiz static void clean(char *); 71 1.23 wiz static void comment(char *); 72 1.23 wiz static void dospecial(char *); 73 1.23 wiz static int fchtogm(int, char *, time_t, char *, char *, mode_t); 74 1.23 wiz static void hardlink(char *); 75 1.23 wiz static void note(const char *, ...) 76 1.19 is __attribute__((__format__(__printf__, 1, 2))); 77 1.23 wiz static void query(char *); 78 1.23 wiz static void recvf(char *, int); 79 1.23 wiz static void removeit(struct stat *); 80 1.23 wiz static int response(void); 81 1.23 wiz static void rmchk(int); 82 1.5 cgd static struct linkbuf * 83 1.23 wiz savelink(struct stat *); 84 1.23 wiz static void sendf(char *, int); 85 1.23 wiz static int update(char *, int, struct stat *); 86 1.1 cgd 87 1.1 cgd /* 88 1.1 cgd * Server routine to read requests and process them. 89 1.1 cgd * Commands are: 90 1.1 cgd * Tname - Transmit file if out of date 91 1.1 cgd * Vname - Verify if file out of date or not 92 1.1 cgd * Qname - Query if file exists. Return mtime & size if it does. 93 1.1 cgd */ 94 1.5 cgd void 95 1.23 wiz server(void) 96 1.1 cgd { 97 1.1 cgd char cmdbuf[BUFSIZ]; 98 1.13 lukem char *cp; 99 1.1 cgd 100 1.1 cgd signal(SIGHUP, cleanup); 101 1.1 cgd signal(SIGINT, cleanup); 102 1.1 cgd signal(SIGQUIT, cleanup); 103 1.1 cgd signal(SIGTERM, cleanup); 104 1.1 cgd signal(SIGPIPE, cleanup); 105 1.1 cgd 106 1.1 cgd rem = 0; 107 1.1 cgd oumask = umask(0); 108 1.9 thorpej (void) snprintf(buf, sizeof(buf), "V%d\n", VERSION); 109 1.18 mrg if (write(rem, buf, strlen(buf)) < 0) 110 1.18 mrg error("server: could not write remote end: %s\n", 111 1.18 mrg strerror(errno)); 112 1.1 cgd 113 1.1 cgd for (;;) { 114 1.1 cgd cp = cmdbuf; 115 1.1 cgd if (read(rem, cp, 1) <= 0) 116 1.1 cgd return; 117 1.1 cgd if (*cp++ == '\n') { 118 1.1 cgd error("server: expected control record\n"); 119 1.1 cgd continue; 120 1.1 cgd } 121 1.1 cgd do { 122 1.1 cgd if (read(rem, cp, 1) != 1) 123 1.5 cgd cleanup(0); 124 1.1 cgd } while (*cp++ != '\n' && cp < &cmdbuf[BUFSIZ]); 125 1.1 cgd *--cp = '\0'; 126 1.1 cgd cp = cmdbuf; 127 1.1 cgd switch (*cp++) { 128 1.1 cgd case 'T': /* init target file/directory name */ 129 1.1 cgd catname = 1; /* target should be directory */ 130 1.1 cgd goto dotarget; 131 1.1 cgd 132 1.1 cgd case 't': /* init target file/directory name */ 133 1.1 cgd catname = 0; 134 1.1 cgd dotarget: 135 1.1 cgd if (exptilde(target, cp) == NULL) 136 1.1 cgd continue; 137 1.1 cgd tp = target; 138 1.1 cgd while (*tp) 139 1.1 cgd tp++; 140 1.1 cgd ack(); 141 1.1 cgd continue; 142 1.1 cgd 143 1.1 cgd case 'R': /* Transfer a regular file. */ 144 1.1 cgd recvf(cp, S_IFREG); 145 1.1 cgd continue; 146 1.1 cgd 147 1.1 cgd case 'D': /* Transfer a directory. */ 148 1.1 cgd recvf(cp, S_IFDIR); 149 1.1 cgd continue; 150 1.1 cgd 151 1.1 cgd case 'K': /* Transfer symbolic link. */ 152 1.1 cgd recvf(cp, S_IFLNK); 153 1.1 cgd continue; 154 1.1 cgd 155 1.1 cgd case 'k': /* Transfer hard link. */ 156 1.1 cgd hardlink(cp); 157 1.1 cgd continue; 158 1.1 cgd 159 1.1 cgd case 'E': /* End. (of directory) */ 160 1.1 cgd *tp = '\0'; 161 1.1 cgd if (catname <= 0) { 162 1.1 cgd error("server: too many 'E's\n"); 163 1.1 cgd continue; 164 1.1 cgd } 165 1.1 cgd tp = stp[--catname]; 166 1.1 cgd *tp = '\0'; 167 1.1 cgd ack(); 168 1.1 cgd continue; 169 1.1 cgd 170 1.1 cgd case 'C': /* Clean. Cleanup a directory */ 171 1.1 cgd clean(cp); 172 1.1 cgd continue; 173 1.1 cgd 174 1.1 cgd case 'Q': /* Query. Does the file/directory exist? */ 175 1.1 cgd query(cp); 176 1.1 cgd continue; 177 1.1 cgd 178 1.1 cgd case 'S': /* Special. Execute commands */ 179 1.1 cgd dospecial(cp); 180 1.1 cgd continue; 181 1.1 cgd 182 1.1 cgd #ifdef notdef 183 1.1 cgd /* 184 1.1 cgd * These entries are reserved but not currently used. 185 1.1 cgd * The intent is to allow remote hosts to have master copies. 186 1.1 cgd * Currently, only the host rdist runs on can have masters. 187 1.1 cgd */ 188 1.1 cgd case 'X': /* start a new list of files to exclude */ 189 1.1 cgd except = bp = NULL; 190 1.1 cgd case 'x': /* add name to list of files to exclude */ 191 1.1 cgd if (*cp == '\0') { 192 1.1 cgd ack(); 193 1.1 cgd continue; 194 1.1 cgd } 195 1.1 cgd if (*cp == '~') { 196 1.1 cgd if (exptilde(buf, cp) == NULL) 197 1.1 cgd continue; 198 1.1 cgd cp = buf; 199 1.1 cgd } 200 1.1 cgd if (bp == NULL) 201 1.1 cgd except = bp = expand(makeblock(NAME, cp), E_VARS); 202 1.1 cgd else 203 1.1 cgd bp->b_next = expand(makeblock(NAME, cp), E_VARS); 204 1.1 cgd while (bp->b_next != NULL) 205 1.1 cgd bp = bp->b_next; 206 1.1 cgd ack(); 207 1.1 cgd continue; 208 1.1 cgd 209 1.1 cgd case 'I': /* Install. Transfer file if out of date. */ 210 1.1 cgd opts = 0; 211 1.1 cgd while (*cp >= '0' && *cp <= '7') 212 1.1 cgd opts = (opts << 3) | (*cp++ - '0'); 213 1.1 cgd if (*cp++ != ' ') { 214 1.1 cgd error("server: options not delimited\n"); 215 1.1 cgd return; 216 1.1 cgd } 217 1.1 cgd install(cp, opts); 218 1.1 cgd continue; 219 1.1 cgd 220 1.1 cgd case 'L': /* Log. save message in log file */ 221 1.1 cgd log(lfp, cp); 222 1.1 cgd continue; 223 1.1 cgd #endif 224 1.1 cgd 225 1.1 cgd case '\1': 226 1.1 cgd nerrs++; 227 1.1 cgd continue; 228 1.1 cgd 229 1.1 cgd case '\2': 230 1.1 cgd return; 231 1.1 cgd 232 1.1 cgd default: 233 1.1 cgd error("server: unknown command '%s'\n", cp); 234 1.33 mrg /* FALLTHROUGH */ 235 1.1 cgd case '\0': 236 1.1 cgd continue; 237 1.1 cgd } 238 1.1 cgd } 239 1.1 cgd } 240 1.1 cgd 241 1.1 cgd /* 242 1.1 cgd * Update the file(s) if they are different. 243 1.1 cgd * destdir = 1 if destination should be a directory 244 1.1 cgd * (i.e., more than one source is being copied to the same destination). 245 1.1 cgd */ 246 1.5 cgd void 247 1.23 wiz install(char *src, char *dest, int destdir, int opts) 248 1.1 cgd { 249 1.1 cgd char *rname; 250 1.1 cgd char destcopy[BUFSIZ]; 251 1.1 cgd 252 1.1 cgd if (dest == NULL) { 253 1.1 cgd opts &= ~WHOLE; /* WHOLE mode only useful if renaming */ 254 1.1 cgd dest = src; 255 1.28 mycroft } else if (!(opts & WHOLE)) { 256 1.28 mycroft /* prepare for proper renaming of directory trees */ 257 1.28 mycroft Destcopy = destcopy; 258 1.28 mycroft Destcopylen = strlen(dest); 259 1.28 mycroft while (Destcopylen > 0 && dest[Destcopylen] == '/') 260 1.28 mycroft Destcopylen--; 261 1.1 cgd } 262 1.28 mycroft strlcpy(destcopy, dest, sizeof(destcopy)); 263 1.1 cgd 264 1.1 cgd if (nflag || debug) { 265 1.1 cgd printf("%s%s%s%s%s %s %s\n", opts & VERIFY ? "verify":"install", 266 1.1 cgd opts & WHOLE ? " -w" : "", 267 1.1 cgd opts & YOUNGER ? " -y" : "", 268 1.1 cgd opts & COMPARE ? " -b" : "", 269 1.1 cgd opts & REMOVE ? " -R" : "", src, dest); 270 1.1 cgd if (nflag) 271 1.1 cgd return; 272 1.1 cgd } 273 1.1 cgd 274 1.1 cgd rname = exptilde(target, src); 275 1.1 cgd if (rname == NULL) 276 1.1 cgd return; 277 1.1 cgd tp = target; 278 1.1 cgd while (*tp) 279 1.1 cgd tp++; 280 1.28 mycroft if (Destcopy) { 281 1.28 mycroft /* We can only do this after expansion of src */ 282 1.28 mycroft Sourcelen = strlen(target); 283 1.28 mycroft while (Sourcelen > 0 && target[Sourcelen] == '/') 284 1.28 mycroft Sourcelen--; 285 1.28 mycroft } 286 1.1 cgd /* 287 1.1 cgd * If we are renaming a directory and we want to preserve 288 1.21 wiz * the directory hierarchy (-w), we must strip off the leading 289 1.1 cgd * directory name and preserve the rest. 290 1.1 cgd */ 291 1.1 cgd if (opts & WHOLE) { 292 1.1 cgd while (*rname == '/') 293 1.1 cgd rname++; 294 1.1 cgd destdir = 1; 295 1.1 cgd } else { 296 1.13 lukem rname = strrchr(target, '/'); 297 1.1 cgd if (rname == NULL) 298 1.1 cgd rname = target; 299 1.1 cgd else 300 1.1 cgd rname++; 301 1.1 cgd } 302 1.1 cgd if (debug) 303 1.1 cgd printf("target = %s, rname = %s\n", target, rname); 304 1.1 cgd /* 305 1.1 cgd * Pass the destination file/directory name to remote. 306 1.1 cgd */ 307 1.9 thorpej (void) snprintf(buf, sizeof(buf), "%c%s\n", destdir ? 'T' : 't', dest); 308 1.1 cgd if (debug) 309 1.1 cgd printf("buf = %s", buf); 310 1.18 mrg if (write(rem, buf, strlen(buf)) < 0) 311 1.18 mrg error("could not pass filename to remote: %s\n", 312 1.18 mrg strerror(errno)); 313 1.1 cgd if (response() < 0) 314 1.1 cgd return; 315 1.1 cgd 316 1.28 mycroft if (destdir) 317 1.1 cgd Tdest = destcopy; 318 1.1 cgd sendf(rname, opts); 319 1.28 mycroft Destcopy = 0; 320 1.1 cgd Tdest = 0; 321 1.1 cgd } 322 1.1 cgd 323 1.1 cgd #define protoname() (pw ? pw->pw_name : user) 324 1.1 cgd #define protogroup() (gr ? gr->gr_name : group) 325 1.1 cgd /* 326 1.1 cgd * Transfer the file or directory in target[]. 327 1.1 cgd * rname is the name of the file on the remote host. 328 1.1 cgd */ 329 1.5 cgd static void 330 1.23 wiz sendf(char *rname, int opts) 331 1.1 cgd { 332 1.13 lukem struct subcmd *sc; 333 1.1 cgd struct stat stb; 334 1.1 cgd int sizerr, f, u, len; 335 1.1 cgd off_t i; 336 1.1 cgd DIR *d; 337 1.16 christos struct dirent *dp; 338 1.1 cgd char *otp, *cp; 339 1.1 cgd extern struct subcmd *subcmds; 340 1.1 cgd static char user[15], group[15]; 341 1.1 cgd 342 1.1 cgd if (debug) 343 1.1 cgd printf("sendf(%s, %x)\n", rname, opts); 344 1.1 cgd 345 1.1 cgd if (except(target)) 346 1.1 cgd return; 347 1.1 cgd if ((opts & FOLLOW ? stat(target, &stb) : lstat(target, &stb)) < 0) { 348 1.1 cgd error("%s: %s\n", target, strerror(errno)); 349 1.1 cgd return; 350 1.1 cgd } 351 1.1 cgd if ((u = update(rname, opts, &stb)) == 0) { 352 1.14 mycroft if (S_ISREG(stb.st_mode) && stb.st_nlink > 1) 353 1.1 cgd (void) savelink(&stb); 354 1.1 cgd return; 355 1.1 cgd } 356 1.1 cgd 357 1.1 cgd if (pw == NULL || pw->pw_uid != stb.st_uid) 358 1.1 cgd if ((pw = getpwuid(stb.st_uid)) == NULL) { 359 1.24 thorpej dolog(lfp, "%s: no password entry for uid %d \n", 360 1.1 cgd target, stb.st_uid); 361 1.1 cgd pw = NULL; 362 1.13 lukem (void)snprintf(user, sizeof(user), ":%lu", 363 1.13 lukem (u_long)stb.st_uid); 364 1.1 cgd } 365 1.1 cgd if (gr == NULL || gr->gr_gid != stb.st_gid) 366 1.1 cgd if ((gr = getgrgid(stb.st_gid)) == NULL) { 367 1.24 thorpej dolog(lfp, "%s: no name for group %d\n", 368 1.1 cgd target, stb.st_gid); 369 1.1 cgd gr = NULL; 370 1.9 thorpej (void)snprintf(group, sizeof(group), ":%lu", 371 1.13 lukem (u_long)stb.st_gid); 372 1.1 cgd } 373 1.1 cgd if (u == 1) { 374 1.1 cgd if (opts & VERIFY) { 375 1.24 thorpej dolog(lfp, "need to install: %s\n", target); 376 1.1 cgd goto dospecial; 377 1.1 cgd } 378 1.24 thorpej dolog(lfp, "installing: %s\n", target); 379 1.1 cgd opts &= ~(COMPARE|REMOVE); 380 1.1 cgd } 381 1.1 cgd 382 1.1 cgd switch (stb.st_mode & S_IFMT) { 383 1.1 cgd case S_IFDIR: 384 1.1 cgd if ((d = opendir(target)) == NULL) { 385 1.1 cgd error("%s: %s\n", target, strerror(errno)); 386 1.1 cgd return; 387 1.1 cgd } 388 1.9 thorpej (void) snprintf(buf, sizeof(buf), "D%o %04o 0 0 %s %s %s\n", 389 1.9 thorpej opts, stb.st_mode & 07777, protoname(), protogroup(), 390 1.9 thorpej rname); 391 1.1 cgd if (debug) 392 1.1 cgd printf("buf = %s", buf); 393 1.18 mrg if (write(rem, buf, strlen(buf)) < 0) 394 1.18 mrg error("can not write dir spec to remote: %s\n", 395 1.18 mrg strerror(errno)); 396 1.18 mrg 397 1.1 cgd if (response() < 0) { 398 1.1 cgd closedir(d); 399 1.1 cgd return; 400 1.1 cgd } 401 1.1 cgd 402 1.1 cgd if (opts & REMOVE) 403 1.1 cgd rmchk(opts); 404 1.1 cgd 405 1.1 cgd otp = tp; 406 1.1 cgd len = tp - target; 407 1.13 lukem while ((dp = readdir(d)) != NULL) { 408 1.1 cgd if (!strcmp(dp->d_name, ".") || 409 1.1 cgd !strcmp(dp->d_name, "..")) 410 1.1 cgd continue; 411 1.1 cgd if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { 412 1.1 cgd error("%s/%s: Name too long\n", target, 413 1.1 cgd dp->d_name); 414 1.1 cgd continue; 415 1.1 cgd } 416 1.1 cgd tp = otp; 417 1.1 cgd *tp++ = '/'; 418 1.1 cgd cp = dp->d_name; 419 1.13 lukem while ((*tp++ = *cp++) != 0) 420 1.1 cgd ; 421 1.1 cgd tp--; 422 1.1 cgd sendf(dp->d_name, opts); 423 1.1 cgd } 424 1.1 cgd closedir(d); 425 1.18 mrg if (write(rem, "E\n", 2) < 0) 426 1.18 mrg error("can not write E to remote: %s\n", 427 1.18 mrg strerror(errno)); 428 1.1 cgd (void) response(); 429 1.1 cgd tp = otp; 430 1.1 cgd *tp = '\0'; 431 1.1 cgd return; 432 1.1 cgd 433 1.1 cgd case S_IFLNK: 434 1.1 cgd if (u != 1) 435 1.1 cgd opts |= COMPARE; 436 1.1 cgd if (stb.st_nlink > 1) { 437 1.1 cgd struct linkbuf *lp; 438 1.1 cgd 439 1.1 cgd if ((lp = savelink(&stb)) != NULL) { 440 1.1 cgd /* install link */ 441 1.1 cgd if (*lp->target == 0) 442 1.9 thorpej (void) snprintf(buf, sizeof(buf), 443 1.9 thorpej "k%o %s %s\n", opts, lp->pathname, rname); 444 1.1 cgd else 445 1.9 thorpej (void) snprintf(buf, sizeof(buf), 446 1.9 thorpej "k%o %s/%s %s\n", opts, lp->target, 447 1.9 thorpej lp->pathname, rname); 448 1.1 cgd if (debug) 449 1.1 cgd printf("buf = %s", buf); 450 1.18 mrg if (write(rem, buf, strlen(buf)) < 0) 451 1.18 mrg error("can not write link spec to remote: %s\n", 452 1.18 mrg strerror(errno)); 453 1.1 cgd (void) response(); 454 1.1 cgd return; 455 1.1 cgd } 456 1.1 cgd } 457 1.20 lukem (void) snprintf(buf, sizeof(buf), "K%o %o %lld %ld %s %s %s\n", 458 1.15 mrg opts, stb.st_mode & 07777, (unsigned long long)stb.st_size, 459 1.15 mrg (u_long)stb.st_mtime, protoname(), protogroup(), rname); 460 1.1 cgd if (debug) 461 1.1 cgd printf("buf = %s", buf); 462 1.18 mrg if (write(rem, buf, strlen(buf)) < 0) 463 1.18 mrg error("can not write link spec to remote: %s\n", 464 1.18 mrg strerror(errno)); 465 1.1 cgd if (response() < 0) 466 1.1 cgd return; 467 1.1 cgd sizerr = (readlink(target, buf, BUFSIZ) != stb.st_size); 468 1.18 mrg if (write(rem, buf, stb.st_size) < 0) 469 1.18 mrg error("can not write link name to remote: %s\n", 470 1.18 mrg strerror(errno)); 471 1.1 cgd if (debug) 472 1.1 cgd printf("readlink = %.*s\n", (int)stb.st_size, buf); 473 1.1 cgd goto done; 474 1.1 cgd 475 1.1 cgd case S_IFREG: 476 1.1 cgd break; 477 1.1 cgd 478 1.1 cgd default: 479 1.1 cgd error("%s: not a file or directory\n", target); 480 1.1 cgd return; 481 1.1 cgd } 482 1.1 cgd 483 1.1 cgd if (u == 2) { 484 1.1 cgd if (opts & VERIFY) { 485 1.24 thorpej dolog(lfp, "need to update: %s\n", target); 486 1.1 cgd goto dospecial; 487 1.1 cgd } 488 1.24 thorpej dolog(lfp, "updating: %s\n", target); 489 1.1 cgd } 490 1.1 cgd 491 1.1 cgd if (stb.st_nlink > 1) { 492 1.1 cgd struct linkbuf *lp; 493 1.1 cgd 494 1.1 cgd if ((lp = savelink(&stb)) != NULL) { 495 1.1 cgd /* install link */ 496 1.1 cgd if (*lp->target == 0) 497 1.9 thorpej (void) snprintf(buf, sizeof(buf), "k%o %s %s\n", opts, 498 1.1 cgd lp->pathname, rname); 499 1.1 cgd else 500 1.9 thorpej (void) snprintf(buf, sizeof(buf), "k%o %s/%s %s\n", 501 1.9 thorpej opts, lp->target, lp->pathname, rname); 502 1.1 cgd if (debug) 503 1.1 cgd printf("buf = %s", buf); 504 1.18 mrg if (write(rem, buf, strlen(buf)) <0) 505 1.18 mrg error("write of file name failed: %s\n", 506 1.18 mrg strerror(errno)); 507 1.1 cgd (void) response(); 508 1.1 cgd return; 509 1.1 cgd } 510 1.1 cgd } 511 1.1 cgd 512 1.5 cgd if ((f = open(target, O_RDONLY, 0)) < 0) { 513 1.1 cgd error("%s: %s\n", target, strerror(errno)); 514 1.1 cgd return; 515 1.1 cgd } 516 1.20 lukem (void)snprintf(buf, sizeof(buf), "R%o %o %lld %lu %s %s %s\n", opts, 517 1.15 mrg stb.st_mode & 07777, (unsigned long long)stb.st_size, 518 1.15 mrg (u_long)stb.st_mtime, protoname(), protogroup(), rname); 519 1.1 cgd if (debug) 520 1.1 cgd printf("buf = %s", buf); 521 1.18 mrg if (write(rem, buf, strlen(buf)) < 0) 522 1.18 mrg error("write of file name failed: %s\n", strerror(errno)); 523 1.1 cgd if (response() < 0) { 524 1.1 cgd (void) close(f); 525 1.1 cgd return; 526 1.1 cgd } 527 1.1 cgd sizerr = 0; 528 1.1 cgd for (i = 0; i < stb.st_size; i += BUFSIZ) { 529 1.1 cgd int amt = BUFSIZ; 530 1.1 cgd if (i + amt > stb.st_size) 531 1.1 cgd amt = stb.st_size - i; 532 1.1 cgd if (sizerr == 0 && read(f, buf, amt) != amt) 533 1.1 cgd sizerr = 1; 534 1.18 mrg if (write(rem, buf, amt) < 0) 535 1.18 mrg error("write of file data failed: %s\n", strerror(errno)); 536 1.1 cgd } 537 1.1 cgd (void) close(f); 538 1.1 cgd done: 539 1.1 cgd if (sizerr) { 540 1.1 cgd error("%s: file changed size\n", target); 541 1.1 cgd err(); 542 1.1 cgd } else 543 1.1 cgd ack(); 544 1.1 cgd f = response(); 545 1.13 lukem if (f < 0 || (f == 0 && (opts & COMPARE))) 546 1.1 cgd return; 547 1.1 cgd dospecial: 548 1.1 cgd for (sc = subcmds; sc != NULL; sc = sc->sc_next) { 549 1.1 cgd if (sc->sc_type != SPECIAL) 550 1.1 cgd continue; 551 1.1 cgd if (sc->sc_args != NULL && !inlist(sc->sc_args, target)) 552 1.1 cgd continue; 553 1.24 thorpej dolog(lfp, "special \"%s\"\n", sc->sc_name); 554 1.1 cgd if (opts & VERIFY) 555 1.1 cgd continue; 556 1.9 thorpej (void) snprintf(buf, sizeof(buf), "SFILE=%s;%s\n", target, 557 1.9 thorpej sc->sc_name); 558 1.1 cgd if (debug) 559 1.1 cgd printf("buf = %s", buf); 560 1.18 mrg if (write(rem, buf, strlen(buf)) < 0) 561 1.18 mrg error("write of special failed: %s\n", strerror(errno)); 562 1.1 cgd while (response() > 0) 563 1.1 cgd ; 564 1.1 cgd } 565 1.1 cgd } 566 1.1 cgd 567 1.5 cgd static struct linkbuf * 568 1.31 lukem savelink(struct stat *st) 569 1.1 cgd { 570 1.1 cgd struct linkbuf *lp; 571 1.1 cgd 572 1.1 cgd for (lp = ihead; lp != NULL; lp = lp->nextp) 573 1.31 lukem if (lp->inum == st->st_ino && lp->devnum == st->st_dev) { 574 1.1 cgd lp->count--; 575 1.1 cgd return(lp); 576 1.1 cgd } 577 1.1 cgd lp = (struct linkbuf *) malloc(sizeof(*lp)); 578 1.1 cgd if (lp == NULL) 579 1.24 thorpej dolog(lfp, "out of memory, link information lost\n"); 580 1.1 cgd else { 581 1.1 cgd lp->nextp = ihead; 582 1.1 cgd ihead = lp; 583 1.31 lukem lp->inum = st->st_ino; 584 1.31 lukem lp->devnum = st->st_dev; 585 1.31 lukem lp->count = st->st_nlink - 1; 586 1.28 mycroft if (Destcopy) { 587 1.28 mycroft /* 588 1.28 mycroft * Change the starting directory of target 589 1.28 mycroft * into the destination directory 590 1.28 mycroft */ 591 1.28 mycroft strncpy(lp->pathname, Destcopy, Destcopylen); 592 1.28 mycroft strlcpy(lp->pathname + Destcopylen, target + Sourcelen, sizeof(lp->pathname) - Destcopylen); 593 1.28 mycroft } else 594 1.28 mycroft strlcpy(lp->pathname, target, sizeof(lp->pathname)); 595 1.1 cgd if (Tdest) 596 1.26 itojun strlcpy(lp->target, Tdest, sizeof(lp->target)); 597 1.1 cgd else 598 1.1 cgd *lp->target = 0; 599 1.1 cgd } 600 1.1 cgd return(NULL); 601 1.1 cgd } 602 1.1 cgd 603 1.1 cgd /* 604 1.1 cgd * Check to see if file needs to be updated on the remote machine. 605 1.1 cgd * Returns 0 if no update, 1 if remote doesn't exist, 2 if out of date 606 1.1 cgd * and 3 if comparing binaries to determine if out of date. 607 1.1 cgd */ 608 1.5 cgd static int 609 1.31 lukem update(char *rname, int opts, struct stat *st) 610 1.1 cgd { 611 1.13 lukem char *cp, *s; 612 1.13 lukem off_t size; 613 1.13 lukem time_t mtime; 614 1.1 cgd 615 1.1 cgd if (debug) 616 1.31 lukem printf("update(%s, %lx, %lx)\n", rname, (long)opts, (long)st); 617 1.1 cgd 618 1.1 cgd /* 619 1.1 cgd * Check to see if the file exists on the remote machine. 620 1.1 cgd */ 621 1.9 thorpej (void) snprintf(buf, sizeof(buf), "Q%s\n", rname); 622 1.1 cgd if (debug) 623 1.1 cgd printf("buf = %s", buf); 624 1.18 mrg if (write(rem, buf, strlen(buf)) < 0) 625 1.18 mrg error("write to remote failed: %s\n", strerror(errno)); 626 1.1 cgd again: 627 1.1 cgd cp = s = buf; 628 1.1 cgd do { 629 1.1 cgd if (read(rem, cp, 1) != 1) 630 1.5 cgd lostconn(0); 631 1.1 cgd } while (*cp++ != '\n' && cp < &buf[BUFSIZ]); 632 1.1 cgd 633 1.1 cgd switch (*s++) { 634 1.1 cgd case 'Y': 635 1.1 cgd break; 636 1.1 cgd 637 1.1 cgd case 'N': /* file doesn't exist so install it */ 638 1.1 cgd return(1); 639 1.1 cgd 640 1.1 cgd case '\1': 641 1.1 cgd nerrs++; 642 1.1 cgd if (*s != '\n') { 643 1.1 cgd if (!iamremote) { 644 1.1 cgd fflush(stdout); 645 1.1 cgd (void) write(2, s, cp - s); 646 1.1 cgd } 647 1.1 cgd if (lfp != NULL) 648 1.1 cgd (void) fwrite(s, 1, cp - s, lfp); 649 1.1 cgd } 650 1.1 cgd return(0); 651 1.1 cgd 652 1.1 cgd case '\3': 653 1.1 cgd *--cp = '\0'; 654 1.1 cgd if (lfp != NULL) 655 1.24 thorpej dolog(lfp, "update: note: %s\n", s); 656 1.1 cgd goto again; 657 1.1 cgd 658 1.1 cgd default: 659 1.1 cgd *--cp = '\0'; 660 1.1 cgd error("update: unexpected response '%s'\n", s); 661 1.1 cgd return(0); 662 1.1 cgd } 663 1.1 cgd 664 1.1 cgd if (*s == '\n') 665 1.1 cgd return(2); 666 1.1 cgd 667 1.1 cgd if (opts & COMPARE) 668 1.1 cgd return(3); 669 1.1 cgd 670 1.1 cgd size = 0; 671 1.17 christos while (isdigit((unsigned char)*s)) 672 1.1 cgd size = size * 10 + (*s++ - '0'); 673 1.1 cgd if (*s++ != ' ') { 674 1.1 cgd error("update: size not delimited\n"); 675 1.1 cgd return(0); 676 1.1 cgd } 677 1.1 cgd mtime = 0; 678 1.17 christos while (isdigit((unsigned char)*s)) 679 1.1 cgd mtime = mtime * 10 + (*s++ - '0'); 680 1.1 cgd if (*s != '\n') { 681 1.1 cgd error("update: mtime not delimited\n"); 682 1.1 cgd return(0); 683 1.1 cgd } 684 1.1 cgd /* 685 1.1 cgd * File needs to be updated? 686 1.1 cgd */ 687 1.1 cgd if (opts & YOUNGER) { 688 1.31 lukem if (st->st_mtime == mtime) 689 1.1 cgd return(0); 690 1.31 lukem if (st->st_mtime < mtime) { 691 1.24 thorpej dolog(lfp, "Warning: %s: remote copy is newer\n", 692 1.24 thorpej target); 693 1.1 cgd return(0); 694 1.1 cgd } 695 1.31 lukem } else if (st->st_mtime == mtime && st->st_size == size) 696 1.1 cgd return(0); 697 1.1 cgd return(2); 698 1.1 cgd } 699 1.1 cgd 700 1.1 cgd /* 701 1.1 cgd * Query. Check to see if file exists. Return one of the following: 702 1.1 cgd * N\n - doesn't exist 703 1.1 cgd * Ysize mtime\n - exists and its a regular file (size & mtime of file) 704 1.1 cgd * Y\n - exists and its a directory or symbolic link 705 1.1 cgd * ^Aerror message\n 706 1.1 cgd */ 707 1.5 cgd static void 708 1.23 wiz query(char *name) 709 1.1 cgd { 710 1.1 cgd struct stat stb; 711 1.1 cgd 712 1.1 cgd if (catname) 713 1.10 thorpej (void) snprintf(tp, sizeof(target) - (tp - target), 714 1.10 thorpej "/%s", name); 715 1.1 cgd 716 1.1 cgd if (lstat(target, &stb) < 0) { 717 1.18 mrg if (errno == ENOENT) { 718 1.18 mrg if (write(rem, "N\n", 2) < 0) 719 1.18 mrg error("write to remote failed: %s\n", 720 1.18 mrg strerror(errno)); 721 1.18 mrg } else 722 1.1 cgd error("%s:%s: %s\n", host, target, strerror(errno)); 723 1.1 cgd *tp = '\0'; 724 1.1 cgd return; 725 1.1 cgd } 726 1.1 cgd 727 1.1 cgd switch (stb.st_mode & S_IFMT) { 728 1.1 cgd case S_IFREG: 729 1.20 lukem (void)snprintf(buf, sizeof(buf), "Y%lld %ld\n", 730 1.15 mrg (unsigned long long)stb.st_size, (u_long)stb.st_mtime); 731 1.18 mrg if (write(rem, buf, strlen(buf)) < 0) 732 1.18 mrg error("write to remote failed: %s\n", strerror(errno)); 733 1.1 cgd break; 734 1.1 cgd 735 1.1 cgd case S_IFLNK: 736 1.1 cgd case S_IFDIR: 737 1.18 mrg if (write(rem, "Y\n", 2) < 0) 738 1.18 mrg error("write to remote failed: %s\n", strerror(errno)); 739 1.1 cgd break; 740 1.1 cgd 741 1.1 cgd default: 742 1.1 cgd error("%s: not a file or directory\n", name); 743 1.1 cgd break; 744 1.1 cgd } 745 1.1 cgd *tp = '\0'; 746 1.1 cgd } 747 1.1 cgd 748 1.5 cgd static void 749 1.23 wiz recvf(char *cmd, int type) 750 1.1 cgd { 751 1.13 lukem char *cp = cmd; 752 1.32 christos int f = -1, opts = 0, wrerr; 753 1.14 mycroft mode_t mode; 754 1.1 cgd off_t i, size; 755 1.1 cgd time_t mtime; 756 1.1 cgd struct stat stb; 757 1.1 cgd char *owner, *group; 758 1.1 cgd char new[BUFSIZ]; 759 1.1 cgd extern char *tempname; 760 1.1 cgd 761 1.1 cgd while (*cp >= '0' && *cp <= '7') 762 1.1 cgd opts = (opts << 3) | (*cp++ - '0'); 763 1.1 cgd if (*cp++ != ' ') { 764 1.1 cgd error("recvf: options not delimited\n"); 765 1.1 cgd return; 766 1.1 cgd } 767 1.1 cgd mode = 0; 768 1.1 cgd while (*cp >= '0' && *cp <= '7') 769 1.1 cgd mode = (mode << 3) | (*cp++ - '0'); 770 1.1 cgd if (*cp++ != ' ') { 771 1.1 cgd error("recvf: mode not delimited\n"); 772 1.1 cgd return; 773 1.1 cgd } 774 1.1 cgd size = 0; 775 1.17 christos while (isdigit((unsigned char)*cp)) 776 1.1 cgd size = size * 10 + (*cp++ - '0'); 777 1.1 cgd if (*cp++ != ' ') { 778 1.1 cgd error("recvf: size not delimited\n"); 779 1.1 cgd return; 780 1.1 cgd } 781 1.1 cgd mtime = 0; 782 1.17 christos while (isdigit((unsigned char)*cp)) 783 1.1 cgd mtime = mtime * 10 + (*cp++ - '0'); 784 1.1 cgd if (*cp++ != ' ') { 785 1.1 cgd error("recvf: mtime not delimited\n"); 786 1.1 cgd return; 787 1.1 cgd } 788 1.1 cgd owner = cp; 789 1.1 cgd while (*cp && *cp != ' ') 790 1.1 cgd cp++; 791 1.1 cgd if (*cp != ' ') { 792 1.1 cgd error("recvf: owner name not delimited\n"); 793 1.1 cgd return; 794 1.1 cgd } 795 1.1 cgd *cp++ = '\0'; 796 1.1 cgd group = cp; 797 1.1 cgd while (*cp && *cp != ' ') 798 1.1 cgd cp++; 799 1.1 cgd if (*cp != ' ') { 800 1.1 cgd error("recvf: group name not delimited\n"); 801 1.1 cgd return; 802 1.1 cgd } 803 1.1 cgd *cp++ = '\0'; 804 1.1 cgd 805 1.1 cgd if (type == S_IFDIR) { 806 1.31 lukem if (catname >= (int)sizeof(stp)) { 807 1.1 cgd error("%s:%s: too many directory levels\n", 808 1.1 cgd host, target); 809 1.1 cgd return; 810 1.1 cgd } 811 1.1 cgd stp[catname] = tp; 812 1.1 cgd if (catname++) { 813 1.1 cgd *tp++ = '/'; 814 1.13 lukem while ((*tp++ = *cp++) != 0) 815 1.1 cgd ; 816 1.1 cgd tp--; 817 1.1 cgd } 818 1.1 cgd if (opts & VERIFY) { 819 1.1 cgd ack(); 820 1.1 cgd return; 821 1.1 cgd } 822 1.1 cgd if (lstat(target, &stb) == 0) { 823 1.14 mycroft if (S_ISDIR(stb.st_mode)) { 824 1.1 cgd if ((stb.st_mode & 07777) == mode) { 825 1.1 cgd ack(); 826 1.1 cgd return; 827 1.1 cgd } 828 1.1 cgd buf[0] = '\0'; 829 1.9 thorpej (void) snprintf(buf + 1, sizeof(buf) - 1, 830 1.18 mrg "%s: Warning: remote mode %o != local mode %o\n", 831 1.18 mrg target, stb.st_mode & 07777, mode); 832 1.18 mrg if (write(rem, buf, strlen(buf + 1) + 1) < 0) 833 1.18 mrg error("write to remote failed: %s\n", 834 1.18 mrg strerror(errno)); 835 1.1 cgd return; 836 1.1 cgd } 837 1.1 cgd errno = ENOTDIR; 838 1.14 mycroft } else if ((errno == ENOENT && mkdir(target, mode) == 0) || 839 1.13 lukem (chkparent(target) == 0 && mkdir(target, mode) == 0)) { 840 1.14 mycroft if (fchtogm(-1, target, mtime, owner, group, mode) == 0) 841 1.1 cgd ack(); 842 1.1 cgd return; 843 1.1 cgd } 844 1.1 cgd error("%s:%s: %s\n", host, target, strerror(errno)); 845 1.1 cgd tp = stp[--catname]; 846 1.1 cgd *tp = '\0'; 847 1.1 cgd return; 848 1.1 cgd } 849 1.1 cgd 850 1.1 cgd if (catname) 851 1.10 thorpej (void) snprintf(tp, sizeof(target) - (tp - target), "/%s", cp); 852 1.13 lukem cp = strrchr(target, '/'); 853 1.1 cgd if (cp == NULL) 854 1.26 itojun strlcpy(new, tempname, sizeof(new)); 855 1.1 cgd else if (cp == target) 856 1.9 thorpej (void) snprintf(new, sizeof(new), "/%s", tempname); 857 1.1 cgd else { 858 1.1 cgd *cp = '\0'; 859 1.9 thorpej (void) snprintf(new, sizeof(new), "%s/%s", target, tempname); 860 1.1 cgd *cp = '/'; 861 1.1 cgd } 862 1.1 cgd 863 1.1 cgd if (type == S_IFLNK) { 864 1.1 cgd int j; 865 1.1 cgd 866 1.1 cgd ack(); 867 1.1 cgd cp = buf; 868 1.1 cgd for (i = 0; i < size; i += j) { 869 1.1 cgd if ((j = read(rem, cp, size - i)) <= 0) 870 1.5 cgd cleanup(0); 871 1.1 cgd cp += j; 872 1.1 cgd } 873 1.1 cgd *cp = '\0'; 874 1.1 cgd if (response() < 0) { 875 1.1 cgd err(); 876 1.1 cgd return; 877 1.1 cgd } 878 1.1 cgd if (symlink(buf, new) < 0) { 879 1.1 cgd if (errno != ENOENT || chkparent(new) < 0 || 880 1.1 cgd symlink(buf, new) < 0) 881 1.5 cgd goto badnew1; 882 1.1 cgd } 883 1.1 cgd mode &= 0777; 884 1.1 cgd if (opts & COMPARE) { 885 1.1 cgd char tbuf[BUFSIZ]; 886 1.1 cgd 887 1.1 cgd if ((i = readlink(target, tbuf, BUFSIZ)) >= 0 && 888 1.1 cgd i == size && strncmp(buf, tbuf, size) == 0) { 889 1.1 cgd (void) unlink(new); 890 1.1 cgd ack(); 891 1.1 cgd return; 892 1.1 cgd } 893 1.1 cgd if (opts & VERIFY) 894 1.1 cgd goto differ; 895 1.1 cgd } 896 1.1 cgd goto fixup; 897 1.1 cgd } 898 1.1 cgd 899 1.1 cgd if ((f = creat(new, mode)) < 0) { 900 1.1 cgd if (errno != ENOENT || chkparent(new) < 0 || 901 1.1 cgd (f = creat(new, mode)) < 0) 902 1.5 cgd goto badnew1; 903 1.1 cgd } 904 1.1 cgd 905 1.1 cgd ack(); 906 1.1 cgd wrerr = 0; 907 1.1 cgd for (i = 0; i < size; i += BUFSIZ) { 908 1.1 cgd int amt = BUFSIZ; 909 1.1 cgd 910 1.1 cgd cp = buf; 911 1.1 cgd if (i + amt > size) 912 1.1 cgd amt = size - i; 913 1.1 cgd do { 914 1.1 cgd int j = read(rem, cp, amt); 915 1.1 cgd 916 1.1 cgd if (j <= 0) { 917 1.1 cgd (void) close(f); 918 1.1 cgd (void) unlink(new); 919 1.5 cgd cleanup(0); 920 1.1 cgd } 921 1.1 cgd amt -= j; 922 1.1 cgd cp += j; 923 1.1 cgd } while (amt > 0); 924 1.1 cgd amt = BUFSIZ; 925 1.1 cgd if (i + amt > size) 926 1.1 cgd amt = size - i; 927 1.1 cgd if (wrerr == 0 && write(f, buf, amt) != amt) { 928 1.1 cgd wrerr++; 929 1.1 cgd } 930 1.1 cgd } 931 1.1 cgd if (response() < 0) { 932 1.1 cgd err(); 933 1.5 cgd goto badnew2; 934 1.1 cgd } 935 1.5 cgd if (wrerr) 936 1.5 cgd goto badnew1; 937 1.1 cgd if (opts & COMPARE) { 938 1.1 cgd FILE *f1, *f2; 939 1.1 cgd int c; 940 1.1 cgd 941 1.1 cgd if ((f1 = fopen(target, "r")) == NULL) 942 1.5 cgd goto badtarget; 943 1.1 cgd if ((f2 = fopen(new, "r")) == NULL) { 944 1.5 cgd badnew1: error("%s:%s: %s\n", host, new, strerror(errno)); 945 1.5 cgd goto badnew2; 946 1.1 cgd } 947 1.1 cgd while ((c = getc(f1)) == getc(f2)) 948 1.1 cgd if (c == EOF) { 949 1.1 cgd (void) fclose(f1); 950 1.1 cgd (void) fclose(f2); 951 1.1 cgd ack(); 952 1.5 cgd goto badnew2; 953 1.1 cgd } 954 1.1 cgd (void) fclose(f1); 955 1.1 cgd (void) fclose(f2); 956 1.1 cgd if (opts & VERIFY) { 957 1.5 cgd differ: buf[0] = '\0'; 958 1.12 mrg (void)snprintf(buf + 1, sizeof(buf) - 1, 959 1.9 thorpej "need to update: %s\n",target); 960 1.1 cgd (void) write(rem, buf, strlen(buf + 1) + 1); 961 1.5 cgd goto badnew2; 962 1.1 cgd } 963 1.1 cgd } 964 1.1 cgd 965 1.14 mycroft if (fchtogm(f, new, mtime, owner, group, mode) < 0) { 966 1.12 mrg badnew2: 967 1.8 mrg if (f != -1) 968 1.8 mrg (void) close(f); 969 1.1 cgd (void) unlink(new); 970 1.1 cgd return; 971 1.1 cgd } 972 1.5 cgd (void) close(f); 973 1.5 cgd 974 1.5 cgd fixup: if (rename(new, target) < 0) { 975 1.5 cgd badtarget: error("%s:%s: %s\n", host, target, strerror(errno)); 976 1.1 cgd (void) unlink(new); 977 1.1 cgd return; 978 1.1 cgd } 979 1.5 cgd 980 1.1 cgd if (opts & COMPARE) { 981 1.1 cgd buf[0] = '\0'; 982 1.9 thorpej (void) snprintf(buf + 1, sizeof(buf) - 1, 983 1.9 thorpej "updated %s\n", target); 984 1.1 cgd (void) write(rem, buf, strlen(buf + 1) + 1); 985 1.1 cgd } else 986 1.1 cgd ack(); 987 1.1 cgd } 988 1.1 cgd 989 1.1 cgd /* 990 1.1 cgd * Creat a hard link to existing file. 991 1.1 cgd */ 992 1.5 cgd static void 993 1.23 wiz hardlink(char *cmd) 994 1.1 cgd { 995 1.13 lukem char *cp; 996 1.1 cgd struct stat stb; 997 1.1 cgd char *oldname; 998 1.1 cgd int opts, exists = 0; 999 1.1 cgd 1000 1.1 cgd cp = cmd; 1001 1.1 cgd opts = 0; 1002 1.1 cgd while (*cp >= '0' && *cp <= '7') 1003 1.1 cgd opts = (opts << 3) | (*cp++ - '0'); 1004 1.1 cgd if (*cp++ != ' ') { 1005 1.1 cgd error("hardlink: options not delimited\n"); 1006 1.1 cgd return; 1007 1.1 cgd } 1008 1.1 cgd oldname = cp; 1009 1.1 cgd while (*cp && *cp != ' ') 1010 1.1 cgd cp++; 1011 1.1 cgd if (*cp != ' ') { 1012 1.1 cgd error("hardlink: oldname name not delimited\n"); 1013 1.1 cgd return; 1014 1.1 cgd } 1015 1.1 cgd *cp++ = '\0'; 1016 1.1 cgd 1017 1.1 cgd if (catname) { 1018 1.10 thorpej (void) snprintf(tp, sizeof(target) - (tp - target), "/%s", cp); 1019 1.1 cgd } 1020 1.1 cgd if (lstat(target, &stb) == 0) { 1021 1.14 mycroft if (!S_ISREG(stb.st_mode) && !S_ISLNK(stb.st_mode)) { 1022 1.14 mycroft error("%s: %s: not a regular file\n", host, target); 1023 1.1 cgd return; 1024 1.1 cgd } 1025 1.1 cgd exists = 1; 1026 1.1 cgd } 1027 1.1 cgd if (chkparent(target) < 0 ) { 1028 1.1 cgd error("%s:%s: %s (no parent)\n", 1029 1.1 cgd host, target, strerror(errno)); 1030 1.1 cgd return; 1031 1.1 cgd } 1032 1.1 cgd if (exists && (unlink(target) < 0)) { 1033 1.1 cgd error("%s:%s: %s (unlink)\n", 1034 1.1 cgd host, target, strerror(errno)); 1035 1.1 cgd return; 1036 1.1 cgd } 1037 1.1 cgd if (link(oldname, target) < 0) { 1038 1.1 cgd error("%s:can't link %s to %s\n", 1039 1.1 cgd host, target, oldname); 1040 1.1 cgd return; 1041 1.1 cgd } 1042 1.1 cgd ack(); 1043 1.1 cgd } 1044 1.1 cgd 1045 1.1 cgd /* 1046 1.1 cgd * Check to see if parent directory exists and create one if not. 1047 1.1 cgd */ 1048 1.5 cgd static int 1049 1.23 wiz chkparent(char *name) 1050 1.1 cgd { 1051 1.13 lukem char *cp; 1052 1.1 cgd struct stat stb; 1053 1.1 cgd 1054 1.13 lukem cp = strrchr(name, '/'); 1055 1.1 cgd if (cp == NULL || cp == name) 1056 1.1 cgd return(0); 1057 1.1 cgd *cp = '\0'; 1058 1.1 cgd if (lstat(name, &stb) < 0) { 1059 1.1 cgd if (errno == ENOENT && chkparent(name) >= 0 && 1060 1.1 cgd mkdir(name, 0777 & ~oumask) >= 0) { 1061 1.1 cgd *cp = '/'; 1062 1.1 cgd return(0); 1063 1.1 cgd } 1064 1.14 mycroft } else if (S_ISDIR(stb.st_mode)) { 1065 1.1 cgd *cp = '/'; 1066 1.1 cgd return(0); 1067 1.1 cgd } 1068 1.1 cgd *cp = '/'; 1069 1.1 cgd return(-1); 1070 1.1 cgd } 1071 1.1 cgd 1072 1.1 cgd /* 1073 1.1 cgd * Change owner, group and mode of file. 1074 1.1 cgd */ 1075 1.5 cgd static int 1076 1.23 wiz fchtogm(int fd, char *file, time_t mtime, char *owner, char *group, __mode_t mode) 1077 1.1 cgd { 1078 1.13 lukem int i; 1079 1.14 mycroft struct timeval tv[2]; 1080 1.14 mycroft uid_t uid; 1081 1.14 mycroft gid_t gid; 1082 1.1 cgd extern char user[]; 1083 1.1 cgd 1084 1.1 cgd uid = userid; 1085 1.1 cgd if (userid == 0) { 1086 1.1 cgd if (*owner == ':') { 1087 1.1 cgd uid = atoi(owner + 1); 1088 1.1 cgd } else if (pw == NULL || strcmp(owner, pw->pw_name) != 0) { 1089 1.1 cgd if ((pw = getpwnam(owner)) == NULL) { 1090 1.1 cgd if (mode & 04000) { 1091 1.1 cgd note("%s:%s: unknown login name, clearing setuid", 1092 1.1 cgd host, owner); 1093 1.1 cgd mode &= ~04000; 1094 1.1 cgd uid = 0; 1095 1.1 cgd } 1096 1.1 cgd } else 1097 1.1 cgd uid = pw->pw_uid; 1098 1.1 cgd } else 1099 1.1 cgd uid = pw->pw_uid; 1100 1.1 cgd if (*group == ':') { 1101 1.1 cgd gid = atoi(group + 1); 1102 1.1 cgd goto ok; 1103 1.1 cgd } 1104 1.1 cgd } else if ((mode & 04000) && strcmp(user, owner) != 0) 1105 1.1 cgd mode &= ~04000; 1106 1.1 cgd gid = -1; 1107 1.1 cgd if (gr == NULL || strcmp(group, gr->gr_name) != 0) { 1108 1.1 cgd if ((*group == ':' && (getgrgid(gid = atoi(group + 1)) == NULL)) 1109 1.1 cgd || ((gr = getgrnam(group)) == NULL)) { 1110 1.1 cgd if (mode & 02000) { 1111 1.1 cgd note("%s:%s: unknown group", host, group); 1112 1.1 cgd mode &= ~02000; 1113 1.1 cgd } 1114 1.1 cgd } else 1115 1.1 cgd gid = gr->gr_gid; 1116 1.1 cgd } else 1117 1.1 cgd gid = gr->gr_gid; 1118 1.30 christos if (userid && gid != (gid_t)-1) { 1119 1.1 cgd if (gr) for (i = 0; gr->gr_mem[i] != NULL; i++) 1120 1.1 cgd if (!(strcmp(user, gr->gr_mem[i]))) 1121 1.1 cgd goto ok; 1122 1.1 cgd mode &= ~02000; 1123 1.1 cgd gid = -1; 1124 1.1 cgd } 1125 1.14 mycroft ok: 1126 1.14 mycroft (void) gettimeofday(&tv[0], (struct timezone *)0); 1127 1.14 mycroft tv[1].tv_sec = mtime; 1128 1.14 mycroft tv[1].tv_usec = 0; 1129 1.14 mycroft if (fd != -1 ? futimes(fd, tv) < 0 : utimes(file, tv) < 0) 1130 1.14 mycroft note("%s: %s utimes: %s", host, file, strerror(errno)); 1131 1.14 mycroft if (fd != -1 ? fchown(fd, uid, gid) < 0 : chown(file, uid, gid) < 0) 1132 1.5 cgd note("%s: %s chown: %s", host, file, strerror(errno)); 1133 1.5 cgd else if (mode & 07000 && 1134 1.14 mycroft (fd != -1 ? fchmod(fd, mode) < 0 : chmod(file, mode) < 0)) 1135 1.5 cgd note("%s: %s chmod: %s", host, file, strerror(errno)); 1136 1.1 cgd return(0); 1137 1.1 cgd } 1138 1.1 cgd 1139 1.1 cgd /* 1140 1.1 cgd * Check for files on the machine being updated that are not on the master 1141 1.1 cgd * machine and remove them. 1142 1.1 cgd */ 1143 1.5 cgd static void 1144 1.23 wiz rmchk(int opts) 1145 1.1 cgd { 1146 1.13 lukem char *cp, *s; 1147 1.1 cgd struct stat stb; 1148 1.1 cgd 1149 1.1 cgd if (debug) 1150 1.1 cgd printf("rmchk()\n"); 1151 1.1 cgd 1152 1.1 cgd /* 1153 1.1 cgd * Tell the remote to clean the files from the last directory sent. 1154 1.1 cgd */ 1155 1.9 thorpej (void) snprintf(buf, sizeof(buf), "C%o\n", opts & VERIFY); 1156 1.1 cgd if (debug) 1157 1.1 cgd printf("buf = %s", buf); 1158 1.1 cgd (void) write(rem, buf, strlen(buf)); 1159 1.1 cgd if (response() < 0) 1160 1.1 cgd return; 1161 1.1 cgd for (;;) { 1162 1.1 cgd cp = s = buf; 1163 1.1 cgd do { 1164 1.1 cgd if (read(rem, cp, 1) != 1) 1165 1.5 cgd lostconn(0); 1166 1.1 cgd } while (*cp++ != '\n' && cp < &buf[BUFSIZ]); 1167 1.1 cgd 1168 1.1 cgd switch (*s++) { 1169 1.1 cgd case 'Q': /* Query if file should be removed */ 1170 1.1 cgd /* 1171 1.1 cgd * Return the following codes to remove query. 1172 1.1 cgd * N\n -- file exists - DON'T remove. 1173 1.1 cgd * Y\n -- file doesn't exist - REMOVE. 1174 1.1 cgd */ 1175 1.1 cgd *--cp = '\0'; 1176 1.10 thorpej (void) snprintf(tp, sizeof(target) - (tp - target), 1177 1.10 thorpej "/%s", s); 1178 1.1 cgd if (debug) 1179 1.1 cgd printf("check %s\n", target); 1180 1.1 cgd if (except(target)) 1181 1.1 cgd (void) write(rem, "N\n", 2); 1182 1.1 cgd else if (lstat(target, &stb) < 0) 1183 1.1 cgd (void) write(rem, "Y\n", 2); 1184 1.1 cgd else 1185 1.1 cgd (void) write(rem, "N\n", 2); 1186 1.1 cgd break; 1187 1.1 cgd 1188 1.1 cgd case '\0': 1189 1.1 cgd *--cp = '\0'; 1190 1.1 cgd if (*s != '\0') 1191 1.24 thorpej dolog(lfp, "%s\n", s); 1192 1.1 cgd break; 1193 1.1 cgd 1194 1.1 cgd case 'E': 1195 1.1 cgd *tp = '\0'; 1196 1.1 cgd ack(); 1197 1.1 cgd return; 1198 1.1 cgd 1199 1.1 cgd case '\1': 1200 1.1 cgd case '\2': 1201 1.1 cgd nerrs++; 1202 1.1 cgd if (*s != '\n') { 1203 1.1 cgd if (!iamremote) { 1204 1.1 cgd fflush(stdout); 1205 1.1 cgd (void) write(2, s, cp - s); 1206 1.1 cgd } 1207 1.1 cgd if (lfp != NULL) 1208 1.1 cgd (void) fwrite(s, 1, cp - s, lfp); 1209 1.1 cgd } 1210 1.1 cgd if (buf[0] == '\2') 1211 1.5 cgd lostconn(0); 1212 1.1 cgd break; 1213 1.1 cgd 1214 1.1 cgd default: 1215 1.1 cgd error("rmchk: unexpected response '%s'\n", buf); 1216 1.1 cgd err(); 1217 1.1 cgd } 1218 1.1 cgd } 1219 1.1 cgd } 1220 1.1 cgd 1221 1.1 cgd /* 1222 1.1 cgd * Check the current directory (initialized by the 'T' command to server()) 1223 1.1 cgd * for extraneous files and remove them. 1224 1.1 cgd */ 1225 1.5 cgd static void 1226 1.23 wiz clean(char *cp) 1227 1.1 cgd { 1228 1.1 cgd DIR *d; 1229 1.16 christos struct dirent *dp; 1230 1.1 cgd struct stat stb; 1231 1.1 cgd char *otp; 1232 1.1 cgd int len, opts; 1233 1.1 cgd 1234 1.1 cgd opts = 0; 1235 1.1 cgd while (*cp >= '0' && *cp <= '7') 1236 1.1 cgd opts = (opts << 3) | (*cp++ - '0'); 1237 1.1 cgd if (*cp != '\0') { 1238 1.1 cgd error("clean: options not delimited\n"); 1239 1.1 cgd return; 1240 1.1 cgd } 1241 1.1 cgd if ((d = opendir(target)) == NULL) { 1242 1.1 cgd error("%s:%s: %s\n", host, target, strerror(errno)); 1243 1.1 cgd return; 1244 1.1 cgd } 1245 1.1 cgd ack(); 1246 1.1 cgd 1247 1.1 cgd otp = tp; 1248 1.1 cgd len = tp - target; 1249 1.13 lukem while ((dp = readdir(d)) != NULL) { 1250 1.1 cgd if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 1251 1.1 cgd continue; 1252 1.1 cgd if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { 1253 1.1 cgd error("%s:%s/%s: Name too long\n", 1254 1.1 cgd host, target, dp->d_name); 1255 1.1 cgd continue; 1256 1.1 cgd } 1257 1.1 cgd tp = otp; 1258 1.1 cgd *tp++ = '/'; 1259 1.25 simonb cp = dp->d_name; 1260 1.13 lukem while ((*tp++ = *cp++) != 0) 1261 1.1 cgd ; 1262 1.1 cgd tp--; 1263 1.1 cgd if (lstat(target, &stb) < 0) { 1264 1.1 cgd error("%s:%s: %s\n", host, target, strerror(errno)); 1265 1.1 cgd continue; 1266 1.1 cgd } 1267 1.9 thorpej (void) snprintf(buf, sizeof(buf), "Q%s\n", dp->d_name); 1268 1.1 cgd (void) write(rem, buf, strlen(buf)); 1269 1.1 cgd cp = buf; 1270 1.1 cgd do { 1271 1.1 cgd if (read(rem, cp, 1) != 1) 1272 1.5 cgd cleanup(0); 1273 1.1 cgd } while (*cp++ != '\n' && cp < &buf[BUFSIZ]); 1274 1.1 cgd *--cp = '\0'; 1275 1.1 cgd cp = buf; 1276 1.1 cgd if (*cp != 'Y') 1277 1.1 cgd continue; 1278 1.1 cgd if (opts & VERIFY) { 1279 1.1 cgd cp = buf; 1280 1.1 cgd *cp++ = '\0'; 1281 1.9 thorpej (void) snprintf(cp, sizeof(buf) - 1, 1282 1.9 thorpej "need to remove: %s\n", target); 1283 1.1 cgd (void) write(rem, buf, strlen(cp) + 1); 1284 1.1 cgd } else 1285 1.1 cgd removeit(&stb); 1286 1.1 cgd } 1287 1.1 cgd closedir(d); 1288 1.1 cgd (void) write(rem, "E\n", 2); 1289 1.1 cgd (void) response(); 1290 1.1 cgd tp = otp; 1291 1.1 cgd *tp = '\0'; 1292 1.1 cgd } 1293 1.1 cgd 1294 1.1 cgd /* 1295 1.1 cgd * Remove a file or directory (recursively) and send back an acknowledge 1296 1.1 cgd * or an error message. 1297 1.1 cgd */ 1298 1.5 cgd static void 1299 1.31 lukem removeit(struct stat *st) 1300 1.1 cgd { 1301 1.1 cgd DIR *d; 1302 1.16 christos struct dirent *dp; 1303 1.13 lukem char *cp; 1304 1.1 cgd struct stat stb; 1305 1.1 cgd char *otp; 1306 1.1 cgd int len; 1307 1.1 cgd 1308 1.31 lukem switch (st->st_mode & S_IFMT) { 1309 1.1 cgd case S_IFREG: 1310 1.1 cgd case S_IFLNK: 1311 1.1 cgd if (unlink(target) < 0) 1312 1.1 cgd goto bad; 1313 1.1 cgd goto removed; 1314 1.1 cgd 1315 1.1 cgd case S_IFDIR: 1316 1.1 cgd break; 1317 1.1 cgd 1318 1.1 cgd default: 1319 1.1 cgd error("%s:%s: not a plain file\n", host, target); 1320 1.1 cgd return; 1321 1.1 cgd } 1322 1.1 cgd 1323 1.1 cgd if ((d = opendir(target)) == NULL) 1324 1.1 cgd goto bad; 1325 1.1 cgd 1326 1.1 cgd otp = tp; 1327 1.1 cgd len = tp - target; 1328 1.13 lukem while ((dp = readdir(d)) != NULL) { 1329 1.1 cgd if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 1330 1.1 cgd continue; 1331 1.1 cgd if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { 1332 1.1 cgd error("%s:%s/%s: Name too long\n", 1333 1.1 cgd host, target, dp->d_name); 1334 1.1 cgd continue; 1335 1.1 cgd } 1336 1.1 cgd tp = otp; 1337 1.1 cgd *tp++ = '/'; 1338 1.25 simonb cp = dp->d_name; 1339 1.13 lukem while ((*tp++ = *cp++) != 0) 1340 1.1 cgd ; 1341 1.1 cgd tp--; 1342 1.1 cgd if (lstat(target, &stb) < 0) { 1343 1.1 cgd error("%s:%s: %s\n", host, target, strerror(errno)); 1344 1.1 cgd continue; 1345 1.1 cgd } 1346 1.1 cgd removeit(&stb); 1347 1.1 cgd } 1348 1.1 cgd closedir(d); 1349 1.1 cgd tp = otp; 1350 1.1 cgd *tp = '\0'; 1351 1.1 cgd if (rmdir(target) < 0) { 1352 1.1 cgd bad: 1353 1.1 cgd error("%s:%s: %s\n", host, target, strerror(errno)); 1354 1.1 cgd return; 1355 1.1 cgd } 1356 1.1 cgd removed: 1357 1.1 cgd cp = buf; 1358 1.1 cgd *cp++ = '\0'; 1359 1.9 thorpej (void) snprintf(cp, sizeof(buf) - 1, "removed %s\n", target); 1360 1.1 cgd (void) write(rem, buf, strlen(cp) + 1); 1361 1.1 cgd } 1362 1.1 cgd 1363 1.1 cgd /* 1364 1.1 cgd * Execute a shell command to handle special cases. 1365 1.1 cgd */ 1366 1.5 cgd static void 1367 1.23 wiz dospecial(char *cmd) 1368 1.1 cgd { 1369 1.1 cgd int fd[2], status, pid, i; 1370 1.13 lukem char *cp, *s; 1371 1.1 cgd char sbuf[BUFSIZ]; 1372 1.1 cgd 1373 1.1 cgd if (pipe(fd) < 0) { 1374 1.1 cgd error("%s\n", strerror(errno)); 1375 1.1 cgd return; 1376 1.1 cgd } 1377 1.1 cgd if ((pid = fork()) == 0) { 1378 1.1 cgd /* 1379 1.1 cgd * Return everything the shell commands print. 1380 1.1 cgd */ 1381 1.1 cgd (void) close(0); 1382 1.1 cgd (void) close(1); 1383 1.1 cgd (void) close(2); 1384 1.1 cgd (void) open(_PATH_DEVNULL, O_RDONLY); 1385 1.1 cgd (void) dup(fd[1]); 1386 1.1 cgd (void) dup(fd[1]); 1387 1.1 cgd (void) close(fd[0]); 1388 1.1 cgd (void) close(fd[1]); 1389 1.1 cgd setgid(groupid); 1390 1.1 cgd setuid(userid); 1391 1.29 mrg execl(_PATH_BSHELL, "sh", "-c", cmd, NULL); 1392 1.1 cgd _exit(127); 1393 1.1 cgd } 1394 1.1 cgd (void) close(fd[1]); 1395 1.1 cgd s = sbuf; 1396 1.1 cgd *s++ = '\0'; 1397 1.1 cgd while ((i = read(fd[0], buf, sizeof(buf))) > 0) { 1398 1.1 cgd cp = buf; 1399 1.1 cgd do { 1400 1.1 cgd *s++ = *cp++; 1401 1.1 cgd if (cp[-1] != '\n') { 1402 1.1 cgd if (s < &sbuf[sizeof(sbuf)-1]) 1403 1.1 cgd continue; 1404 1.1 cgd *s++ = '\n'; 1405 1.1 cgd } 1406 1.1 cgd /* 1407 1.1 cgd * Throw away blank lines. 1408 1.1 cgd */ 1409 1.1 cgd if (s == &sbuf[2]) { 1410 1.1 cgd s--; 1411 1.1 cgd continue; 1412 1.1 cgd } 1413 1.1 cgd (void) write(rem, sbuf, s - sbuf); 1414 1.1 cgd s = &sbuf[1]; 1415 1.1 cgd } while (--i); 1416 1.1 cgd } 1417 1.1 cgd if (s > &sbuf[1]) { 1418 1.1 cgd *s++ = '\n'; 1419 1.1 cgd (void) write(rem, sbuf, s - sbuf); 1420 1.1 cgd } 1421 1.1 cgd while ((i = wait(&status)) != pid && i != -1) 1422 1.1 cgd ; 1423 1.1 cgd if (i == -1) 1424 1.1 cgd status = -1; 1425 1.1 cgd (void) close(fd[0]); 1426 1.1 cgd if (status) 1427 1.1 cgd error("shell returned %d\n", status); 1428 1.1 cgd else 1429 1.1 cgd ack(); 1430 1.1 cgd } 1431 1.1 cgd 1432 1.5 cgd 1433 1.5 cgd void 1434 1.24 thorpej dolog(FILE *fp, const char *fmt, ...) 1435 1.1 cgd { 1436 1.5 cgd va_list ap; 1437 1.22 wiz 1438 1.22 wiz /* Print changes locally if not quiet mode */ 1439 1.22 wiz if (!qflag) { 1440 1.22 wiz va_start(ap, fmt); 1441 1.5 cgd (void)vprintf(fmt, ap); 1442 1.22 wiz va_end(ap); 1443 1.22 wiz } 1444 1.1 cgd 1445 1.1 cgd /* Save changes (for mailing) if really updating files */ 1446 1.22 wiz if (!(options & VERIFY) && fp != NULL) { 1447 1.22 wiz va_start(ap, fmt); 1448 1.5 cgd (void)vfprintf(fp, fmt, ap); 1449 1.22 wiz va_end(ap); 1450 1.22 wiz } 1451 1.1 cgd } 1452 1.1 cgd 1453 1.5 cgd void 1454 1.5 cgd error(const char *fmt, ...) 1455 1.1 cgd { 1456 1.1 cgd static FILE *fp; 1457 1.5 cgd va_list ap; 1458 1.22 wiz 1459 1.22 wiz ++nerrs; 1460 1.22 wiz if (!fp && !(fp = fdopen(rem, "w"))) 1461 1.22 wiz return; 1462 1.5 cgd va_start(ap, fmt); 1463 1.1 cgd if (iamremote) { 1464 1.1 cgd (void)fprintf(fp, "%crdist: ", 0x01); 1465 1.5 cgd (void)vfprintf(fp, fmt, ap); 1466 1.1 cgd fflush(fp); 1467 1.1 cgd } 1468 1.1 cgd else { 1469 1.1 cgd fflush(stdout); 1470 1.1 cgd (void)fprintf(stderr, "rdist: "); 1471 1.5 cgd (void)vfprintf(stderr, fmt, ap); 1472 1.1 cgd fflush(stderr); 1473 1.1 cgd } 1474 1.22 wiz va_end(ap); 1475 1.1 cgd if (lfp != NULL) { 1476 1.1 cgd (void)fprintf(lfp, "rdist: "); 1477 1.22 wiz va_start(ap, fmt); 1478 1.5 cgd (void)vfprintf(lfp, fmt, ap); 1479 1.22 wiz va_end(ap); 1480 1.1 cgd fflush(lfp); 1481 1.1 cgd } 1482 1.1 cgd } 1483 1.1 cgd 1484 1.5 cgd void 1485 1.5 cgd fatal(const char *fmt, ...) 1486 1.1 cgd { 1487 1.1 cgd static FILE *fp; 1488 1.5 cgd va_list ap; 1489 1.22 wiz 1490 1.22 wiz ++nerrs; 1491 1.22 wiz if (!fp && !(fp = fdopen(rem, "w"))) 1492 1.22 wiz return; 1493 1.5 cgd va_start(ap, fmt); 1494 1.1 cgd if (iamremote) { 1495 1.1 cgd (void)fprintf(fp, "%crdist: ", 0x02); 1496 1.5 cgd (void)vfprintf(fp, fmt, ap); 1497 1.1 cgd fflush(fp); 1498 1.1 cgd } 1499 1.1 cgd else { 1500 1.1 cgd fflush(stdout); 1501 1.1 cgd (void)fprintf(stderr, "rdist: "); 1502 1.5 cgd (void)vfprintf(stderr, fmt, ap); 1503 1.1 cgd fflush(stderr); 1504 1.1 cgd } 1505 1.22 wiz va_end(ap); 1506 1.1 cgd if (lfp != NULL) { 1507 1.1 cgd (void)fprintf(lfp, "rdist: "); 1508 1.22 wiz va_start(ap, fmt); 1509 1.5 cgd (void)vfprintf(lfp, fmt, ap); 1510 1.22 wiz va_end(ap); 1511 1.1 cgd fflush(lfp); 1512 1.1 cgd } 1513 1.5 cgd cleanup(0); 1514 1.1 cgd } 1515 1.1 cgd 1516 1.5 cgd static int 1517 1.23 wiz response(void) 1518 1.1 cgd { 1519 1.1 cgd char *cp, *s; 1520 1.1 cgd char resp[BUFSIZ]; 1521 1.1 cgd 1522 1.1 cgd if (debug) 1523 1.1 cgd printf("response()\n"); 1524 1.1 cgd 1525 1.1 cgd cp = s = resp; 1526 1.1 cgd do { 1527 1.1 cgd if (read(rem, cp, 1) != 1) 1528 1.5 cgd lostconn(0); 1529 1.1 cgd } while (*cp++ != '\n' && cp < &resp[BUFSIZ]); 1530 1.1 cgd 1531 1.1 cgd switch (*s++) { 1532 1.1 cgd case '\0': 1533 1.1 cgd *--cp = '\0'; 1534 1.1 cgd if (*s != '\0') { 1535 1.24 thorpej dolog(lfp, "%s\n", s); 1536 1.1 cgd return(1); 1537 1.1 cgd } 1538 1.1 cgd return(0); 1539 1.1 cgd case '\3': 1540 1.1 cgd *--cp = '\0'; 1541 1.24 thorpej dolog(lfp, "Note: %s\n",s); 1542 1.1 cgd return(response()); 1543 1.1 cgd 1544 1.1 cgd default: 1545 1.1 cgd s--; 1546 1.33 mrg /* FALLTHROUGH */ 1547 1.1 cgd case '\1': 1548 1.1 cgd case '\2': 1549 1.1 cgd nerrs++; 1550 1.1 cgd if (*s != '\n') { 1551 1.1 cgd if (!iamremote) { 1552 1.1 cgd fflush(stdout); 1553 1.1 cgd (void) write(2, s, cp - s); 1554 1.1 cgd } 1555 1.1 cgd if (lfp != NULL) 1556 1.1 cgd (void) fwrite(s, 1, cp - s, lfp); 1557 1.1 cgd } 1558 1.1 cgd if (resp[0] == '\2') 1559 1.5 cgd lostconn(0); 1560 1.1 cgd return(-1); 1561 1.1 cgd } 1562 1.1 cgd } 1563 1.1 cgd 1564 1.1 cgd /* 1565 1.1 cgd * Remove temporary files and do any cleanup operations before exiting. 1566 1.1 cgd */ 1567 1.1 cgd void 1568 1.30 christos /*ARGSUSED*/ 1569 1.30 christos cleanup(int signo __unused) 1570 1.1 cgd { 1571 1.1 cgd (void) unlink(tempfile); 1572 1.1 cgd exit(1); 1573 1.1 cgd } 1574 1.1 cgd 1575 1.5 cgd static void 1576 1.5 cgd note(const char *fmt, ...) 1577 1.1 cgd { 1578 1.31 lukem static char nbuf[BUFSIZ]; 1579 1.5 cgd va_list ap; 1580 1.23 wiz 1581 1.5 cgd va_start(ap, fmt); 1582 1.31 lukem (void)vsnprintf(nbuf, sizeof(nbuf), fmt, ap); 1583 1.5 cgd va_end(ap); 1584 1.31 lukem comment(nbuf); 1585 1.1 cgd } 1586 1.1 cgd 1587 1.5 cgd static void 1588 1.23 wiz comment(char *s) 1589 1.1 cgd { 1590 1.5 cgd char c; 1591 1.5 cgd 1592 1.5 cgd c = '\3'; 1593 1.1 cgd write(rem, &c, 1); 1594 1.1 cgd write(rem, s, strlen(s)); 1595 1.1 cgd c = '\n'; 1596 1.1 cgd write(rem, &c, 1); 1597 1.1 cgd } 1598