|
|
1.1 root 1: /* install.c - installation of files on remote host */
2:
3: /*
4: * $Header: /f/osi/others/idist/RCS/install.c,v 7.0 89/11/23 21:58:34 mrose Rel $
5: *
6: * Installation of files on remote host - the routines here drive the
7: * protocol for installation, comparision and deletion etc. The
8: * protocol is basically similar to the original rdist, except it is
9: * fully client/server in this model with the daemon only responding
10: * to requests. In the old version, the two sides occasionally swapped
11: * around for some operations. Parts of this file were originally in
12: * the file server.c.
13: *
14: * Julian Onions <[email protected]>
15: * Nottingham University Computer Science
16: *
17: *
18: * $Log: install.c,v $
19: * Revision 7.0 89/11/23 21:58:34 mrose
20: * Release 6.0
21: *
22: */
23:
24: /*
25: * Copyright (c) 1983 Regents of the University of California.
26: * All rights reserved. The Berkeley software License Agreement
27: * specifies the terms and conditions for redistribution.
28: */
29:
30: #ifndef lint
31: static char sccsid[] = "@(#)server.c 5.3 (Berkeley) 6/7/86";
32: static char rcsid[] = "$Header: /f/osi/others/idist/RCS/install.c,v 7.0 89/11/23 21:58:34 mrose Rel $";
33: #endif
34:
35: #include "defs.h"
36: #include <sys/file.h>
37:
38: struct linkbuf *ihead; /* list of files with more than one link */
39: char target[BUFSIZ]; /* target/source directory name */
40: char basename[BUFSIZ]; /* base of directory operations */
41: char *tp; /* pointer to end of target name */
42: char *Tdest; /* pointer to last T dest*/
43: int catname; /* cat name to target name */
44: char *stp[128]; /* stack of saved tp's for directories */
45: int oumask; /* old umask for creating files */
46: char tranbuf[1024*8]; /* 8K at a time... */
47:
48: extern FILE *lfp; /* log file for mailing changes */
49:
50: int cleanup();
51: struct linkbuf *savelink();
52: extern char *getstring ();
53:
54: /*
55: * Update the file(s) if they are different.
56: * destdir = 1 if destination should be a directory
57: * (i.e., more than one source is being copied to the same destination).
58: */
59: install(src, dest, destdir, opts)
60: char *src, *dest;
61: int destdir, opts;
62: {
63: char *rname;
64: char destcopy[BUFSIZ];
65:
66: if (dest == NULL) {
67: opts &= ~WHOLE; /* WHOLE mode only useful if renaming */
68: dest = src;
69: }
70:
71: if (nflag || debug) {
72: printf("%s%s%s%s%s%s %s %s\n",
73: opts & VERIFY ? "verify":"install",
74: opts & WHOLE ? " -w" : "",
75: opts & YOUNGER ? " -y" : "",
76: opts & COMPARE ? " -b" : "",
77: opts & REMOVE ? " -R" : "",
78: opts & QUERYM ? " -Q" : "", src, dest);
79: if (nflag)
80: return;
81: }
82:
83: rname = exptilde(target, src);
84: if (rname == NULL)
85: return;
86: tp = target;
87: (void) strcpy (basename, target);
88: while (*tp)
89: tp++;
90: /*
91: * If we are renaming a directory and we want to preserve
92: * the directory heirarchy (-w), we must strip off the leading
93: * directory name and preserve the rest.
94: */
95: if (opts & WHOLE) {
96: rname = target;
97: while (*rname == '/')
98: rname++;
99: destdir = 1;
100: } else {
101: rname = rindex(target, '/');
102: if (rname == NULL)
103: rname = target;
104: else
105: rname++;
106: }
107: if (debug)
108: printf("target = %s, rname = %s\n", target, rname);
109: /*
110: * Pass the destination file/directory name to remote.
111: */
112: if (initdir (destdir, dest) < 0)
113: return;
114:
115: (void) strcpy(destcopy, dest);
116: Tdest = destcopy;
117:
118: sendf(rname, opts);
119: Tdest = 0;
120: }
121:
122: #define protoname() (pw ? pw->pw_name : user)
123: #define protogroup() (gr ? gr->gr_name : group)
124: /*
125: * Transfer the file or directory in target[].
126: * rname is the name of the file on the remote host.
127: */
128: sendf(rname, opts)
129: char *rname;
130: int opts;
131: {
132: register struct subcmd *sc;
133: struct stat stb;
134: int sizerr, f, u, len;
135: off_t i;
136: DIR *d;
137: struct direct *dp;
138: char *otp, *cp;
139: extern struct subcmd *subcmds;
140: char buf[BUFSIZ];
141: static char uname[15], group[15];
142:
143: if (debug)
144: printf("sendf(%s, %x)\n", rname, opts);
145:
146: if (except(target))
147: return;
148: if ((opts & FOLLOW ? stat(target, &stb) : lstat(target, &stb)) < 0) {
149: advise (target, "Can't stat");
150: return;
151: }
152: if ((u = update(rname, opts, &stb)) == 0) {
153: if ((stb.st_mode & S_IFMT) == S_IFREG && stb.st_nlink > 1)
154: (void) savelink(&stb, opts);
155: return;
156: }
157:
158: if (pw == NULL || pw->pw_uid != stb.st_uid)
159: if ((pw = getpwuid(stb.st_uid)) == NULL) {
160: log(lfp, "%s: no password entry for uid \n", target);
161: pw = NULL;
162: (void) sprintf(uname, ":%d", stb.st_uid);
163: }
164: if (gr == NULL || gr->gr_gid != stb.st_gid)
165: if ((gr = getgrgid(stb.st_gid)) == NULL) {
166: log(lfp, "%s: no name for group %d\n", target);
167: gr = NULL;
168: (void) sprintf(group, ":%d", stb.st_gid);
169: }
170: if (u == 1) {
171: #ifdef UW
172: if (opts & NOINSTALL) {
173: log(lfp, "does not exist, did not install: %s\n", target);
174: goto dospecial;
175: }
176: #endif UW
177: if (opts & VERIFY) {
178: log(lfp, "need to install: %s\n", target);
179: goto dospecial;
180: }
181: log(lfp, "installing: %s\n", target);
182: opts &= ~(COMPARE|REMOVE);
183: }
184:
185: switch (stb.st_mode & S_IFMT) {
186: case S_IFDIR:
187: if ((d = opendir(target)) == NULL) {
188: advise (target, "Can't open directory");
189: return;
190: }
191: if (transfer (stb.st_mode & S_IFMT, opts,
192: stb.st_mode & 07777, (off_t)0, (time_t)0,
193: protoname (), protogroup (),
194: rname, "") < 0) {
195: closedir (d);
196: return;
197: }
198:
199: if (opts & REMOVE)
200: (void) rmchk(opts);
201:
202: otp = tp;
203: len = tp - target;
204: while (dp = readdir(d)) {
205: if (!strcmp(dp->d_name, ".") ||
206: !strcmp(dp->d_name, ".."))
207: continue;
208: if (len + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
209: advise (NULLCP, "%s/%s name too long",
210: target, dp->d_name);
211: continue;
212: }
213: tp = otp;
214: *tp++ = '/';
215: cp = dp->d_name;
216: while (*tp++ = *cp++)
217: ;
218: tp--;
219: sendf(dp->d_name, opts);
220: }
221: closedir(d);
222: (void) terminate (S_IFDIR, OK);
223: tp = otp;
224: *tp = '\0';
225: return;
226:
227: case S_IFLNK:
228: if (u != 1)
229: opts |= COMPARE;
230: if (stb.st_nlink > 1) {
231: struct linkbuf *lp;
232:
233: if ((lp = savelink(&stb, opts)) != NULL) {
234: if (*lp -> target == 0)
235: (void) strcpy (buf, lp -> pathname);
236: else (void) sprintf (buf, "%s/%s",
237: lp -> target,
238: lp -> pathname);
239: (void) transfer ((unsigned short)0, opts,
240: (unsigned short)0, (off_t)0,
241: (time_t)0, "", "",
242: rname, buf);
243: return;
244: }
245: }
246: sizerr = (readlink(target, buf, BUFSIZ) != stb.st_size);
247: if (debug)
248: printf("readlink = %.*s\n", stb.st_size, buf);
249: if (transfer (stb.st_mode & S_IFMT, opts, stb.st_mode & 07777,
250: stb.st_size, stb.st_mtime,
251: protoname (), protogroup (), rname,
252: buf) < 0)
253: return;
254: goto done;
255:
256: case S_IFREG:
257: break;
258:
259: default:
260: advise (NULLCP, "%s: not a file or directory", target);
261: return;
262: }
263:
264: if (u == 2) {
265: if (opts & VERIFY) {
266: log(lfp, "need to update: %s\n", target);
267: goto dospecial;
268: }
269: log(lfp, "updating: %s\n", target);
270: }
271:
272: if (stb.st_nlink > 1) {
273: struct linkbuf *lp;
274:
275: if ((lp = savelink(&stb, opts)) != NULL) {
276: if (*lp -> target == 0)
277: (void) strcpy (buf, lp -> pathname);
278: else (void) sprintf (buf, "%s/%s",
279: lp -> target,
280: lp -> pathname);
281: (void) transfer ((unsigned short)0, opts,
282: (unsigned short)0, (off_t)0,
283: (time_t)0, "", "",
284: rname, buf);
285: return;
286: }
287: }
288:
289: if ((f = open(target, O_RDONLY, 0)) < 0) {
290: advise (target, "Can't open file");
291: return;
292: }
293: if ( transfer ((unsigned short)S_IFREG, opts, stb.st_mode & 07777,
294: stb.st_size,
295: stb.st_mtime, protoname (), protogroup (),
296: rname, "") < 0) {
297: (void) close (f);
298: return;
299: }
300: sizerr = 0;
301: for (i = 0; i < stb.st_size; i += sizeof tranbuf) {
302: int amt = sizeof tranbuf;
303: if (i + amt > stb.st_size)
304: amt = stb.st_size - i;
305: if (sizerr == 0 && read(f, tranbuf, amt) != amt)
306: sizerr = 1;
307: if (tran_data (tranbuf, amt) == NOTOK)
308: break;
309: }
310: (void) close(f);
311: if (sizerr) {
312: advise (NULLCP, "%s: file changed size", target);
313: if (terminate (S_IFREG, NOTOK) < 0)
314: return;
315: } else {
316: if (terminate (S_IFREG, OK) < 0)
317: return;
318: }
319: done:
320: if (opts & COMPARE)
321: return;
322: dospecial:
323: for (sc = subcmds; sc != NULL; sc = sc->sc_next) {
324: if (sc->sc_type != SPECIAL)
325: continue;
326: #ifdef UW
327: if (opts & NOINSTALL) /* don't do specials associated with
328: non-installation notices */
329: continue;
330: #endif UW
331: if (sc->sc_args != NULL && !inlist(sc->sc_args, target))
332: continue;
333: log(lfp, "special \"%s\"\n", sc->sc_name);
334: if (opts & VERIFY)
335: continue;
336: (void) sprintf(buf, "FILE=%s;export FILE;%s",
337: target, sc->sc_name);
338: (void) runspecial (buf);
339:
340: }
341: }
342:
343: struct linkbuf *
344: savelink(sp, opts)
345: struct stat *sp;
346: int opts;
347: {
348: struct linkbuf *lp;
349: extern char *makestr ();
350:
351: for (lp = ihead; lp != NULL; lp = lp->nextp)
352: if (lp->inum == sp->st_ino && lp->devnum == sp->st_dev) {
353: lp->count--;
354: return(lp);
355: }
356: lp = (struct linkbuf *) malloc(sizeof(*lp));
357: if (lp == NULL)
358: log(lfp, "out of memory, link information lost\n");
359: else {
360: lp->nextp = ihead;
361: ihead = lp;
362: lp->inum = sp->st_ino;
363: lp->devnum = sp->st_dev;
364: lp->count = sp->st_nlink - 1;
365: if (opts & WHOLE)
366: lp->pathname = makestr (target);
367: else {
368: if (strncmp (target, basename, strlen(basename)) == 0)
369: lp -> pathname = makestr (target +
370: strlen(basename) + 1);
371: else
372: lp -> pathname = makestr (target);
373: }
374:
375: if (Tdest)
376: lp->target = makestr (Tdest);
377: else
378: *lp->target = 0;
379: }
380: return(NULL);
381: }
382:
383: update(rname, opts, sp)
384: char *rname;
385: int opts;
386: struct stat *sp;
387: {
388: off_t size;
389: time_t mtime;
390: unsigned short mode;
391: int retval;
392:
393: if (debug)
394: printf("update(%s, %x, %x)\n", rname, opts, sp);
395:
396: /*
397: * Check to see if the file exists on the remote machine.
398: */
399: switch (retval = rquery (rname, &mtime, &size, &mode)) {
400: case DONE: /* file doesn't exist so install it */
401: if ((opts & QUERYM) && !query ("Install",
402: (sp ->st_mode & S_IFMT),
403: NULLCP))
404: return 0;
405: return(1);
406:
407: case NOTOK: /* something went wrong! */
408: nerrs++;
409: return(0);
410:
411: case OK:
412: break;
413:
414: default:
415: advise (NULLCP, "update: unexpected response %d", retval);
416: return(0);
417: }
418:
419: if (mode == S_IFDIR)
420: return (2);
421:
422: if (opts & COMPARE) {
423: if ((opts & QUERYM) && !query ("Compare and update", mode, NULLCP))
424: return 0;
425: return(3);
426: }
427:
428: /*
429: * File needs to be updated?
430: */
431: if (opts & YOUNGER) {
432: if (sp->st_mtime == mtime)
433: return(0);
434: if (sp->st_mtime < mtime) {
435: log(lfp, "Warning: %s: remote copy is newer\n", target);
436: return(0);
437: }
438: } else if (sp->st_mtime == mtime && sp->st_size == size)
439: return(0);
440: if ((opts & QUERYM) && !query ("Update",
441: sp -> st_mode & S_IFMT, NULLCP))
442: return 0;
443: return(2);
444: }
445:
446:
447:
448: /*VARARGS2*/
449: log(fp, fmt, a1, a2, a3)
450: FILE *fp;
451: char *fmt;
452: int a1, a2, a3;
453: {
454: /* Print changes locally if not quiet mode */
455: if (!qflag)
456: printf(fmt, a1, a2, a3);
457:
458: /* Save changes (for mailing) if really updating files */
459: if (!(options & VERIFY) && fp != NULL)
460: fprintf(fp, fmt, a1, a2, a3);
461: }
462:
463: /*
464: * Remove temporary files and do any cleanup operations before exiting.
465: */
466: cleanup()
467: {
468: (void) unlink(utmpfile);
469: exit(1);
470: }
471:
472: query (mess, mode, name)
473: int mode;
474: char *mess, *name;
475: {
476: char buf[BUFSIZ];
477: char *cp;
478:
479: switch (mode) {
480: case S_IFDIR:
481: cp = "directory";
482: break;
483: case 0:
484: case S_IFREG:
485: cp = "file";
486: break;
487: case S_IFLNK:
488: cp = "symbolic link";
489: break;
490: default:
491: cp = "unknown file type";
492: break;
493: }
494:
495: (void) sprintf (buf, "%s %s %s? ", mess, cp,
496: name == NULLCP ? target : name);
497: for (;;) {
498: cp = getstring (buf);
499: if (cp == NULLCP)
500: continue;
501: if (*cp == 'y' || *cp == 'Y' || *cp == 'n' || *cp == 'N')
502: break;
503: }
504:
505: if (*cp == 'y' || *cp == 'Y')
506: return 1;
507: return 0;
508: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.