2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
16 /* missing type from C language */
24 #include <afs/afs_args.h>
25 #include <sys/param.h>
35 #include <sys/ioctl.h>
39 #include <sys/ioctl.h>
41 #ifdef HAVE_NETINET_IN_H
42 #include <netinet/in.h>
47 #include <afs/venus.h>
49 /* ************************************************************* */
53 #if !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
55 extern char *sys_errlist[];
59 short renameTargets = 0;
61 short preserveDate = 1;
62 short preserveMountPoints = 0;
63 short forceOverwrite = 0;
68 char file1[MAXPATHLEN], file2[MAXPATHLEN];
71 static char space[MAXSIZE];
80 static void ScanArgs(int argc, char *argv[]);
81 static short MakeParent(char *file, afs_int32 owner);
82 static int Copy(char *file1, char *file2, short recursive, int level);
83 static int isMountPoint(char *name, struct ViceIoctl *blob);
86 /* ************************************************************ */
90 /* ************************************************************ */
92 #include "AFS_component_version_number.c"
95 main(int argc, char *argv[])
99 * The following signal action for AIX is necessary so that in case of a
100 * crash (i.e. core is generated) we can include the user's data section
101 * in the core dump. Unfortunately, by default, only a partial core is
102 * generated which, in many cases, isn't too useful.
104 struct sigaction nsa;
106 sigemptyset(&nsa.sa_mask);
107 nsa.sa_handler = SIG_DFL;
108 nsa.sa_flags = SA_FULLDUMP;
109 sigaction(SIGSEGV, &nsa, NULL);
111 #if !defined (AFS_AIX_ENV) && !defined (AFS_HPUX_ENV)
112 pageSize = getpagesize();
114 ScanArgs(argc, argv);
116 /* now read each line of the CopyList */
117 if (Copy(file1, file2, !oneLevel, 0))
118 return(1); /* some type of failure */
124 #define USAGE "usage: up [-v1frxm] from to\n"
126 ScanArgs(int argc, char *argv[])
128 /* skip program name */
131 /* check for -flag options */
132 while (argc > 0 && *argv[0] == '-') {
157 preserveMountPoints = 1;
161 fprintf(stderr, "Unknown option: '%c'\n", *cp);
162 fprintf(stderr, USAGE);
169 fprintf(stderr, USAGE);
173 strncpy(file1, argv[0], MAXPATHLEN);
174 strncpy(file2, argv[1], MAXPATHLEN);
182 * Make sure the parent directory of this file exists. Returns
183 * 1 if it exists, 0 otherwise. Note: the owner argument
184 * is a hack. All directories made will have this owner.
187 MakeParent(char *file, afs_int32 owner)
189 char parent[MAXPATHLEN];
193 strcpy(parent, file);
195 p = strrchr(parent, '/');
198 } else if (p > parent) {
204 if (stat(parent, &s) < 0) {
205 if (!MakeParent(parent, owner))
209 printf("Creating directory %s\n", parent);
214 chown(parent, owner, -1);
222 * This does the bulk of the work of the program. Handle one file,
223 * possibly copying subfiles if this is a directory
226 Copy(char *file1, char *file2, short recursive, int level)
228 struct stat s1, s2; /*Stat blocks */
229 struct ViceIoctl blob;
230 char aclspace[MAXACL];
231 afs_int32 rcode = 0, code;
234 code = lstat(file1, &s1);
236 fprintf(stderr, "Can't find %s\n", file1);
240 code = lstat(file2, &s2);
242 if (!MakeParent(file2, s1.st_uid))
247 if ((s1.st_mode & S_IFMT) == S_IFREG) {
249 * -------------------- Copy regular file --------------------
252 char buf[4096]; /* Must be bigger than sizeof (*head) */
253 struct timeval tv[2];
254 char tmpfile[MAXPATHLEN], newName[MAXPATHLEN];
257 printf("Level %d: File %s to %s\n", level, file1, file2);
261 /* Wonder if there is a security hole */
262 if (((s1.st_mode & 04002) == 04002) || ((s1.st_mode & 04020) == 04020)
263 || ((s1.st_mode & 02002) == 02002)) {
265 "WARNING: Mode-bits security hole in files %s and %s\n",
269 if (!goods2 || (s1.st_mtime != s2.st_mtime) || (s1.st_size != s2.st_size)) { /*c */
270 /* Don't ovewrite a write protected file (unless force: -f) */
271 if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
273 "File %s is write protected against its owner; not changed\n",
279 printf(" Copy file %s to %s (%u Bytes)\n", file1, file2,
284 strcpy(tmpfile, file2); /* Name of temporary file */
285 strcat(tmpfile, ".UPD");
287 /* open file1 for input */
288 f1 = open(file1, O_RDONLY);
290 fprintf(stderr, "Unable to open input file %s, ", file1);
291 if (errno >= sys_nerr)
292 fprintf(stderr, "error code = %d\n", errno);
294 fprintf(stderr, "%s\n", sys_errlist[errno]);
298 /* open temporary output file */
299 f2 = open(tmpfile, (O_WRONLY | O_CREAT | O_TRUNC), s1.st_mode);
301 fprintf(stderr, "Unable to open output file %s, ", tmpfile);
302 if (errno >= sys_nerr)
303 fprintf(stderr, "error code = %d\n", errno);
305 fprintf(stderr, "%s\n", sys_errlist[errno]);
311 /* Copy file1 to temporary file */
312 while ((n = read(f1, buf, sizeof(buf))) > 0) {
313 if (write(f2, buf, n) != n) {
315 "Write failed, file %s must be copied again.\n",
320 /* preserve access and modification times: ("-x" disables) */
322 tv[0].tv_sec = s1.st_atime;
324 tv[1].tv_sec = s1.st_mtime;
329 /* Close the files */
337 /* Rename file2 to file2.old. [-r] */
338 if (renameTargets && goods2) {
339 strcpy(newName, file2);
340 strcat(newName, ".old");
342 printf(" Renaming %s to %s\n", file2, newName);
345 if (rename(file2, newName) < 0) {
346 fprintf(stderr, "Rename of %s to %s failed.\n", file2,
351 /* Rename temporary file to file2 */
352 code = rename(tmpfile, file2);
354 fprintf(stderr, "Rename of %s to %s failed.\n", tmpfile,
359 /* Re-stat file2 and compare file sizes */
360 code = lstat(file2, &s2);
362 fprintf(stderr, "WARNING: Unable to stat new file %s\n",
366 if (s1.st_size != s2.st_size) {
368 "WARNING: New file %s is %u bytes long; should be %u\n",
369 file2, s2.st_size, s1.st_size);
374 /* Set the user-id */
375 if (s2.st_uid != s1.st_uid) {
377 printf(" Set owner-id for %s to %d\n", file2, s1.st_uid);
380 code = chown(file2, s1.st_uid, -1);
382 fprintf(stderr, "Unable to set owner-id for %s to %d\n",
386 s1.st_mode &= ~04000; /* Don't set suid bit */
390 /* Set the group-id */
391 if (s2.st_gid != s1.st_gid) {
393 printf(" Set group-id for %s to %d\n", file2, s1.st_gid);
396 code = chown(file2, -1, s1.st_gid);
398 fprintf(stderr, "Unable to set group-id for %s to %d\n",
402 s1.st_mode &= ~02000; /* Don't set sgid bit */
406 /* Set the mode bits */
407 if (s1.st_mode != s2.st_mode) {
409 printf(" Set mode-bit for %s to %o\n", file2,
410 (s1.st_mode & 07777));
413 code = chmod(file2, s1.st_mode);
415 fprintf(stderr, "Unable to set mode-bits for %s to %d\n",
422 else if ((s1.st_mode & S_IFMT) == S_IFLNK) {
424 * --------------------- Copy symlink --------------------
426 char linkvalue[MAXPATHLEN + 1];
430 printf("Level %d: Symbolic link %s to %s\n", level, file1, file2);
434 /* Don't ovewrite a write protected directory (unless force: -f) */
435 if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
437 "Link %s is write protected against its owner; not changed\n",
443 printf(" Copy symbolic link %s->%s to %s\n", file1, linkvalue,
448 n = readlink(file1, linkvalue, sizeof(linkvalue));
450 fprintf(stderr, "Could not read symbolic link %s\n", file1);
451 perror("read link ");
456 unlink(file2); /* Always make the new link (it was easier) */
458 code = symlink(linkvalue, file2);
460 fprintf(stderr, "Could not create symbolic link %s\n", file2);
461 perror("create link ");
465 /*Dealing with symlink */
466 else if (preserveMountPoints && (code = isMountPoint(file1, &blob))) {
468 * --------------------- Copy mount point --------------------
472 perror("checking for mount point ");
476 printf("Level %d: Mount point %s to %s\n", level, file1, file2);
480 /* Don't ovewrite a write protected directory (unless force: -f) */
481 if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
483 "Target %s is write protected against its owner; not changed\n",
489 printf(" Copy mount point %s for vol %s to %s\n", file1,
494 unlink(file2); /* Always make the new link (it was easier) */
496 strcat(blob.out, "."); /* stupid convention; these end with a period */
497 code = symlink(blob.out, file2);
499 fprintf(stderr, "Could not create mount point %s for vol %s\n",
501 perror("create mount point ");
506 /*Dealing with mount point */
507 else if (((s1.st_mode & S_IFMT) == S_IFDIR)
508 && (recursive || (level == 0))) {
510 * ----------------------- Copy directory -----------------------
516 char f1[MAXPATHLEN], f2[MAXPATHLEN];
519 struct timeval tv[2];
522 printf("Level %d: Directory %s to %s\n", level, file1, file2);
526 /* Don't ovewrite a write protected directory (unless force: -f) */
527 if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
529 "Directory %s is write protected against its owner; not changed\n",
536 p1 = f1 + strlen(f1);
537 p2 = f2 + strlen(f2);
538 if (p1 == f1 || p1[-1] != '/')
540 if (p2 == f2 || p2[-1] != '/')
543 dir = opendir(file1);
545 fprintf(stderr, "Couldn't open %s\n", file1);
549 while ((d = readdir(dir)) != NULL) {
550 if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0)
552 strcpy(p1, d->d_name);
553 strcpy(p2, d->d_name);
554 code = Copy(f1, f2, recursive, level + 1);
556 rcode = 1; /* remember errors */
562 printf("Level %d: Copied directory %s to %s\n", level, file1,
567 mkdir(file2, 0777); /* Handle case where MakeParent not invoked. */
570 printf(" Set owner-id for %s to %d\n", file2, s1.st_uid);
573 code = chown(file2, s1.st_uid, -1);
575 fprintf(stderr, "Unable to set owner-id for %s to %d\n", file2,
578 s1.st_mode &= ~04000; /* Don't set suid bit */
582 printf(" Set group-id for %s to %d\n", file2, s1.st_gid);
585 code = chown(file2, -1, s1.st_gid);
587 fprintf(stderr, "Unable to set group-id for %s to %d\n", file2,
590 s1.st_mode &= ~02000; /* Don't set sgid bit */
594 printf(" Set mode-bit for %s to %o\n", file2,
595 (s1.st_mode & 07777));
598 code = chmod(file2, s1.st_mode);
600 fprintf(stderr, "Unable to set mode-bits for %s to %d\n", file2,
608 printf(" Set acls for %s\n", file2);
615 blob.out_size = MAXACL;
618 /* Get an old-style ACL and convert it */
620 printf(" Getting old style acl\n");
624 for (i = 1; i < strlen(file1); i++)
627 strcpy(aclspace, &file1[i]);
629 blob.in_size = 1 + strlen(aclspace);
630 tfd = open(file1, O_RDONLY, 0);
632 perror("old-acl open ");
635 code = ioctl(tfd, _VICEIOCTL(4), &blob);
638 if (errno == EINVAL) {
641 printf(" _VICEIOCTL(4) returns EINVAL\n");
648 /* Now convert the thing. */
649 oacl = (struct OldAcl *)(aclspace + 4);
650 sprintf(tacl, "%d\n%d\n", oacl->nplus, oacl->nminus);
651 strcat(tacl, oacl->data);
652 strcpy(aclspace, tacl);
653 } /*Grab and convert old-style ACL */
655 /* Get a new-style ACL */
657 printf(" Getting new style acl\n");
661 code = pioctl(file1, _VICEIOCTL(2), &blob, 1);
663 if (errno == EINVAL) {
666 printf(" _VICEIOCTL(2) returns EINVAL\n");
674 } /*Grab new-style ACL */
677 * Now, set the new-style ACL.
681 printf(" Setting new style acl\n");
687 blob.in_size = 1 + strlen(aclspace);
688 code = pioctl(file2, _VICEIOCTL(1), &blob, 1);
690 if (errno == EINVAL) {
693 printf(" _VICEIOCTL(1) returns EINVAL\n");
697 fprintf(stderr, "Couldn't set acls for %s\n", file2);
704 printf("Not setting acls\n");
708 /* preserve access and modification times: ("-x" disables) */
710 tv[0].tv_sec = s1.st_atime;
712 tv[1].tv_sec = s1.st_mtime;
723 isMountPoint(char *name, struct ViceIoctl *blob)
726 char true_name[1024]; /*dirname */
727 char parent_dir[1024]; /*Parent directory of true name */
728 char *last_component; /*Last component of true name */
730 sprintf(true_name, "%s%s", (name[0] == '/') ? "" : "./", name);
733 * Find rightmost slash, if any.
735 last_component = (char *)strrchr(true_name, '/');
736 if (last_component) {
738 * Found it. Designate everything before it as the parent directory,
739 * everything after it as the final component.
741 strncpy(parent_dir, true_name, last_component - true_name);
742 parent_dir[last_component - true_name] = 0;
743 last_component++; /*Skip the slash */
746 * No slash appears in the given file name. Set parent_dir to the current
747 * directory, and the last component as the given name.
749 strcpy(parent_dir, ".");
750 last_component = true_name;
753 if (strcmp(last_component, ".") == 0 || strcmp(last_component, "..") == 0) {
755 "up: you may not use '.' or '..' as the last component\n");
756 fprintf(stderr, "up: of a name in the 'up' command.\n");
760 blob->in = last_component;
761 blob->in_size = strlen(last_component) + 1;
762 blob->out_size = MAXSIZE;
764 memset(space, 0, MAXSIZE);
766 code = pioctl(parent_dir, VIOC_AFS_STAT_MT_PT, blob, 0);
769 printf("'%s' is a mount point for volume '%s'\n", name, space);
773 if (errno == EINVAL) {
774 /* printf( "'%s' is not a mount point.\n", name);
779 fprintf(stderr, "problem examining '%s' in '%s'.\n",
780 last_component, parent_dir);
782 /* Die(errno, (ti->data ? ti->data : parent_dir));