Expand PMF_FN_* macros.
[netbsd-mini2440.git] / usr.sbin / sup / source / supcmeat.c
blobe1660a2995e79c368d6479ce08744c85bcd7f850
1 /* $NetBSD: supcmeat.c,v 1.36 2009/10/16 22:45:18 christos Exp $ */
3 /*
4 * Copyright (c) 1992 Carnegie Mellon University
5 * All Rights Reserved.
7 * Permission to use, copy, modify and distribute this software and its
8 * documentation is hereby granted, provided that both the copyright
9 * notice and this permission notice appear in all copies of the
10 * software, derivative works or modified versions, and any portions
11 * thereof, and that both notices appear in supporting documentation.
13 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
14 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
15 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17 * Carnegie Mellon requests users of this software to return to
19 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
20 * School of Computer Science
21 * Carnegie Mellon University
22 * Pittsburgh PA 15213-3890
24 * any improvements or extensions that they make and grant Carnegie Mellon
25 * the rights to redistribute these changes.
28 * sup "meat" routines
29 **********************************************************************
30 * HISTORY
32 * 7-July-93 Nate Williams at Montana State University
33 * Modified SUP to use gzip based compression when sending files
34 * across the network to save BandWidth
36 * Revision 1.16 92/09/09 22:04:51 mrt
37 * Really added bww's recvone changes this time.
38 * Added code to support non-crypting version of sup.
39 * [92/09/01 mrt]
41 * Revision 1.15 92/08/11 12:07:09 mrt
42 * Added support to add release to FILEWHEN name.
43 * Updated variable arguemnt list usage - bww
44 * Updated recvone() to take a va_list - bww
45 * Changed conditional for rpausing code from CMUCS to MACH
46 * [92/07/24 mrt]
48 * Revision 1.14 92/02/08 18:24:12 mja
49 * Only apply "keep" mode when local file is strictly newer
50 * otherwise allow update as before if necessary.
51 * [92/02/08 18:09:00 mja]
53 * Added support for -k (keep) option to needone(). Rewrote and
54 * commented other parts of needone().
55 * [92/01/17 vdelvecc]
57 * Revision 1.13 91/05/16 14:49:41 ern
58 * Add timestap to fileserver.
59 * Drop day of the week from 5 messages.
60 * [91/05/16 14:47:53 ern]
62 * Revision 1.12 89/08/23 14:55:44 gm0w
63 * Changed msgf routines to msg routines.
64 * [89/08/23 gm0w]
66 * Revision 1.11 89/08/03 19:49:10 mja
67 * Updated to use v*printf() in place of _doprnt().
68 * [89/04/19 mja]
70 * Revision 1.10 89/06/18 14:41:27 gm0w
71 * Fixed up some notify messages of errors to use "SUP:" prefix.
72 * [89/06/18 gm0w]
74 * Revision 1.9 89/06/10 15:12:17 gm0w
75 * Changed to always use rename to install targets. This breaks hard
76 * links and recreates those known to sup, other links will be orphaned.
77 * [89/06/10 gm0w]
79 * Revision 1.8 89/05/24 15:04:23 gm0w
80 * Added code to check for EINVAL from FSPARAM ioctl for disk
81 * space check failures when the ioctl is not implemented.
82 * [89/05/24 gm0w]
84 * Revision 1.7 89/01/16 18:22:28 gm0w
85 * Changed needone() to check that mode of files match before
86 * setting update if times also match.
87 * [89/01/16 gm0w]
89 * 10-Feb-88 Glenn Marcy (gm0w) at Carnegie-Mellon University
90 * Added timeout to backoff.
92 * 27-Dec-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
93 * Added crosspatch support.
95 * 09-Sep-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
96 * Added code to be less verbose when updating files that have
97 * already been successfully upgraded.
99 * 28-Jun-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
100 * Added code for "release" support.
102 * 26-May-87 Doug Philips (dwp) at Carnegie-Mellon University
103 * Converted to end connection with more information.
104 * Added done routine. Modified goaway routine to free old
105 * goawayreason.
107 * 26-May-87 Doug Philips (dwp) at Carnegie-Mellon University
108 * Use computeBackoff from scm instead of doing it ourselves.
110 * 25-May-87 Doug Philips (dwp) at Carnegie-Mellon University
111 * Split off from sup.c and reindented goaway calls.
113 **********************************************************************
116 #include "supcdefs.h"
117 #include "supextern.h"
118 #include <sys/param.h>
119 #include <sys/wait.h>
121 TREE *lastT; /* last filenames in collection */
122 jmp_buf sjbuf; /* jump location for network errors */
123 int dontjump; /* flag to void sjbuf */
124 int cancompress = FALSE; /* Can we do compression? */
125 int docompress = FALSE; /* Do we do compression? */
127 extern COLLECTION *thisC; /* collection list pointer */
128 extern int rpauseflag; /* don't disable resource pausing */
129 extern int portdebug; /* network debugging ports */
130 extern int noutime; /* don't set utimes */
132 /*************************************************
133 *** U P G R A D E C O L L E C T I O N ***
134 *************************************************/
136 static int needone(TREE *, void *);
137 static int recvone(TREE *, va_list);
138 static int denyone(TREE *, void *);
139 static int deleteone(TREE *, void *);
140 static int linkone(TREE *, void *);
141 static int execone(TREE *, void *);
142 static int finishone(TREE *, void *);
145 /* The next two routines define the fsm to support multiple fileservers
146 * per collection.
148 int
149 getonehost(TREE * t, void *v)
151 long *state = v;
152 if (t->Tflags != *state)
153 return (SCMOK);
154 if (*state != 0 && t->Tmode == SCMEOF) {
155 t->Tflags = 0;
156 return (SCMOK);
158 if (*state == 2)
159 t->Tflags--;
160 else
161 t->Tflags++;
162 thisC->Chost = t;
163 return (SCMEOF);
166 TREE *
167 getcollhost(int *tout, int *backoff, long int *state, int *nhostsp)
169 static long laststate = 0;
170 static int nhosts = 0;
172 if (*state != laststate) {
173 *nhostsp = nhosts;
174 laststate = *state;
175 nhosts = 0;
177 if (Tprocess(thisC->Chtree, getonehost, state) == SCMEOF) {
178 if (*state != 0 && nhosts == 0 && !dobackoff(tout, backoff))
179 return (NULL);
180 nhosts++;
181 return (thisC->Chost);
183 if (nhosts == 0)
184 return (NULL);
185 if (*state == 2)
186 (*state)--;
187 else
188 (*state)++;
189 return (getcollhost(tout, backoff, state, nhostsp));
191 /* Upgrade a collection from the file server on the appropriate
192 * host machine.
195 void
196 getcoll(void)
198 TREE *t;
199 int x;
200 int tout, backoff, nhosts;
201 long state;
203 collname = thisC->Cname;
204 tout = thisC->Ctimeout;
205 lastT = NULL;
206 backoff = 2;
207 state = 0;
208 nhosts = 0;
209 for (;;) {
210 t = getcollhost(&tout, &backoff, &state, &nhosts);
211 if (t == NULL) {
212 finishup(SCMEOF);
213 notify((char *) NULL);
214 return;
216 t->Tmode = SCMEOF;
217 dontjump = FALSE;
218 if (!setjmp(sjbuf) && !signon(t, nhosts, &tout) && !setup(t))
219 break;
220 (void) requestend();
222 dontjump = FALSE;
223 if (setjmp(sjbuf))
224 x = SCMERR;
225 else {
226 suplogin();
227 listfiles();
228 recvfiles();
229 x = SCMOK;
231 if (thisC->Clockfd >= 0) {
232 (void) close(thisC->Clockfd);
233 thisC->Clockfd = -1;
235 finishup(x);
236 notify((char *) NULL);
238 /*** Sign on to file server ***/
240 int
241 signon(TREE * t, int nhosts, int *tout)
243 int x;
244 int timeout;
245 time_t tloc;
247 if ((thisC->Cflags & CFLOCAL) == 0 && thishost(thisC->Chost->Tname)) {
248 vnotify("SUP: Skipping local collection %s\n", collname);
249 t->Tmode = SCMEOF;
250 return (TRUE);
252 if (nhosts == 1)
253 timeout = *tout;
254 else
255 timeout = 0;
256 x = request(portdebug ? DEBUGFPORT : FILEPORT,
257 thisC->Chost->Tname, &timeout);
258 if (nhosts == 1)
259 *tout = timeout;
260 if (x != SCMOK) {
261 if (nhosts) {
262 notify("SUP: Can't connect to host %s\n",
263 thisC->Chost->Tname);
264 t->Tmode = SCMEOF;
265 } else
266 t->Tmode = SCMOK;
267 return (TRUE);
269 xpatch = FALSE;
270 x = msgsignon(); /* signon to fileserver */
271 if (x != SCMOK)
272 goaway("Error sending signon request to fileserver");
273 x = msgsignonack(); /* receive signon ack from fileserver */
274 if (x != SCMOK)
275 goaway("Error reading signon reply from fileserver");
276 tloc = time((time_t *) NULL);
277 vnotify("SUP Fileserver %d.%d (%s) %d on %s at %.8s\n",
278 protver, pgmver, scmver, fspid, remotehost(), ctime(&tloc) + 11);
279 free(scmver);
280 scmver = NULL;
281 if (protver < 4) {
282 dontjump = TRUE;
283 goaway("Fileserver sup protocol version is obsolete.");
284 notify("SUP: This version of sup can only communicate with a fileserver using at least\n");
285 notify("SUP: version 4 of the sup network protocol. You should either run a newer\n");
286 notify("SUP: version of the sup fileserver or find an older version of sup.\n");
287 t->Tmode = SCMEOF;
288 return (TRUE);
290 /* If protocol is > 7 then try compression */
291 if (protver > 7) {
292 cancompress = TRUE;
294 return (FALSE);
296 /*** Tell file server what to connect to ***/
298 int
299 setup(TREE * t)
301 char relsufix[STRINGLENGTH];
302 int x;
303 struct stat sbuf;
305 if (chdir(thisC->Cbase) < 0)
306 goaway("Can't change to base directory %s", thisC->Cbase);
307 if (stat("sup", &sbuf) < 0) {
308 (void) mkdir("sup", 0755);
309 if (stat("sup", &sbuf) < 0)
310 goaway("Can't create directory %s/sup", thisC->Cbase);
311 vnotify("SUP Created directory %s/sup\n", thisC->Cbase);
313 if (thisC->Cprefix && chdir(thisC->Cprefix) < 0)
314 goaway("Can't change to %s from base directory %s",
315 thisC->Cprefix, thisC->Cbase);
316 if (stat(".", &sbuf) < 0)
317 goaway("Can't stat %s directory %s",
318 thisC->Cprefix ? "prefix" : "base",
319 thisC->Cprefix ? thisC->Cprefix : thisC->Cbase);
320 if (thisC->Cprefix)
321 (void) chdir(thisC->Cbase);
322 /* read time of last upgrade from when file */
324 if ((thisC->Cflags & CFURELSUF) && thisC->Crelease)
325 (void) sprintf(relsufix, ".%s", thisC->Crelease);
326 else
327 relsufix[0] = '\0';
328 lasttime = getwhen(collname, relsufix);
329 /* setup for msgsetup */
330 basedir = thisC->Chbase;
331 basedev = sbuf.st_dev;
332 baseino = sbuf.st_ino;
333 listonly = (thisC->Cflags & CFLIST);
334 newonly = ((thisC->Cflags & (CFALL | CFDELETE | CFOLD)) == 0);
335 release = thisC->Crelease;
336 x = msgsetup();
337 if (x != SCMOK)
338 goaway("Error sending setup request to file server");
339 x = msgsetupack();
340 if (x != SCMOK)
341 goaway("Error reading setup reply from file server");
342 if (setupack == FSETUPOK) {
343 /* Test encryption */
344 if (netcrypt(thisC->Ccrypt) != SCMOK)
345 goaway("Running non-crypting sup");
346 crypttest = CRYPTTEST;
347 x = msgcrypt();
348 if (x != SCMOK)
349 goaway("Error sending encryption test request");
350 x = msgcryptok();
351 if (x == SCMEOF)
352 goaway("Data encryption test failed");
353 if (x != SCMOK)
354 goaway("Error reading encryption test reply");
355 return (FALSE);
357 switch (setupack) {
358 case FSETUPSAME:
359 notify("SUP: Attempt to upgrade from same host to same directory\n");
360 done(FDONESRVERROR, "Overwrite error");
361 case FSETUPHOST:
362 notify("SUP: This host has no permission to access %s\n",
363 collname);
364 done(FDONESRVERROR, "Permission denied");
365 case FSETUPOLD:
366 notify("SUP: This version of SUP is too old for the fileserver\n");
367 done(FDONESRVERROR, "Obsolete client");
368 case FSETUPRELEASE:
369 notify("SUP: Invalid release %s for collection %s\n",
370 release == NULL ? DEFRELEASE : release, collname);
371 done(FDONESRVERROR, "Invalid release");
372 case FSETUPBUSY:
373 vnotify("SUP Fileserver is currently busy\n");
374 t->Tmode = SCMOK;
375 doneack = FDONESRVERROR;
376 donereason = "Fileserver is busy";
377 (void) netcrypt((char *) NULL);
378 (void) msgdone();
379 return (TRUE);
380 default:
381 goaway("Unrecognized file server setup status %d", setupack);
383 /* NOTREACHED */
384 return FALSE;
386 /*** Tell file server what account to use ***/
388 void
389 suplogin(void)
391 char buf[STRINGLENGTH];
392 int f, x;
394 /* lock collection if desired */
395 (void) sprintf(buf, FILELOCK, collname);
396 f = open(buf, O_RDONLY, 0);
397 if (f >= 0) {
399 #if defined(LOCK_EX)
400 #define TESTLOCK(f) flock(f, LOCK_EX|LOCK_NB)
401 #define SHARELOCK(f) flock(f, LOCK_SH|LOCK_NB)
402 #define WAITLOCK(f) flock(f, LOCK_EX)
403 #elif defined(F_LOCK)
404 #define TESTLOCK(f) lockf(f, F_TLOCK, 0)
405 #define SHARELOCK(f) 1
406 #define WAITLOCK(f) lockf(f, F_LOCK, 0)
407 #else
408 #define TESTLOCK(f) (close(f), f = -1, 1)
409 #define SHARELOCK(f) 1
410 #define WAITLOCK(f) 1
411 #endif
412 if (TESTLOCK(f) < 0) {
413 if (errno != EWOULDBLOCK && errno != EAGAIN) {
414 (void) close(f);
415 goaway("Can't lock collection %s", collname);
417 if (SHARELOCK(f) < 0) {
418 (void) close(f);
419 if (errno == EWOULDBLOCK && errno != EAGAIN)
420 goaway("Collection %s is locked by another sup", collname);
421 goaway("Can't lock collection %s", collname);
423 vnotify("SUP Waiting for exclusive access lock\n");
424 if (WAITLOCK(f) < 0) {
425 (void) close(f);
426 goaway("Can't lock collection %s", collname);
429 thisC->Clockfd = f;
430 vnotify("SUP Locked collection %s for exclusive access\n", collname);
432 logcrypt = (char *) NULL;
433 loguser = thisC->Clogin;
434 logpswd = thisC->Cpswd;
436 #ifndef CRYPTING /* Define CRYPTING for backwards compatibility
437 * with old supfileservers */
438 if (thisC->Clogin != (char *) NULL) /* othewise we only encrypt if
439 * there is a login id */
440 #endif /* CRYPTING */
442 logcrypt = CRYPTTEST;
443 (void) netcrypt(PSWDCRYPT); /* encrypt password data */
445 x = msglogin();
446 #ifndef CRYPTING
447 if (thisC->Clogin != (char *) NULL)
448 #endif
449 (void) netcrypt((char *) NULL); /* turn off encryption */
450 if (x != SCMOK)
451 goaway("Error sending login request to file server");
452 x = msglogack();
453 if (x != SCMOK)
454 goaway("Error reading login reply from file server");
455 if (logack == FLOGNG) {
456 notify("SUP: %s\n", logerror);
457 free(logerror);
458 logerror = NULL;
459 notify("SUP: Improper login to %s account",
460 thisC->Clogin ? thisC->Clogin : "default");
461 done(FDONESRVERROR, "Improper login");
463 if (netcrypt(thisC->Ccrypt) != SCMOK) /* restore encryption */
464 goaway("Running non-crypting sup");
467 * send list of files that we are not interested in. receive list of
468 * files that are on the repository that could be upgraded. Find the
469 * ones that we need. Receive the list of files that the server could
470 * not access. Delete any files that have been upgraded in the past
471 * which are no longer on the repository.
474 void
475 listfiles(void)
477 char buf[STRINGLENGTH];
478 char relsufix[STRINGLENGTH];
479 char *p, *q;
480 FILE *f;
481 int x;
484 if ((thisC->Cflags & CFURELSUF) && release)
485 (void) sprintf(relsufix, ".%s", release);
486 else
487 relsufix[0] = '\0';
488 (void) sprintf(buf, FILELAST, collname, relsufix);
489 f = fopen(buf, "r");
490 if (f) {
491 while ((p = fgets(buf, STRINGLENGTH, f))) {
492 if ((q = strchr(p, '\n')))
493 *q = '\0';
494 if (strchr("#;:", *p))
495 continue;
496 (void) Tinsert(&lastT, p, FALSE);
498 (void) fclose(f);
500 refuseT = NULL;
501 (void) sprintf(buf, FILEREFUSE, collname);
502 f = fopen(buf, "r");
503 if (f) {
504 while ((p = fgets(buf, STRINGLENGTH, f))) {
505 if ((q = strchr(p, '\n')))
506 *q = '\0';
507 if (strchr("#;:", *p))
508 continue;
509 (void) Tinsert(&refuseT, p, FALSE);
511 (void) fclose(f);
513 vnotify("SUP Requesting changes since %s", ctime(&lasttime) + 4);
514 x = msgrefuse();
515 if (x != SCMOK)
516 goaway("Error sending refuse list to file server");
517 listT = NULL;
518 x = msglist();
519 if (x != SCMOK)
520 goaway("Error reading file list from file server");
521 if (thisC->Cprefix)
522 (void) chdir(thisC->Cprefix);
523 needT = NULL;
524 (void) Tprocess(listT, needone, NULL);
525 Tfree(&listT);
526 x = msgneed();
527 if (x != SCMOK)
528 goaway("Error sending needed files list to file server");
529 Tfree(&needT);
530 denyT = NULL;
531 x = msgdeny();
532 if (x != SCMOK)
533 goaway("Error reading denied files list from file server");
534 if (thisC->Cflags & CFVERBOSE)
535 (void) Tprocess(denyT, denyone, NULL);
536 Tfree(&denyT);
537 if (thisC->Cflags & (CFALL | CFDELETE | CFOLD))
538 (void) Trprocess(lastT, deleteone, NULL);
539 Tfree(&refuseT);
542 static int
543 needone(TREE * t, void *dummy __unused)
545 TREE *newt;
546 int exists, fetch;
547 struct stat sbuf;
549 newt = Tinsert(&lastT, t->Tname, TRUE);
550 newt->Tflags |= FUPDATE;
551 fetch = TRUE;
552 if ((thisC->Cflags & CFALL) == 0) {
553 if ((t->Tflags & FNEW) == 0 && (thisC->Cflags & CFOLD) == 0)
554 return (SCMOK);
555 if (S_ISLNK(t->Tmode))
556 exists = (lstat(t->Tname, &sbuf) == 0);
557 else
558 exists = (stat(t->Tname, &sbuf) == 0);
559 /* This is moderately complicated: If the file is the wrong
560 * type or doesn't exist, we need to fetch the whole file. If
561 * the file is a special file, we rely solely on the server:
562 * if the file changed, we do an update; otherwise nothing. If
563 * the file is a normal file, we check timestamps. If we are
564 * in "keep" mode, we fetch if the file on the server is
565 * newer, and do nothing otherwise. Otherwise, we fetch if the
566 * timestamp is wrong; if the file changed on the server but
567 * the timestamp is right, we do an update. (Update refers to
568 * updating stat information, i.e. timestamp, owner, mode
569 * bits, etc.) */
570 if (exists && (sbuf.st_mode & S_IFMT) == (t->Tmode & S_IFMT)) {
571 if (!S_ISREG(t->Tmode))
572 if (t->Tflags & FNEW)
573 fetch = FALSE;
574 else
575 return (SCMOK);
576 else if ((thisC->Cflags & CFKEEP) &&
577 sbuf.st_mtime > t->Tmtime)
578 return (SCMOK);
579 else if (sbuf.st_mtime == t->Tmtime) {
580 if (t->Tflags & FNEW)
581 fetch = FALSE;
582 else
583 return (SCMOK);
587 /* If we get this far, we're either doing an update or a full fetch. */
588 newt = Tinsert(&needT, t->Tname, TRUE);
589 if (!fetch && S_ISREG(t->Tmode))
590 newt->Tflags |= FUPDATE;
591 return (SCMOK);
594 static int
595 denyone(TREE * t, void *v __unused)
597 vnotify("SUP: Access denied to %s\n", t->Tname);
598 return (SCMOK);
601 static int
602 deleteone(TREE * t, void *v __unused)
604 struct stat sbuf, pbuf;
605 int x;
606 char *name = t->Tname;
607 char pname[MAXPATHLEN];
609 if (t->Tflags & FUPDATE)/* in current upgrade list */
610 return (SCMOK);
611 if (lstat(name, &sbuf) < 0) /* doesn't exist */
612 return (SCMOK);
613 /* is it a symbolic link ? */
614 if (S_ISLNK(sbuf.st_mode)) {
615 if (Tlookup(refuseT, name)) {
616 vnotify("SUP Would not delete symbolic link %s\n",
617 name);
618 return (SCMOK);
620 if (thisC->Cflags & CFLIST) {
621 vnotify("SUP Would delete symbolic link %s\n", name);
622 return (SCMOK);
624 if ((thisC->Cflags & CFDELETE) == 0) {
625 notify("SUP Please delete symbolic link %s\n", name);
626 t->Tflags |= FUPDATE;
627 return (SCMOK);
629 x = unlink(name);
630 if (x < 0) {
631 notify("SUP: Unable to delete symbolic link %s (%s)\n",
632 name, strerror(errno));
633 t->Tflags |= FUPDATE;
634 return (SCMOK);
636 vnotify("SUP Deleted symbolic link %s\n", name);
637 return (SCMOK);
639 /* is it a directory ? */
640 if (S_ISDIR(sbuf.st_mode)) {
641 if (Tlookup(refuseT, name)) {
642 vnotify("SUP Would not delete directory %s\n", name);
643 return (SCMOK);
645 if (thisC->Cflags & CFLIST) {
646 vnotify("SUP Would delete directory %s\n", name);
647 return (SCMOK);
649 if ((thisC->Cflags & CFDELETE) == 0) {
650 notify("SUP Please delete directory %s\n", name);
651 t->Tflags |= FUPDATE;
652 return (SCMOK);
654 if (rmdir(name) < 0) {
655 (void) chmod(name, sbuf.st_mode | S_IRWXU);
656 if (strlen(name) < MAXPATHLEN - 3) {
657 sprintf(pname, "%s/..", name);
658 if (stat(pname, &pbuf) == 0)
659 (void) chmod(pname, pbuf.st_mode | S_IRWXU);
661 runp("rm", "rm", "-rf", name, 0);
663 if (rmdir(name) < 0 && errno != ENOENT) {
664 notify("SUP: Unable to delete directory %s (%s)\n",
665 name, strerror(errno));
666 t->Tflags |= FUPDATE;
667 return (SCMOK);
669 vnotify("SUP Deleted directory %s\n", name);
670 return (SCMOK);
672 /* it is a file */
673 if (Tlookup(refuseT, name)) {
674 vnotify("SUP Would not delete file %s\n", name);
675 return (SCMOK);
677 if (thisC->Cflags & CFLIST) {
678 vnotify("SUP Would delete file %s\n", name);
679 return (SCMOK);
681 if ((thisC->Cflags & CFDELETE) == 0) {
682 notify("SUP Please delete file %s\n", name);
683 t->Tflags |= FUPDATE;
684 return (SCMOK);
686 x = unlink(name);
687 if (x < 0) {
688 notify("SUP: Unable to delete file %s (%s)\n", name,
689 strerror(errno));
690 t->Tflags |= FUPDATE;
691 return (SCMOK);
693 vnotify("SUP Deleted file %s\n", name);
694 return (SCMOK);
696 /***************************************
697 *** R E C E I V E F I L E S ***
698 ***************************************/
700 /* Note for these routines, return code SCMOK generally means
701 * NETWORK communication is OK; it does not mean that the current
702 * file was correctly received and stored. If a file gets messed
703 * up, too bad, just print a message and go on to the next one;
704 * but if the network gets messed up, the whole sup program loses
705 * badly and best just stop the program as soon as possible.
708 void
709 recvfiles(void)
711 int x;
712 int recvmore;
714 /* Does the protocol support compression */
715 if (cancompress) {
716 /* Check for compression on sending files */
717 docompress = (thisC->Cflags & CFCOMPRESS);
718 x = msgcompress();
719 if (x != SCMOK)
720 goaway("Error sending compression check to server");
721 if (docompress)
722 vnotify("SUP Using compressed file transfer\n");
724 recvmore = TRUE;
725 upgradeT = NULL;
726 do {
727 x = msgsend();
728 if (x != SCMOK)
729 goaway("Error sending receive file request to file server");
730 (void) Tinsert(&upgradeT, (char *) NULL, FALSE);
731 x = msgrecv(recvone, &recvmore);
732 if (x != SCMOK)
733 goaway("Error receiving file from file server");
734 Tfree(&upgradeT);
735 } while (recvmore);
737 /* prepare the target, if necessary */
738 int
739 prepare(char *name, int mode, int *newp, struct stat * statp)
741 char *type;
742 char pname[MAXPATHLEN];
743 struct stat pbuf;
744 int er = 0;
746 if (mode == S_IFLNK)
747 *newp = (lstat(name, statp) < 0);
748 else
749 *newp = (stat(name, statp) < 0);
750 if (*newp) {
751 if (thisC->Cflags & CFLIST)
752 return (FALSE);
753 if (establishdir(name))
754 return (TRUE);
755 return (FALSE);
757 if (mode == (statp->st_mode & S_IFMT))
758 return (FALSE);
759 *newp = TRUE;
760 switch (statp->st_mode & S_IFMT) {
761 case S_IFDIR:
762 type = "directory";
763 break;
764 case S_IFLNK:
765 type = "symbolic link";
766 break;
767 case S_IFREG:
768 type = "regular file";
769 break;
770 default:
771 type = "unknown file";
772 break;
774 if (thisC->Cflags & CFLIST) {
775 vnotify("SUP Would remove %s %s\n", type, name);
776 return (FALSE);
778 if (S_ISDIR(statp->st_mode)) {
779 if (rmdir(name) < 0) {
780 (void) chmod(name, statp->st_mode | S_IRWXU);
781 if (strlen(name) < MAXPATHLEN - 3) {
782 sprintf(pname, "%s/..", name);
783 if (stat(pname, &pbuf) == 0)
784 (void) chmod(pname, pbuf.st_mode | S_IRWXU);
786 runp("rm", "rm", "-rf", name, 0);
788 if (rmdir(name) < 0)
789 er = errno;
790 } else {
791 if (unlink(name) < 0)
792 er = errno;
794 if (stat(name, statp) < 0) {
795 vnotify("SUP Removed %s %s\n", type, name);
796 return (FALSE);
798 notify("SUP: Couldn't remove %s %s (%s)\n", type, name, strerror(er));
799 return (TRUE);
802 static int
803 recvone(TREE * t, va_list ap)
805 int x = 0;
806 int new;
807 struct stat sbuf;
808 int *recvmore;
810 recvmore = va_arg(ap, int *);
811 /* check for end of file list */
812 if (t == NULL) {
813 *recvmore = FALSE;
814 return (SCMOK);
816 /* check for failed access at fileserver */
817 if (t->Tmode == 0) {
818 notify("SUP: File server unable to transfer file %s\n",
819 t->Tname);
820 thisC->Cnogood = TRUE;
821 return (SCMOK);
823 if (prepare(t->Tname, t->Tmode & S_IFMT, &new, &sbuf)) {
824 notify("SUP: Can't prepare path for %s (%s)\n", t->Tname,
825 strerror(errno));
826 if (S_ISREG(t->Tmode)) {
827 x = readskip(); /* skip over file */
828 if (x != SCMOK)
829 goaway("Can't skip file transfer");
831 thisC->Cnogood = TRUE;
832 return (SCMOK);
834 /* make file mode specific changes */
835 switch (t->Tmode & S_IFMT) {
836 case S_IFDIR:
837 x = recvdir(t, new, &sbuf);
838 break;
839 case S_IFLNK:
840 x = recvsym(t, new, &sbuf);
841 break;
842 case S_IFREG:
843 x = recvreg(t, new, &sbuf);
844 break;
845 default:
846 goaway("Unknown file type %o\n", t->Tmode & S_IFMT);
848 if (x) {
849 thisC->Cnogood = TRUE;
850 return (SCMOK);
852 if (S_ISREG(t->Tmode))
853 (void) Tprocess(t->Tlink, linkone, t->Tname);
854 (void) Tprocess(t->Texec, execone, NULL);
855 return (SCMOK);
858 int
859 recvdir(TREE * t, int new, struct stat * statp)
860 { /* receive directory from network */
861 struct timeval tbuf[2];
863 if (new) {
864 if (thisC->Cflags & CFLIST) {
865 vnotify("SUP Would create directory %s\n", t->Tname);
866 return (FALSE);
868 if (makedir(t->Tname, 0755, statp) == -1) {
869 notify("SUP: Can't create directory %s (%s)\n",
870 t->Tname, strerror(errno));
871 return TRUE;
874 if ((t->Tflags & FNOACCT) == 0) {
875 /* convert user and group names to local ids */
876 ugconvert(t->Tuser, t->Tgroup, &t->Tuid, &t->Tgid, &t->Tmode);
878 if (!new && (t->Tflags & FNEW) == 0 && statp->st_mtime == t->Tmtime) {
879 if (t->Tflags & FNOACCT)
880 return (FALSE);
881 if (statp->st_uid == t->Tuid && statp->st_gid == t->Tgid)
882 return (FALSE);
884 if (thisC->Cflags & CFLIST) {
885 vnotify("SUP Would update directory %s\n", t->Tname);
886 return (FALSE);
888 if ((t->Tflags & FNOACCT) == 0) {
889 (void) chown(t->Tname, t->Tuid, t->Tgid);
890 (void) chmod(t->Tname, t->Tmode & S_IMODE);
892 tbuf[0].tv_sec = time((time_t *) NULL);
893 tbuf[0].tv_usec = 0;
894 tbuf[1].tv_sec = t->Tmtime;
895 tbuf[1].tv_usec = 0;
896 if (!noutime)
897 (void) utimes(t->Tname, tbuf);
898 vnotify("SUP %s directory %s\n", new ? "Created" : "Updated", t->Tname);
899 return (FALSE);
902 int
903 recvsym(TREE * t, int new, struct stat * statp)
904 { /* receive symbolic link */
905 char buf[STRINGLENGTH];
906 int n;
907 char *linkname;
909 if (t->Tlink == NULL || t->Tlink->Tname == NULL) {
910 notify("SUP: Missing linkname for symbolic link %s\n",
911 t->Tname);
912 return (TRUE);
914 linkname = t->Tlink->Tname;
915 n = -1;
916 if (!new && (t->Tflags & FNEW) == 0 &&
917 (n = readlink(t->Tname, buf, sizeof(buf) - 1)) >= 0 &&
918 (n == strlen(linkname)) && (strncmp(linkname, buf, n) == 0))
919 return (FALSE);
920 if (n >= 0)
921 t->Tname[n] = '\0';
922 if (thisC->Cflags & CFLIST) {
923 vnotify("SUP Would %s symbolic link %s to %s\n",
924 new ? "create" : "update", t->Tname, linkname);
925 return (FALSE);
927 if (!new)
928 (void) unlink(t->Tname);
929 if (symlink(linkname, t->Tname) < 0 || lstat(t->Tname, statp) < 0) {
930 notify("SUP: Unable to create symbolic link %s (%s)\n",
931 t->Tname, strerror(errno));
932 return (TRUE);
934 vnotify("SUP Created symbolic link %s to %s\n", t->Tname, linkname);
935 return (FALSE);
938 int
939 recvreg(TREE * t, int new, struct stat * statp)
940 { /* receive file from network */
941 FILE *fin, *fout;
942 char dirpart[STRINGLENGTH], filepart[STRINGLENGTH];
943 char filename[STRINGLENGTH], buf[STRINGLENGTH];
944 struct timeval tbuf[2];
945 int x;
946 char *p;
948 if (t->Tflags & FUPDATE) {
949 if ((t->Tflags & FNOACCT) == 0) {
950 /* convert user and group names to local ids */
951 ugconvert(t->Tuser, t->Tgroup, &t->Tuid, &t->Tgid,
952 &t->Tmode);
954 if (!new && (t->Tflags & FNEW) == 0 &&
955 statp->st_mtime == t->Tmtime) {
956 if (t->Tflags & FNOACCT)
957 return (FALSE);
958 if (statp->st_uid == t->Tuid &&
959 statp->st_gid == t->Tgid)
960 return (FALSE);
962 if (thisC->Cflags & CFLIST) {
963 vnotify("SUP Would update file %s\n", t->Tname);
964 return (FALSE);
966 vnotify("SUP Updating file %s\n", t->Tname);
967 if ((t->Tflags & FNOACCT) == 0) {
968 (void) chown(t->Tname, t->Tuid, t->Tgid);
969 (void) chmod(t->Tname, t->Tmode & S_IMODE);
971 tbuf[0].tv_sec = time((time_t *) NULL);
972 tbuf[0].tv_usec = 0;
973 tbuf[1].tv_sec = t->Tmtime;
974 tbuf[1].tv_usec = 0;
975 if (!noutime)
976 (void) utimes(t->Tname, tbuf);
977 return (FALSE);
979 if (thisC->Cflags & CFLIST) {
980 if (new)
981 p = "create";
982 else if (statp->st_mtime < t->Tmtime)
983 p = "receive new";
984 else if (statp->st_mtime > t->Tmtime)
985 p = "receive old";
986 else
987 p = "receive";
988 vnotify("SUP Would %s file %s\n", p, t->Tname);
989 return (FALSE);
991 vnotify("SUP Receiving file %s\n", t->Tname);
992 if (!new && S_ISREG(t->Tmode) &&
993 (t->Tflags & FBACKUP) && (thisC->Cflags & CFBACKUP)) {
994 fin = fopen(t->Tname, "r"); /* create backup */
995 if (fin == NULL) {
996 x = readskip(); /* skip over file */
997 if (x != SCMOK)
998 goaway("Can't skip file transfer");
999 notify("SUP: Can't open %s to create backup\n",
1000 t->Tname);
1001 return (TRUE); /* mark upgrade as nogood */
1003 path(t->Tname, dirpart, filepart);
1004 (void) sprintf(filename, FILEBACKUP, dirpart, filepart);
1005 fout = fopen(filename, "w");
1006 if (fout == NULL) {
1007 (void) sprintf(buf, FILEBKDIR, dirpart);
1008 (void) mkdir(buf, 0755);
1009 fout = fopen(filename, "w");
1011 if (fout == NULL) {
1012 x = readskip(); /* skip over file */
1013 if (x != SCMOK)
1014 goaway("Can't skip file transfer");
1015 notify("SUP: Can't create %s for backup\n", filename);
1016 (void) fclose(fin);
1017 return (TRUE);
1019 ffilecopy(fin, fout);
1020 (void) fclose(fin);
1021 (void) fclose(fout);
1022 vnotify("SUP Backup of %s created\n", t->Tname);
1024 x = copyfile(t->Tname, (char *) NULL);
1025 if (x)
1026 return (TRUE);
1027 if ((t->Tflags & FNOACCT) == 0) {
1028 /* convert user and group names to local ids */
1029 ugconvert(t->Tuser, t->Tgroup, &t->Tuid, &t->Tgid, &t->Tmode);
1030 (void) chown(t->Tname, t->Tuid, t->Tgid);
1031 (void) chmod(t->Tname, t->Tmode & S_IMODE);
1033 tbuf[0].tv_sec = time((time_t *) NULL);
1034 tbuf[0].tv_usec = 0;
1035 tbuf[1].tv_sec = t->Tmtime;
1036 tbuf[1].tv_usec = 0;
1037 if (!noutime)
1038 (void) utimes(t->Tname, tbuf);
1039 return (FALSE);
1042 static int
1043 linkone(TREE * t, void *fv)
1044 { /* link to file already received */
1045 char *fname = fv;
1046 struct stat fbuf, sbuf;
1047 char *name = t->Tname;
1048 int new, x;
1049 char *type;
1051 if (lstat(fname, &fbuf) < 0) { /* source file */
1052 if (thisC->Cflags & CFLIST) {
1053 vnotify("SUP Would link %s to %s\n", name, fname);
1054 return (SCMOK);
1056 notify("SUP: Can't link %s to missing file %s\n", name, fname);
1057 thisC->Cnogood = TRUE;
1058 return (SCMOK);
1060 if (prepare(name, S_IFLNK, &new, &sbuf)) {
1061 thisC->Cnogood = TRUE;
1062 return (SCMOK);
1064 if (!new && (t->Tflags & FNEW) == 0 &&
1065 fbuf.st_dev == sbuf.st_dev && fbuf.st_ino == sbuf.st_ino)
1066 return (SCMOK);
1067 if (thisC->Cflags & CFLIST) {
1068 vnotify("SUP Would link %s to %s\n", name, fname);
1069 return (SCMOK);
1071 (void) unlink(name);
1072 type = "";
1073 if (S_ISDIR(fbuf.st_mode) || (x = link(fname, name)) < 0) {
1074 type = "symbolic ";
1075 x = symlink(fname, name);
1077 if (x < 0 || lstat(name, &sbuf) < 0) {
1078 notify("SUP: Unable to create %slink %s (%s)\n", type, name,
1079 strerror(x));
1080 return (TRUE);
1082 vnotify("SUP Created %slink %s to %s\n", type, name, fname);
1083 return (SCMOK);
1086 static int
1087 execone(TREE * t, void *v __unused)
1088 { /* execute command for file */
1089 int w;
1091 if (thisC->Cflags & CFLIST) {
1092 vnotify("SUP Would execute %s\n", t->Tname);
1093 return (SCMOK);
1095 if ((thisC->Cflags & CFEXECUTE) == 0) {
1096 notify("SUP Please execute %s\n", t->Tname);
1097 return (SCMOK);
1099 vnotify("SUP Executing %s\n", t->Tname);
1101 w = system(t->Tname);
1102 if (WIFEXITED(w) && WEXITSTATUS(w) != 0) {
1103 notify("SUP: Execute command returned failure status %#o\n",
1104 WEXITSTATUS(w));
1105 thisC->Cnogood = TRUE;
1106 } else if (WIFSIGNALED(w)) {
1107 notify("SUP: Execute command killed by signal %d\n",
1108 WTERMSIG(w));
1109 thisC->Cnogood = TRUE;
1110 } else if (WIFSTOPPED(w)) {
1111 notify("SUP: Execute command stopped by signal %d\n",
1112 WSTOPSIG(w));
1113 thisC->Cnogood = TRUE;
1115 return (SCMOK);
1118 /* from will be 0 if reading from network */
1119 int
1120 copyfile(char *to, char *from)
1122 int fromf, tof, istemp, x;
1123 char dpart[STRINGLENGTH], fpart[STRINGLENGTH];
1124 char tname[STRINGLENGTH];
1125 static int returntrue = 1;
1127 static int thispid = 0; /* process id # */
1129 if (from) { /* reading file */
1130 fromf = open(from, O_RDONLY, 0);
1131 if (fromf < 0) {
1132 notify("SUP: Can't open %s to copy to %s (%s)\n",
1133 from, to, strerror(errno));
1134 return (TRUE);
1136 } else /* reading network */
1137 fromf = -1;
1138 istemp = TRUE; /* try to create temp file */
1139 lockout(TRUE); /* block interrupts */
1140 if (thispid == 0)
1141 thispid = getpid();
1142 /* Now try hard to find a temp file name. Try VERY hard. */
1143 for (;;) {
1144 /* try destination directory */
1145 path(to, dpart, fpart);
1146 (void) sprintf(tname, "%s/#%d.sup", dpart, thispid);
1147 tof = open(tname, (O_WRONLY | O_CREAT | O_TRUNC | O_EXCL), 0600);
1148 if (tof >= 0)
1149 break;
1150 /* try sup directory */
1151 if (thisC->Cprefix)
1152 (void) chdir(thisC->Cbase);
1153 (void) sprintf(tname, "sup/#%d.sup", thispid);
1154 tof = open(tname, (O_WRONLY | O_CREAT | O_TRUNC | O_EXCL), 0600);
1155 if (tof >= 0) {
1156 if (thisC->Cprefix)
1157 (void) chdir(thisC->Cprefix);
1158 break;
1160 /* try base directory */
1161 (void) sprintf(tname, "#%d.sup", thispid);
1162 tof = open(tname, (O_WRONLY | O_CREAT | O_TRUNC | O_EXCL), 0600);
1163 if (thisC->Cprefix)
1164 (void) chdir(thisC->Cprefix);
1165 if (tof >= 0)
1166 break;
1167 #ifdef VAR_TMP
1168 /* try /var/tmp */
1169 (void) sprintf(tname, "/var/tmp/#%d.sup", thispid);
1170 tof = open(tname, (O_WRONLY | O_CREAT | O_TRUNC | O_EXCL), 0600);
1171 if (tof >= 0)
1172 break;
1173 #else
1174 /* try /usr/tmp */
1175 (void) sprintf(tname, "/usr/tmp/#%d.sup", thispid);
1176 tof = open(tname, (O_WRONLY | O_CREAT | O_TRUNC | O_EXCL), 0600);
1177 if (tof >= 0)
1178 break;
1179 #endif
1180 /* try /tmp */
1181 (void) sprintf(tname, "/tmp/#%d.sup", thispid);
1182 tof = open(tname, (O_WRONLY | O_CREAT | O_TRUNC | O_EXCL), 0600);
1183 if (tof >= 0)
1184 break;
1185 istemp = FALSE;
1186 /* give up: try to create output file */
1187 if (!docompress)
1188 tof = open(to, (O_WRONLY | O_CREAT | O_TRUNC | O_EXCL), 0600);
1189 if (tof >= 0)
1190 break;
1191 /* no luck */
1192 notify("SUP: Can't create %s or temp file for it (%s)\n", to,
1193 strerror(errno));
1194 lockout(FALSE);
1195 if (fromf >= 0)
1196 (void) close(fromf);
1197 else {
1198 x = readskip();
1199 if (x != SCMOK)
1200 goaway("Can't skip file transfer");
1202 if (returntrue)
1203 return (TRUE);
1205 if (fromf >= 0) { /* read file */
1206 x = filecopy(fromf, tof);
1207 (void) close(fromf);
1208 (void) close(tof);
1209 if (x < 0) {
1210 notify("SUP: Error in copying %s to %s\n", from, to);
1211 if (istemp)
1212 (void) unlink(tname);
1213 lockout(FALSE);
1214 return (TRUE);
1216 } else { /* read network */
1217 #if MACH
1218 if (!rpauseflag) {
1219 int fsize;
1220 struct fsparam fsp;
1222 x = prereadcount(&fsize);
1223 if (x != SCMOK) {
1224 if (istemp)
1225 (void) unlink(tname);
1226 lockout(FALSE);
1227 x = readskip();
1228 if (x != SCMOK)
1229 goaway("Can't skip file transfer");
1230 goaway("Error in server space check");
1231 logquit(1, "Error in server space check");
1233 errno = 0;
1234 if (ioctl(tof, FIOCFSPARAM, (char *) &fsp) < 0 &&
1235 errno != EINVAL) {
1236 if (istemp)
1237 (void) unlink(tname);
1238 lockout(FALSE);
1239 x = readskip();
1240 if (x != SCMOK)
1241 goaway("Can't skip file transfer");
1242 goaway("Error in disk space check");
1243 logquit(1, "Error in disk space check");
1245 if (errno == 0) {
1246 fsize = (fsize + 1023) / 1024;
1247 x = fsp.fsp_size * MAX(fsp.fsp_minfree, 1) / 100;
1248 fsp.fsp_free -= x;
1249 if (fsize > MAX(fsp.fsp_free, 0)) {
1250 if (istemp)
1251 (void) unlink(tname);
1252 lockout(FALSE);
1253 x = readskip();
1254 if (x != SCMOK)
1255 goaway("Can't skip file transfer");
1256 goaway("No disk space for file %s", to);
1257 logquit(1, "No disk space for file %s", to);
1261 #endif /* MACH */
1262 x = readfile(tof);
1263 (void) close(tof);
1264 if (x != SCMOK) {
1265 if (istemp)
1266 (void) unlink(tname);
1267 lockout(FALSE);
1268 goaway("Error in receiving %s\n", to);
1271 if (!istemp) { /* no temp file used */
1272 lockout(FALSE);
1273 return (FALSE);
1276 ** If the file is compressed, uncompress it in place. We open the
1277 ** temp file for reading, unlink the file, and then open the same
1278 ** file again for writing. Then we pipe through gzip. When
1279 ** finished the temp file contains the uncompressed version and we
1280 ** can continue as before.
1282 ** Since sup prefers to write close to the original file the
1283 ** benefits of atomic updates probably outweigh the cost of the
1284 ** extra filecopy which occurs when the temp file is on a different
1285 ** filesystem from the original.
1287 if (docompress) {
1288 char *av[4];
1289 int ac = 0;
1290 int infd = -1;
1291 int outfd = -1;
1292 av[ac++] = "gzip";
1293 av[ac++] = "-d";
1294 av[ac++] = NULL;
1295 if ((infd = open(tname, O_RDONLY, 0)) == -1 ||
1296 unlink(tname) == -1 ||
1297 (outfd = open(tname, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) == -1 ||
1298 runiofd(av, infd, outfd, 2) != 0) {
1299 notify("SUP: Error in uncompressing file %s (%s)\n",
1300 to, tname);
1301 (void) unlink(tname);
1302 if (infd != -1)
1303 (void) close(infd);
1304 if (outfd != -1)
1305 (void) close(outfd);
1306 lockout(FALSE);
1307 return (TRUE);
1309 (void) close(infd);
1310 (void) close(outfd);
1312 /* move to destination */
1313 if (rename(tname, to) == 0) {
1314 (void) unlink(tname);
1315 lockout(FALSE);
1316 return (FALSE);
1318 fromf = open(tname, O_RDONLY, 0);
1319 if (fromf < 0) {
1320 notify("SUP: Error in moving temp file to %s (%s)\n",
1321 to, strerror(errno));
1322 (void) unlink(tname);
1323 lockout(FALSE);
1324 return (TRUE);
1326 tof = open(to, (O_WRONLY | O_CREAT | O_TRUNC | O_EXCL), 0600);
1327 if (tof < 0) {
1328 (void) close(fromf);
1329 notify("SUP: Can't create %s from temp file (%s)\n",
1330 to, strerror(errno));
1331 (void) unlink(tname);
1332 lockout(FALSE);
1333 return (TRUE);
1335 x = filecopy(fromf, tof);
1336 (void) close(fromf);
1337 (void) close(tof);
1338 (void) unlink(tname);
1339 lockout(FALSE);
1340 if (x < 0) {
1341 notify("SUP: Error in storing data in %s\n", to);
1342 return (TRUE);
1344 return (FALSE);
1346 /*** Finish connection with file server ***/
1348 void
1349 finishup(int x)
1351 char tname[STRINGLENGTH], fname[STRINGLENGTH];
1352 char relsufix[STRINGLENGTH];
1353 char collrelname[STRINGLENGTH];
1354 time_t tloc;
1355 FILE *finishfile; /* record of all filenames */
1357 if ((thisC->Cflags & CFURELSUF) && release) {
1358 (void) sprintf(relsufix, ".%s", release);
1359 (void) sprintf(collrelname, "%s-%s", collname, release);
1360 } else {
1361 relsufix[0] = '\0';
1362 (void) strcpy(collrelname, collname);
1364 dontjump = TRUE; /* once here, no more longjmp */
1365 (void) netcrypt((char *) NULL);
1366 if (protver < 6) {
1367 /* done with server */
1368 if (x == SCMOK)
1369 goaway((char *) NULL);
1370 (void) requestend();
1372 tloc = time((time_t *) NULL);
1373 if (x != SCMOK) {
1374 notify("SUP: Upgrade of %s aborted at %s",
1375 collrelname, ctime(&tloc) + 4);
1376 Tfree(&lastT);
1377 if (protver < 6)
1378 return;
1379 /* if we've not been blown off, make sure he is! */
1380 if (x != SCMEOF)
1381 goaway("Aborted");
1382 (void) requestend();
1383 return;
1385 if (thisC->Cnogood) {
1386 notify("SUP: Upgrade of %s completed with errors at %s",
1387 collrelname, ctime(&tloc) + 4);
1388 notify("SUP: Upgrade time will not be updated\n");
1389 Tfree(&lastT);
1390 if (protver < 6)
1391 return;
1392 done(FDONEUSRERROR, "Completed with errors");
1393 (void) requestend();
1394 return;
1396 if (thisC->Cprefix)
1397 (void) chdir(thisC->Cbase);
1398 vnotify("SUP Upgrade of %s completed at %s",
1399 collrelname, ctime(&tloc) + 4);
1400 if (thisC->Cflags & CFLIST) {
1401 Tfree(&lastT);
1402 if (protver < 6)
1403 return;
1404 done(FDONEDONTLOG, "List only");
1405 (void) requestend();
1406 return;
1408 (void) sprintf(fname, FILEWHEN, collname, relsufix);
1409 if (establishdir(fname)) {
1410 Tfree(&lastT);
1411 if (protver < 6)
1412 return;
1413 done(FDONEUSRERROR, "Couldn't timestamp");
1414 (void) requestend();
1415 return;
1417 if (!putwhen(fname, scantime)) {
1418 notify("SUP: Can't record current time in %s (%s)\n",
1419 fname, strerror(errno));
1420 Tfree(&lastT);
1421 if (protver < 6)
1422 return;
1423 done(FDONEUSRERROR, "Couldn't timestamp");
1424 (void) requestend();
1425 return;
1427 if (protver >= 6) {
1428 /* At this point we have let the server go */
1429 /* "I'm sorry, we've had to let you go" */
1430 done(FDONESUCCESS, "Success");
1431 (void) requestend();
1433 (void) sprintf(tname, FILELASTTEMP, collname, relsufix);
1434 finishfile = fopen(tname, "w");
1435 if (finishfile == NULL) {
1436 notify("SUP: Can't record list of all files in %s\n", tname);
1437 Tfree(&lastT);
1438 return;
1440 (void) Tprocess(lastT, finishone, finishfile);
1441 (void) fclose(finishfile);
1442 (void) sprintf(fname, FILELAST, collname, relsufix);
1443 if (rename(tname, fname) < 0)
1444 notify("SUP: Can't change %s to %s (%s)\n", tname, fname,
1445 strerror(errno));
1446 (void) unlink(tname);
1447 Tfree(&lastT);
1450 int
1451 finishone(TREE * t, void *fv)
1453 FILE *finishfile = fv;
1454 if ((thisC->Cflags & CFDELETE) == 0 || (t->Tflags & FUPDATE))
1455 fprintf(finishfile, "%s\n", t->Tname);
1456 return (SCMOK);
1459 void
1460 done(int value, const char *fmt, ...)
1462 char buf[STRINGLENGTH];
1463 va_list ap;
1465 va_start(ap, fmt);
1466 (void) netcrypt((char *) NULL);
1468 if (fmt)
1469 vsnprintf(buf, sizeof(buf), fmt, ap);
1470 va_end(ap);
1471 if (protver < 6) {
1472 if (goawayreason)
1473 free(goawayreason);
1474 goawayreason = (fmt) ? estrdup(buf) : (char *) NULL;
1475 (void) msggoaway();
1476 } else {
1477 doneack = value;
1478 donereason = (fmt) ? buf : (char *) NULL;
1479 (void) msgdone();
1481 if (!dontjump)
1482 longjmp(sjbuf, TRUE);
1485 void
1486 goaway(const char *fmt, ...)
1488 char buf[STRINGLENGTH];
1489 va_list ap;
1491 va_start(ap, fmt);
1493 (void) netcrypt((char *) NULL);
1494 if (fmt) {
1495 vsnprintf(buf, sizeof(buf), fmt, ap);
1496 goawayreason = buf;
1497 } else
1498 goawayreason = NULL;
1499 va_end(ap);
1500 (void) msggoaway();
1501 if (fmt) {
1502 if (thisC)
1503 notify("SUP: %s\n", buf);
1504 else
1505 printf("SUP: %s\n", buf);
1507 if (!dontjump)
1508 longjmp(sjbuf, TRUE);