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 */
27 #include <afs/afs_args.h>
28 #include <sys/param.h>
38 #include <sys/ioctl.h>
42 #include <sys/ioctl.h>
44 #ifdef HAVE_NETINET_IN_H
45 #include <netinet/in.h>
56 #include <afs/venus.h>
58 /* ************************************************************* */
62 #if !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
64 extern char *sys_errlist[];
67 Boolean verbose = false;
68 Boolean renameTargets = false;
69 Boolean oneLevel = false;
70 Boolean preserveDate = true;
71 Boolean preserveMountPoints = false;
72 Boolean forceOverwrite = false;
75 Boolean setacl = true;
76 Boolean oldAcl = false;
77 char file1[MAXPATHLEN], file2[MAXPATHLEN];
80 static char space[MAXSIZE];
89 /* ************************************************************ */
93 /* ************************************************************ */
95 #include "AFS_component_version_number.c"
104 * The following signal action for AIX is necessary so that in case of a
105 * crash (i.e. core is generated) we can include the user's data section
106 * in the core dump. Unfortunately, by default, only a partial core is
107 * generated which, in many cases, isn't too useful.
109 struct sigaction nsa;
111 sigemptyset(&nsa.sa_mask);
112 nsa.sa_handler = SIG_DFL;
113 nsa.sa_flags = SA_FULLDUMP;
114 sigaction(SIGSEGV, &nsa, NULL);
116 #if !defined (AFS_AIX_ENV) && !defined (AFS_HPUX_ENV)
117 pageSize = getpagesize();
119 ScanArgs(argc, argv);
121 /* now read each line of the CopyList */
122 if (Copy(file1, file2, !oneLevel, 0))
123 exit(1); /* some type of failure */
134 /* skip program name */
137 /* check for -flag options */
138 while (argc > 0 && *argv[0] == '-') {
151 renameTargets = true;
155 forceOverwrite = true;
159 preserveDate = false;
163 preserveMountPoints = true;
167 fprintf(stderr, "Unknown option: '%c'\n", *cp);
168 fprintf(stderr, "usage: up [-v1frxm] from to\n");
175 fprintf(stderr, "usage: up [-v1frx] from to\n");
179 strncpy(file1, argv[0], MAXPATHLEN);
180 strncpy(file2, argv[1], MAXPATHLEN);
188 * Make sure the parent directory of this file exists. Returns
189 * true if it exists, false otherwise. Note: the owner argument
190 * is a hack. All directories made will have this owner.
193 MakeParent(file, owner)
197 char parent[MAXPATHLEN];
201 strcpy(parent, file);
203 p = strrchr(parent, '/');
206 } else if (p > parent) {
212 if (stat(parent, &s) < 0) {
213 if (!MakeParent(parent, owner))
217 printf("Creating directory %s\n", parent);
222 chown(parent, owner, -1);
230 * This does the bulk of the work of the program. Handle one file,
231 * possibly copying subfiles if this is a directory
233 Copy(file1, file2, recursive, level)
234 char *file1; /* input file name */
235 char *file2; /* output file name */
236 Boolean recursive; /* true if directory should be copied */
237 int level; /* level of recursion: 0, 1, ... */
240 struct stat s1, s2; /*Stat blocks */
241 struct ViceIoctl blob;
242 char aclspace[MAXACL];
243 afs_int32 rcode = 0, code;
246 code = lstat(file1, &s1);
248 fprintf(stderr, "Can't find %s\n", file1);
252 code = lstat(file2, &s2);
254 if (!MakeParent(file2, s1.st_uid))
259 if ((s1.st_mode & S_IFMT) == S_IFREG) {
261 * -------------------- Copy regular file --------------------
264 char buf[4096]; /* Must be bigger than sizeof (*head) */
265 struct timeval tv[2];
266 char tmpfile[MAXPATHLEN], newName[MAXPATHLEN];
269 printf("Level %d: File %s to %s\n", level, file1, file2);
273 /* Wonder if there is a security hole */
274 if (((s1.st_mode & 04002) == 04002) || ((s1.st_mode & 04020) == 04020)
275 || ((s1.st_mode & 02002) == 02002)) {
277 "WARNING: Mode-bits security hole in files %s and %s\n",
281 if (!goods2 || (s1.st_mtime != s2.st_mtime) || (s1.st_size != s2.st_size)) { /*c */
282 /* Don't ovewrite a write protected file (unless force: -f) */
283 if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
285 "File %s is write protected against its owner; not changed\n",
291 printf(" Copy file %s to %s (%u Bytes)\n", file1, file2,
296 strcpy(tmpfile, file2); /* Name of temporary file */
297 strcat(tmpfile, ".UPD");
299 /* open file1 for input */
300 f1 = open(file1, O_RDONLY);
302 fprintf(stderr, "Unable to open input file %s, ", file1);
303 if (errno >= sys_nerr)
304 fprintf(stderr, "error code = %d\n", errno);
306 fprintf(stderr, "%s\n", sys_errlist[errno]);
310 /* open temporary output file */
311 f2 = open(tmpfile, (O_WRONLY | O_CREAT | O_TRUNC), s1.st_mode);
313 fprintf(stderr, "Unable to open output file %s, ", tmpfile);
314 if (errno >= sys_nerr)
315 fprintf(stderr, "error code = %d\n", errno);
317 fprintf(stderr, "%s\n", sys_errlist[errno]);
323 /* Copy file1 to temporary file */
324 while ((n = read(f1, buf, sizeof(buf))) > 0) {
325 if (write(f2, buf, n) != n) {
327 "Write failed, file %s must be copied again.\n",
332 /* preserve access and modification times: ("-x" disables) */
334 tv[0].tv_sec = s1.st_atime;
336 tv[1].tv_sec = s1.st_mtime;
341 /* Close the files */
349 /* Rename file2 to file2.old. [-r] */
350 if (renameTargets && goods2) {
351 strcpy(newName, file2);
352 strcat(newName, ".old");
354 printf(" Renaming %s to %s\n", file2, newName);
357 if (rename(file2, newName) < 0) {
358 fprintf(stderr, "Rename of %s to %s failed.\n", file2,
363 /* Rename temporary file to file2 */
364 code = rename(tmpfile, file2);
366 fprintf(stderr, "Rename of %s to %s failed.\n", tmpfile,
371 /* Re-stat file2 and compare file sizes */
372 code = lstat(file2, &s2);
374 fprintf(stderr, "WARNING: Unable to stat new file %s\n",
378 if (s1.st_size != s2.st_size) {
380 "WARNING: New file %s is %u bytes long; should be %u\n",
381 file2, s2.st_size, s1.st_size);
386 /* Set the user-id */
387 if (s2.st_uid != s1.st_uid) {
389 printf(" Set owner-id for %s to %d\n", file2, s1.st_uid);
392 code = chown(file2, s1.st_uid, -1);
394 fprintf(stderr, "Unable to set owner-id for %s to %d\n",
398 s1.st_mode &= ~04000; /* Don't set suid bit */
402 /* Set the group-id */
403 if (s2.st_gid != s1.st_gid) {
405 printf(" Set group-id for %s to %d\n", file2, s1.st_gid);
408 code = chown(file2, -1, s1.st_gid);
410 fprintf(stderr, "Unable to set group-id for %s to %d\n",
414 s1.st_mode &= ~02000; /* Don't set sgid bit */
418 /* Set the mode bits */
419 if (s1.st_mode != s2.st_mode) {
421 printf(" Set mode-bit for %s to %o\n", file2,
422 (s1.st_mode & 07777));
425 code = chmod(file2, s1.st_mode);
427 fprintf(stderr, "Unable to set mode-bits for %s to %d\n",
434 else if ((s1.st_mode & S_IFMT) == S_IFLNK) {
436 * --------------------- Copy symlink --------------------
438 char linkvalue[MAXPATHLEN + 1];
442 printf("Level %d: Symbolic link %s to %s\n", level, file1, file2);
446 /* Don't ovewrite a write protected directory (unless force: -f) */
447 if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
449 "Link %s is write protected against its owner; not changed\n",
455 printf(" Copy symbolic link %s->%s to %s\n", file1, linkvalue,
460 n = readlink(file1, linkvalue, sizeof(linkvalue));
462 fprintf(stderr, "Could not read symbolic link %s\n", file1);
463 perror("read link ");
468 unlink(file2); /* Always make the new link (it was easier) */
470 code = symlink(linkvalue, file2);
472 fprintf(stderr, "Could not create symbolic link %s\n", file2);
473 perror("create link ");
477 /*Dealing with symlink */
478 else if (preserveMountPoints && (code = isMountPoint(file1, &blob))) {
480 * --------------------- Copy mount point --------------------
484 perror("checking for mount point ");
488 printf("Level %d: Mount point %s to %s\n", level, file1, file2);
492 /* Don't ovewrite a write protected directory (unless force: -f) */
493 if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
495 "Target %s is write protected against its owner; not changed\n",
501 printf(" Copy mount point %s for vol %s to %s\n", file1,
506 unlink(file2); /* Always make the new link (it was easier) */
508 strcat(blob.out, "."); /* stupid convention; these end with a period */
509 code = symlink(blob.out, file2);
511 fprintf(stderr, "Could not create mount point %s for vol %s\n",
513 perror("create mount point ");
518 /*Dealing with mount point */
519 else if (((s1.st_mode & S_IFMT) == S_IFDIR)
520 && (recursive || (level == 0))) {
522 * ----------------------- Copy directory -----------------------
528 char f1[MAXPATHLEN], f2[MAXPATHLEN];
533 printf("Level %d: Directory %s to %s\n", level, file1, file2);
537 /* Don't ovewrite a write protected directory (unless force: -f) */
538 if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
540 "Directory %s is write protected against its owner; not changed\n",
547 p1 = f1 + strlen(f1);
548 p2 = f2 + strlen(f2);
549 if (p1 == f1 || p1[-1] != '/')
551 if (p2 == f2 || p2[-1] != '/')
554 dir = opendir(file1);
556 fprintf(stderr, "Couldn't open %s\n", file1);
560 while ((d = readdir(dir)) != NULL) {
561 if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0)
563 strcpy(p1, d->d_name);
564 strcpy(p2, d->d_name);
565 code = Copy(f1, f2, recursive, level + 1);
567 rcode = 1; /* remember errors */
573 printf("Level %d: Copied directory %s to %s\n", level, file1,
578 mkdir(file2, 0777); /* Handle case where MakeParent not invoked. */
581 printf(" Set owner-id for %s to %d\n", file2, s1.st_uid);
584 code = chown(file2, s1.st_uid, -1);
586 fprintf(stderr, "Unable to set owner-id for %s to %d\n", file2,
589 s1.st_mode &= ~04000; /* Don't set suid bit */
593 printf(" Set group-id for %s to %d\n", file2, s1.st_gid);
596 code = chown(file2, -1, s1.st_gid);
598 fprintf(stderr, "Unable to set group-id for %s to %d\n", file2,
601 s1.st_mode &= ~02000; /* Don't set sgid bit */
605 printf(" Set mode-bit for %s to %o\n", file2,
606 (s1.st_mode & 07777));
609 code = chmod(file2, s1.st_mode);
611 fprintf(stderr, "Unable to set mode-bits for %s to %d\n", file2,
617 if (setacl == true) {
619 printf(" Set acls for %s\n", file2);
626 blob.out_size = MAXACL;
629 /* Get an old-style ACL and convert it */
631 printf(" Getting old style acl\n");
635 for (i = 1; i < strlen(file1); i++)
638 strcpy(aclspace, &file1[i]);
640 blob.in_size = 1 + strlen(aclspace);
641 tfd = open(file1, O_RDONLY, 0);
643 perror("old-acl open ");
646 code = ioctl(tfd, _VICEIOCTL(4), &blob);
649 if (errno == EINVAL) {
652 printf(" _VICEIOCTL(4) returns EINVAL\n");
659 /* Now convert the thing. */
660 oacl = (struct OldAcl *)(aclspace + 4);
661 sprintf(tacl, "%d\n%d\n", oacl->nplus, oacl->nminus);
662 strcat(tacl, oacl->data);
663 strcpy(aclspace, tacl);
664 } /*Grab and convert old-style ACL */
666 /* Get a new-style ACL */
668 printf(" Getting new style acl\n");
672 code = pioctl(file1, _VICEIOCTL(2), &blob, 1);
674 if (errno == EINVAL) {
677 printf(" _VICEIOCTL(2) returns EINVAL\n");
685 } /*Grab new-style ACL */
688 * Now, set the new-style ACL.
690 if (setacl == true) {
692 printf(" Setting new style acl\n");
698 blob.in_size = 1 + strlen(aclspace);
699 code = pioctl(file2, _VICEIOCTL(1), &blob, 1);
701 if (errno == EINVAL) {
704 printf(" _VICEIOCTL(1) returns EINVAL\n");
708 fprintf(stderr, "Couldn't set acls for %s\n", file2);
714 if (setacl == false) {
715 printf("Not setting acls\n");
725 isMountPoint(name, blob)
727 struct ViceIoctl *blob;
730 char true_name[1024]; /*dirname */
731 char parent_dir[1024]; /*Parent directory of true name */
732 char *last_component; /*Last component of true name */
734 sprintf(true_name, "%s%s", (name[0] == '/') ? "" : "./", name);
737 * Find rightmost slash, if any.
739 last_component = (char *)strrchr(true_name, '/');
740 if (last_component) {
742 * Found it. Designate everything before it as the parent directory,
743 * everything after it as the final component.
745 strncpy(parent_dir, true_name, last_component - true_name);
746 parent_dir[last_component - true_name] = 0;
747 last_component++; /*Skip the slash */
750 * No slash appears in the given file name. Set parent_dir to the current
751 * directory, and the last component as the given name.
753 strcpy(parent_dir, ".");
754 last_component = true_name;
757 if (strcmp(last_component, ".") == 0 || strcmp(last_component, "..") == 0) {
759 "up: you may not use '.' or '..' as the last component\n");
760 fprintf(stderr, "up: of a name in the 'up' command.\n");
764 blob->in = last_component;
765 blob->in_size = strlen(last_component) + 1;
766 blob->out_size = MAXSIZE;
768 memset(space, 0, MAXSIZE);
770 code = pioctl(parent_dir, VIOC_AFS_STAT_MT_PT, blob, 0);
773 printf("'%s' is a mount point for volume '%s'\n", name, space);
777 if (errno == EINVAL) {
778 /* printf( "'%s' is not a mount point.\n", name);
783 fprintf(stderr, "problem examining '%s' in '%s'.\n",
784 last_component, parent_dir);
786 /* Die(errno, (ti->data ? ti->data : parent_dir));