📄 server.c
字号:
/* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)server.c 8.1 (Berkeley) 6/9/93";#endif /* not lint */#include <sys/wait.h>#include "defs.h"#define ack() (void) write(rem, "\0\n", 2)#define err() (void) write(rem, "\1\n", 2)struct linkbuf *ihead; /* list of files with more than one link */char buf[BUFSIZ]; /* general purpose buffer */char target[BUFSIZ]; /* target/source directory name */char *tp; /* pointer to end of target name */char *Tdest; /* pointer to last T dest*/int catname; /* cat name to target name */char *stp[32]; /* stack of saved tp's for directories */int oumask; /* old umask for creating files */extern FILE *lfp; /* log file for mailing changes */static int chkparent __P((char *));static void clean __P((char *));static void comment __P((char *));static void dospecial __P((char *));static int fchog __P((int, char *, char *, char *, int));static void hardlink __P((char *));static void note __P((const char *, ...));static void query __P((char *));static void recvf __P((char *, int));static void removeit __P((struct stat *));static int response __P((void));static void rmchk __P((int));static struct linkbuf * savelink __P((struct stat *));static void sendf __P((char *, int));static int update __P((char *, int, struct stat *));/* * Server routine to read requests and process them. * Commands are: * Tname - Transmit file if out of date * Vname - Verify if file out of date or not * Qname - Query if file exists. Return mtime & size if it does. */voidserver(){ char cmdbuf[BUFSIZ]; register char *cp; signal(SIGHUP, cleanup); signal(SIGINT, cleanup); signal(SIGQUIT, cleanup); signal(SIGTERM, cleanup); signal(SIGPIPE, cleanup); rem = 0; oumask = umask(0); (void) sprintf(buf, "V%d\n", VERSION); (void) write(rem, buf, strlen(buf)); for (;;) { cp = cmdbuf; if (read(rem, cp, 1) <= 0) return; if (*cp++ == '\n') { error("server: expected control record\n"); continue; } do { if (read(rem, cp, 1) != 1) cleanup(0); } while (*cp++ != '\n' && cp < &cmdbuf[BUFSIZ]); *--cp = '\0'; cp = cmdbuf; switch (*cp++) { case 'T': /* init target file/directory name */ catname = 1; /* target should be directory */ goto dotarget; case 't': /* init target file/directory name */ catname = 0; dotarget: if (exptilde(target, cp) == NULL) continue; tp = target; while (*tp) tp++; ack(); continue; case 'R': /* Transfer a regular file. */ recvf(cp, S_IFREG); continue; case 'D': /* Transfer a directory. */ recvf(cp, S_IFDIR); continue; case 'K': /* Transfer symbolic link. */ recvf(cp, S_IFLNK); continue; case 'k': /* Transfer hard link. */ hardlink(cp); continue; case 'E': /* End. (of directory) */ *tp = '\0'; if (catname <= 0) { error("server: too many 'E's\n"); continue; } tp = stp[--catname]; *tp = '\0'; ack(); continue; case 'C': /* Clean. Cleanup a directory */ clean(cp); continue; case 'Q': /* Query. Does the file/directory exist? */ query(cp); continue; case 'S': /* Special. Execute commands */ dospecial(cp); continue;#ifdef notdef /* * These entries are reserved but not currently used. * The intent is to allow remote hosts to have master copies. * Currently, only the host rdist runs on can have masters. */ case 'X': /* start a new list of files to exclude */ except = bp = NULL; case 'x': /* add name to list of files to exclude */ if (*cp == '\0') { ack(); continue; } if (*cp == '~') { if (exptilde(buf, cp) == NULL) continue; cp = buf; } if (bp == NULL) except = bp = expand(makeblock(NAME, cp), E_VARS); else bp->b_next = expand(makeblock(NAME, cp), E_VARS); while (bp->b_next != NULL) bp = bp->b_next; ack(); continue; case 'I': /* Install. Transfer file if out of date. */ opts = 0; while (*cp >= '0' && *cp <= '7') opts = (opts << 3) | (*cp++ - '0'); if (*cp++ != ' ') { error("server: options not delimited\n"); return; } install(cp, opts); continue; case 'L': /* Log. save message in log file */ log(lfp, cp); continue;#endif case '\1': nerrs++; continue; case '\2': return; default: error("server: unknown command '%s'\n", cp); case '\0': continue; } }}/* * Update the file(s) if they are different. * destdir = 1 if destination should be a directory * (i.e., more than one source is being copied to the same destination). */voidinstall(src, dest, destdir, opts) char *src, *dest; int destdir, opts;{ char *rname; char destcopy[BUFSIZ]; if (dest == NULL) { opts &= ~WHOLE; /* WHOLE mode only useful if renaming */ dest = src; } if (nflag || debug) { printf("%s%s%s%s%s %s %s\n", opts & VERIFY ? "verify":"install", opts & WHOLE ? " -w" : "", opts & YOUNGER ? " -y" : "", opts & COMPARE ? " -b" : "", opts & REMOVE ? " -R" : "", src, dest); if (nflag) return; } rname = exptilde(target, src); if (rname == NULL) return; tp = target; while (*tp) tp++; /* * If we are renaming a directory and we want to preserve * the directory heirarchy (-w), we must strip off the leading * directory name and preserve the rest. */ if (opts & WHOLE) { while (*rname == '/') rname++; destdir = 1; } else { rname = rindex(target, '/'); if (rname == NULL) rname = target; else rname++; } if (debug) printf("target = %s, rname = %s\n", target, rname); /* * Pass the destination file/directory name to remote. */ (void) sprintf(buf, "%c%s\n", destdir ? 'T' : 't', dest); if (debug) printf("buf = %s", buf); (void) write(rem, buf, strlen(buf)); if (response() < 0) return; if (destdir) { strcpy(destcopy, dest); Tdest = destcopy; } sendf(rname, opts); Tdest = 0;}#define protoname() (pw ? pw->pw_name : user)#define protogroup() (gr ? gr->gr_name : group)/* * Transfer the file or directory in target[]. * rname is the name of the file on the remote host. */static voidsendf(rname, opts) char *rname; int opts;{ register struct subcmd *sc; struct stat stb; int sizerr, f, u, len; off_t i; DIR *d; struct direct *dp; char *otp, *cp; extern struct subcmd *subcmds; static char user[15], group[15]; if (debug) printf("sendf(%s, %x)\n", rname, opts); if (except(target)) return; if ((opts & FOLLOW ? stat(target, &stb) : lstat(target, &stb)) < 0) { error("%s: %s\n", target, strerror(errno)); return; } if ((u = update(rname, opts, &stb)) == 0) { if ((stb.st_mode & S_IFMT) == S_IFREG && stb.st_nlink > 1) (void) savelink(&stb); return; } if (pw == NULL || pw->pw_uid != stb.st_uid) if ((pw = getpwuid(stb.st_uid)) == NULL) { log(lfp, "%s: no password entry for uid %d \n", target, stb.st_uid); pw = NULL; (void)sprintf(user, ":%lu", stb.st_uid); } if (gr == NULL || gr->gr_gid != stb.st_gid) if ((gr = getgrgid(stb.st_gid)) == NULL) { log(lfp, "%s: no name for group %d\n", target, stb.st_gid); gr = NULL; (void)sprintf(group, ":%lu", stb.st_gid); } if (u == 1) { if (opts & VERIFY) { log(lfp, "need to install: %s\n", target); goto dospecial; } log(lfp, "installing: %s\n", target); opts &= ~(COMPARE|REMOVE); } switch (stb.st_mode & S_IFMT) { case S_IFDIR: if ((d = opendir(target)) == NULL) { error("%s: %s\n", target, strerror(errno)); return; } (void) sprintf(buf, "D%o %04o 0 0 %s %s %s\n", opts, stb.st_mode & 07777, protoname(), protogroup(), rname); if (debug) printf("buf = %s", buf); (void) write(rem, buf, strlen(buf)); if (response() < 0) { closedir(d); return; } if (opts & REMOVE) rmchk(opts); otp = tp; len = tp - target; while (dp = readdir(d)) { if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue; if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { error("%s/%s: Name too long\n", target, dp->d_name); continue; } tp = otp; *tp++ = '/'; cp = dp->d_name; while (*tp++ = *cp++) ; tp--; sendf(dp->d_name, opts); } closedir(d); (void) write(rem, "E\n", 2); (void) response(); tp = otp; *tp = '\0'; return; case S_IFLNK: if (u != 1) opts |= COMPARE; if (stb.st_nlink > 1) { struct linkbuf *lp; if ((lp = savelink(&stb)) != NULL) { /* install link */ if (*lp->target == 0) (void) sprintf(buf, "k%o %s %s\n", opts, lp->pathname, rname); else (void) sprintf(buf, "k%o %s/%s %s\n", opts, lp->target, lp->pathname, rname); if (debug) printf("buf = %s", buf); (void) write(rem, buf, strlen(buf)); (void) response(); return; } } (void) sprintf(buf, "K%o %o %qd %ld %s %s %s\n", opts, stb.st_mode & 07777, stb.st_size, stb.st_mtime, protoname(), protogroup(), rname); if (debug) printf("buf = %s", buf); (void) write(rem, buf, strlen(buf)); if (response() < 0) return; sizerr = (readlink(target, buf, BUFSIZ) != stb.st_size); (void) write(rem, buf, stb.st_size); if (debug) printf("readlink = %.*s\n", (int)stb.st_size, buf); goto done; case S_IFREG: break; default: error("%s: not a file or directory\n", target); return; } if (u == 2) { if (opts & VERIFY) { log(lfp, "need to update: %s\n", target); goto dospecial; } log(lfp, "updating: %s\n", target); } if (stb.st_nlink > 1) { struct linkbuf *lp; if ((lp = savelink(&stb)) != NULL) { /* install link */ if (*lp->target == 0) (void) sprintf(buf, "k%o %s %s\n", opts, lp->pathname, rname); else (void) sprintf(buf, "k%o %s/%s %s\n", opts, lp->target, lp->pathname, rname); if (debug) printf("buf = %s", buf); (void) write(rem, buf, strlen(buf)); (void) response(); return; } } if ((f = open(target, O_RDONLY, 0)) < 0) { error("%s: %s\n", target, strerror(errno)); return; } (void) sprintf(buf, "R%o %o %qd %ld %s %s %s\n", opts, stb.st_mode & 07777, stb.st_size, stb.st_mtime, protoname(), protogroup(), rname); if (debug) printf("buf = %s", buf); (void) write(rem, buf, strlen(buf)); if (response() < 0) { (void) close(f); return; } sizerr = 0; for (i = 0; i < stb.st_size; i += BUFSIZ) { int amt = BUFSIZ; if (i + amt > stb.st_size) amt = stb.st_size - i; if (sizerr == 0 && read(f, buf, amt) != amt) sizerr = 1; (void) write(rem, buf, amt); } (void) close(f);done: if (sizerr) { error("%s: file changed size\n", target); err(); } else ack(); f = response(); if (f < 0 || f == 0 && (opts & COMPARE)) return;dospecial: for (sc = subcmds; sc != NULL; sc = sc->sc_next) { if (sc->sc_type != SPECIAL) continue; if (sc->sc_args != NULL && !inlist(sc->sc_args, target)) continue; log(lfp, "special \"%s\"\n", sc->sc_name); if (opts & VERIFY) continue; (void) sprintf(buf, "SFILE=%s;%s\n", target, sc->sc_name); if (debug) printf("buf = %s", buf); (void) write(rem, buf, strlen(buf)); while (response() > 0) ; }}static struct linkbuf *savelink(stp) struct stat *stp;{ struct linkbuf *lp; for (lp = ihead; lp != NULL; lp = lp->nextp) if (lp->inum == stp->st_ino && lp->devnum == stp->st_dev) { lp->count--; return(lp); } lp = (struct linkbuf *) malloc(sizeof(*lp));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -