Module Name: src
Committed By: christos
Date: Wed Sep 21 19:34:54 UTC 2011
Modified Files:
src/usr.sbin/sup/source: sup.1 supcdefs.h supcmain.c supcmeat.c
supcparse.c
Log Message:
Add a canonicalize option to avoid disaster when one converts directories
to symlinks in the tree and back. This option is expensive, it could be
made better by cacheing, but not now.
To generate a diff of this commit:
cvs rdiff -u -r1.18 -r1.19 src/usr.sbin/sup/source/sup.1
cvs rdiff -u -r1.13 -r1.14 src/usr.sbin/sup/source/supcdefs.h
cvs rdiff -u -r1.31 -r1.32 src/usr.sbin/sup/source/supcmain.c
cvs rdiff -u -r1.39 -r1.40 src/usr.sbin/sup/source/supcmeat.c
cvs rdiff -u -r1.14 -r1.15 src/usr.sbin/sup/source/supcparse.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/usr.sbin/sup/source/sup.1
diff -u src/usr.sbin/sup/source/sup.1:1.18 src/usr.sbin/sup/source/sup.1:1.19
--- src/usr.sbin/sup/source/sup.1:1.18 Sun Nov 1 19:29:04 2009
+++ src/usr.sbin/sup/source/sup.1 Wed Sep 21 15:34:54 2011
@@ -1,4 +1,4 @@
-.\" $NetBSD: sup.1,v 1.18 2009/11/02 00:29:04 joerg Exp $
+.\" $NetBSD: sup.1,v 1.19 2011/09/21 19:34:54 christos Exp $
.\"
.\" Copyright (c) 1992 Carnegie Mellon University
.\" All Rights Reserved.
@@ -197,6 +197,16 @@
.B backup
supfile option.
.TP
+.B -C
+The
+.B -C
+flag or the
+.B canonicalize
+supfile option, canonicalize all pathnames upon reception to make sure
+local changes from directories to symlinks and vice versa have not happened
+behind sup's back, and attempt to repair them. This option is expensive.
+.TP
+.TP
.B -d
Files that are no longer in the collection on the
repository will be deleted if present on the local
@@ -861,6 +871,8 @@
that contains the same names.
Then sup will cross the symlink and start deleting files and directories
from the destination.
-This is not easily fixed.
+This is avoided by using the
+.B canonicalize
+option, but it is expensive.
Don't use sup with symlink/rsymlink and the delete
option at the same time or *be careful*!
Index: src/usr.sbin/sup/source/supcdefs.h
diff -u src/usr.sbin/sup/source/supcdefs.h:1.13 src/usr.sbin/sup/source/supcdefs.h:1.14
--- src/usr.sbin/sup/source/supcdefs.h:1.13 Fri Nov 29 22:10:58 2002
+++ src/usr.sbin/sup/source/supcdefs.h Wed Sep 21 15:34:54 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: supcdefs.h,v 1.13 2002/11/30 03:10:58 lukem Exp $ */
+/* $NetBSD: supcdefs.h,v 1.14 2011/09/21 19:34:54 christos Exp $ */
/*
* Copyright (c) 1992 Carnegie Mellon University
@@ -116,6 +116,7 @@
#define CFURELSUF 02000
#define CFCOMPRESS 04000
#define CFSILENT 10000
+#define CFCANONICALIZE 20000
/*************************
*** M A C R O S ***
Index: src/usr.sbin/sup/source/supcmain.c
diff -u src/usr.sbin/sup/source/supcmain.c:1.31 src/usr.sbin/sup/source/supcmain.c:1.32
--- src/usr.sbin/sup/source/supcmain.c:1.31 Wed Aug 31 12:25:00 2011
+++ src/usr.sbin/sup/source/supcmain.c Wed Sep 21 15:34:54 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: supcmain.c,v 1.31 2011/08/31 16:25:00 plunky Exp $ */
+/* $NetBSD: supcmain.c,v 1.32 2011/09/21 19:34:54 christos Exp $ */
/*
* Copyright (c) 1992 Carnegie Mellon University
@@ -470,7 +470,7 @@
int oflags, aflags;
int c;
-#define SUPOPTIONS "abBdDeEfkKlmM:NoOPRsStuvXzZ=:"
+#define SUPOPTIONS "abBCdDeEfkKlmM:NoOPRsStuvXzZ=:"
oflags = aflags = 0;
while ((c = getopt(*argc, *argv, SUPOPTIONS)) != -1)
@@ -502,6 +502,9 @@
oflags &= ~CFBACKUP;
aflags |= CFBACKUP;
break;
+ case 'C':
+ oflags |= CFCANONICALIZE;
+ break;
case 'd':
oflags |= CFDELETE;
aflags &= ~CFDELETE;
Index: src/usr.sbin/sup/source/supcmeat.c
diff -u src/usr.sbin/sup/source/supcmeat.c:1.39 src/usr.sbin/sup/source/supcmeat.c:1.40
--- src/usr.sbin/sup/source/supcmeat.c:1.39 Wed Aug 31 12:25:00 2011
+++ src/usr.sbin/sup/source/supcmeat.c Wed Sep 21 15:34:54 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: supcmeat.c,v 1.39 2011/08/31 16:25:00 plunky Exp $ */
+/* $NetBSD: supcmeat.c,v 1.40 2011/09/21 19:34:54 christos Exp $ */
/*
* Copyright (c) 1992 Carnegie Mellon University
@@ -140,6 +140,7 @@
static int linkone(TREE *, void *);
static int execone(TREE *, void *);
static int finishone(TREE *, void *);
+static int canonicalize(const char *);
/* The next two routines define the fsm to support multiple fileservers
@@ -493,6 +494,8 @@
*q = '\0';
if (strchr("#;:", *p))
continue;
+ if (canonicalize(p) != 0)
+ continue;
(void) Tinsert(&lastT, p, FALSE);
}
(void) fclose(f);
@@ -720,6 +723,8 @@
goaway("Error sending compression check to server");
if (docompress)
vnotify("SUP Using compressed file transfer\n");
+ if (thisC->Cflags & CFCANONICALIZE)
+ vnotify("SUP Filename canonicalization is on\n");
}
recvmore = TRUE;
upgradeT = NULL;
@@ -942,10 +947,22 @@
char dirpart[STRINGLENGTH], filepart[STRINGLENGTH];
char filename[STRINGLENGTH], buf[STRINGLENGTH];
struct timeval tbuf[2];
- int x;
+ int x, noupdate = 0;
char *p;
- if (t->Tflags & FUPDATE) {
+ switch (canonicalize(t->Tname)) {
+ case 0: /* Ok no changes */
+ break;
+ case 1:
+ noupdate = 1;
+ break;
+ case -1:
+ notify("SUP: Can't create path for %s (%s)\n", t->Tname,
+ strerror(errno));
+ return TRUE;
+ }
+
+ if ((t->Tflags & FUPDATE) && !noupdate) {
if ((t->Tflags & FNOACCT) == 0) {
/* convert user and group names to local ids */
ugconvert(t->Tuser, t->Tgroup, &t->Tuid, &t->Tgid,
@@ -1115,6 +1132,62 @@
return (SCMOK);
}
+/*
+ * We know that since "to" is a pathname coming from the server, it must
+ * not contain any symbolic links after the root, because otherwise the
+ * server would send us only the symlink above it. So we hunt for the symlink
+ * above and if found we convert the symlink to a directory, prepare the
+ * path below the symlink, and keep
+ */
+static int
+canonicalize(const char *to)
+{
+ char absto[STRINGLENGTH], cabsto[STRINGLENGTH * 4];
+ char dir[STRINGLENGTH], file[STRINGLENGTH];
+ char *a;
+ char *c;
+ size_t len;
+ struct stat st;
+ const char *pwd = thisC->Cprefix ? thisC->Cprefix : thisC->Cbase;
+
+ if ((thisC->Cflags & CFCANONICALIZE) == 0)
+ return 0;
+
+ path(to, dir, file);
+
+ len = strlen(pwd);
+ (void)snprintf(absto, sizeof(absto), "%s/%s", pwd, dir);
+
+ len++;
+ if (realpath(absto, cabsto) == NULL)
+ return -1;
+
+ a = absto + len;
+ c = cabsto + len;
+
+ while (*a && *c && *a == *c)
+ a++, c++;
+
+ if (*a == '\0' && *c == '\0')
+ return 0;
+
+ while (*a && *a != '/')
+ a++;
+
+ *a = '\0';
+ if (lstat(absto, &st) == -1 || !S_ISLNK(st.st_mode))
+ return -1;
+
+ if (unlink(absto) == -1)
+ return -1;
+
+ strcpy(c, a);
+ if (estabd(file, cabsto) == -1) {
+ return -1;
+ }
+ return 1;
+}
+
/* from will be 0 if reading from network */
int
copyfile(char *to, char *from)
Index: src/usr.sbin/sup/source/supcparse.c
diff -u src/usr.sbin/sup/source/supcparse.c:1.14 src/usr.sbin/sup/source/supcparse.c:1.15
--- src/usr.sbin/sup/source/supcparse.c:1.14 Sat Apr 1 20:39:48 2006
+++ src/usr.sbin/sup/source/supcparse.c Wed Sep 21 15:34:54 2011
@@ -1,4 +1,4 @@
-/* $NetBSD: supcparse.c,v 1.14 2006/04/02 01:39:48 christos Exp $ */
+/* $NetBSD: supcparse.c,v 1.15 2011/09/21 19:34:54 christos Exp $ */
/*
* Copyright (c) 1992 Carnegie Mellon University
@@ -69,7 +69,7 @@
OHOST, OBASE, OHOSTBASE, OPREFIX, ORELEASE,
ONOTIFY, OLOGIN, OPASSWORD, OCRYPT,
OBACKUP, ODELETE, OEXECUTE, OOLD, OTIMEOUT, OKEEP, OURELSUF,
- OCOMPRESS
+ OCOMPRESS, OCANONICALIZE
} OPTION;
struct option {
@@ -92,7 +92,8 @@
{ "timeout", OTIMEOUT },
{ "keep", OKEEP },
{ "use-rel-suffix", OURELSUF },
- { "compress", OCOMPRESS }
+ { "compress", OCOMPRESS },
+ { "canonicalize", OCANONICALIZE },
};
static void passdelim(char **, char);
@@ -215,6 +216,9 @@
case OCOMPRESS:
c->Cflags |= CFCOMPRESS;
break;
+ case OCANONICALIZE:
+ c->Cflags |= CFCANONICALIZE;
+ break;
case OTIMEOUT:
passdelim(&args, '=');
arg = nxtarg(&args, " \t");