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 <afs/param.h>
11 #include <afsconfig.h>
15 /* missing type from C language */
26 #include <afs/afs_args.h>
27 #include <sys/param.h>
37 #include <sys/ioctl.h>
41 #include <sys/ioctl.h>
43 #ifdef HAVE_NETINET_IN_H
44 #include <netinet/in.h>
46 #include <afs/venus.h>
48 /* ************************************************************* */
52 extern char *index ();
53 extern char *rindex ();
54 #if !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
56 extern char *sys_errlist[];
59 Boolean verbose = false;
60 Boolean renameTargets = false;
61 Boolean oneLevel = false;
62 Boolean preserveDate = true;
63 Boolean preserveMountPoints = false;
64 Boolean forceOverwrite = false;
67 Boolean setacl = true;
68 Boolean oldAcl = false;
69 char file1[MAXPATHLEN], file2[MAXPATHLEN];
72 static char space[MAXSIZE];
81 /* ************************************************************ */
85 /* ************************************************************ */
87 #include "AFS_component_version_number.c"
96 * The following signal action for AIX is necessary so that in case of a
97 * crash (i.e. core is generated) we can include the user's data section
98 * in the core dump. Unfortunately, by default, only a partial core is
99 * generated which, in many cases, isn't too useful.
101 struct sigaction nsa;
103 sigemptyset(&nsa.sa_mask);
104 nsa.sa_handler = SIG_DFL;
105 nsa.sa_flags = SA_FULLDUMP;
106 sigaction(SIGSEGV, &nsa, NULL);
108 #if !defined (AFS_AIX_ENV) && !defined (AFS_HPUX_ENV)
109 pageSize = getpagesize();
111 ScanArgs(argc, argv);
113 /* now read each line of the CopyList */
114 if (Copy(file1, file2, !oneLevel, 0))
115 exit(1); /* some type of failure */
126 /* skip program name */
129 /* check for -flag options */
130 while (argc > 0 && *argv[0] == '-') {
143 renameTargets = true;
147 forceOverwrite = true;
151 preserveDate = false;
155 preserveMountPoints = true;
159 fprintf(stderr, "Unknown option: '%c'\n", *cp);
160 fprintf(stderr, "usage: up [-v1frxm] from to\n");
167 fprintf(stderr, "usage: up [-v1frx] from to\n");
171 strncpy(file1, argv[0], MAXPATHLEN);
172 strncpy(file2, argv[1], MAXPATHLEN);
180 * Make sure the parent directory of this file exists. Returns
181 * true if it exists, false otherwise. Note: the owner argument
182 * is a hack. All directories made will have this owner.
184 Boolean MakeParent(file, owner)
188 char parent[MAXPATHLEN];
192 strcpy(parent, file);
194 p = rindex(parent, '/');
198 else if (p > parent) {
205 if (stat(parent, &s) < 0) {
206 if (!MakeParent(parent, owner))
210 printf("Creating directory %s\n", parent);
215 chown(parent, owner, -1);
223 * This does the bulk of the work of the program. Handle one file,
224 * possibly copying subfiles if this is a directory
226 Copy(file1, file2, recursive, level)
227 char *file1; /* input file name */
228 char *file2; /* output file name */
229 Boolean recursive; /* true if directory should be copied */
230 int level; /* level of recursion: 0, 1, ... */
233 struct stat s1, s2; /*Stat blocks*/
234 struct ViceIoctl blob;
235 char aclspace[MAXACL];
236 afs_int32 rcode = 0, code;
239 code = lstat(file1, &s1);
241 fprintf(stderr,"Can't find %s\n",file1);
245 code = lstat(file2, &s2);
247 if (!MakeParent(file2,s1.st_uid))
252 if ((s1.st_mode & S_IFMT) == S_IFREG) {
254 * -------------------- Copy regular file --------------------
257 char buf[4096]; /* Must be bigger than sizeof (*head) */
258 struct timeval tv[2];
259 char tmpfile[MAXPATHLEN], newName[MAXPATHLEN];
262 printf("Level %d: File %s to %s\n", level, file1, file2);
266 /* Wonder if there is a security hole */
267 if ( ((s1.st_mode & 04002) == 04002) ||
268 ((s1.st_mode & 04020) == 04020) ||
269 ((s1.st_mode & 02002) == 02002) ) {
270 fprintf(stderr, "WARNING: Mode-bits security hole in files %s and %s\n",
274 if (!goods2 || (s1.st_mtime != s2.st_mtime) || (s1.st_size != s2.st_size)) { /*c*/
275 /* Don't ovewrite a write protected file (unless force: -f) */
276 if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
278 "File %s is write protected against its owner; not changed\n",
284 printf(" Copy file %s to %s (%u Bytes)\n", file1, file2, s1.st_size);
288 strcpy(tmpfile, file2); /* Name of temporary file */
289 strcat(tmpfile,".UPD");
291 /* open file1 for input */
292 f1 = open(file1, O_RDONLY);
294 fprintf(stderr, "Unable to open input file %s, ", file1);
295 if (errno >= sys_nerr)
296 fprintf(stderr, "error code = %d\n", errno);
298 fprintf(stderr, "%s\n", sys_errlist[errno]);
302 /* open temporary output file */
303 f2 = open(tmpfile, (O_WRONLY | O_CREAT | O_TRUNC), s1.st_mode);
305 fprintf(stderr, "Unable to open output file %s, ", tmpfile);
306 if (errno >= sys_nerr)
307 fprintf(stderr, "error code = %d\n", errno);
309 fprintf(stderr, "%s\n", sys_errlist[errno]);
315 /* Copy file1 to temporary file */
316 while ((n = read(f1, buf, sizeof(buf))) > 0) {
317 if (write(f2, buf, n) != n) {
318 fprintf(stderr,"Write failed, file %s must be copied again.\n", file2);
322 /* preserve access and modification times: ("-x" disables)*/
324 tv[0].tv_sec = s1.st_atime;
326 tv[1].tv_sec = s1.st_mtime;
331 /* Close the files */
339 /* Rename file2 to file2.old. [-r] */
340 if (renameTargets && goods2) {
341 strcpy(newName, file2);
342 strcat(newName, ".old");
344 printf(" Renaming %s to %s\n", file2, newName);
347 if (rename(file2, newName) < 0) {
348 fprintf(stderr, "Rename of %s to %s failed.\n", file2, newName);
352 /* Rename temporary file to file2 */
353 code = rename(tmpfile, file2);
355 fprintf(stderr, "Rename of %s to %s failed.\n", tmpfile, file2);
359 /* Re-stat file2 and compare file sizes */
360 code = lstat(file2, &s2);
362 fprintf(stderr, "WARNING: Unable to stat new file %s\n", file2);
365 if (s1.st_size != s2.st_size) {
366 fprintf(stderr, "WARNING: New file %s is %u bytes long; should be %u\n",
367 file2, s2.st_size, s1.st_size);
371 /* Set the user-id */
372 if (s2.st_uid != s1.st_uid) {
374 printf(" Set owner-id for %s to %d\n", file2, s1.st_uid);
377 code = chown(file2, s1.st_uid, -1);
379 fprintf(stderr, "Unable to set owner-id for %s to %d\n", file2, s1.st_uid);
382 s1.st_mode &= ~04000; /* Don't set suid bit */
386 /* Set the group-id */
387 if (s2.st_gid != s1.st_gid) {
389 printf(" Set group-id for %s to %d\n", file2, s1.st_gid);
392 code = chown(file2, -1, s1.st_gid);
394 fprintf(stderr, "Unable to set group-id for %s to %d\n", file2, s1.st_gid);
397 s1.st_mode &= ~02000; /* Don't set sgid bit */
401 /* Set the mode bits */
402 if (s1.st_mode != s2.st_mode) {
404 printf(" Set mode-bit for %s to %o\n", file2, (s1.st_mode & 07777));
407 code = chmod(file2, s1.st_mode);
409 fprintf(stderr, "Unable to set mode-bits for %s to %d\n", file2, s1.st_mode);
415 else if ((s1.st_mode & S_IFMT) == S_IFLNK) {
417 * --------------------- Copy symlink --------------------
419 char linkvalue[MAXPATHLEN+1];
423 printf("Level %d: Symbolic link %s to %s\n", level, file1, file2);
427 /* Don't ovewrite a write protected directory (unless force: -f) */
428 if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
430 "Link %s is write protected against its owner; not changed\n",
436 printf(" Copy symbolic link %s->%s to %s\n", file1, linkvalue, file2);
440 n = readlink(file1, linkvalue, sizeof(linkvalue));
442 fprintf(stderr, "Could not read symbolic link %s\n", file1);
443 perror("read link ");
448 unlink(file2); /* Always make the new link (it was easier) */
450 code = symlink(linkvalue, file2);
452 fprintf(stderr, "Could not create symbolic link %s\n", file2);
453 perror("create link ");
456 } /*Dealing with symlink*/
458 else if ( preserveMountPoints && (code=isMountPoint( file1, &blob )) ) {
460 * --------------------- Copy mount point --------------------
464 perror("checking for mount point ");
468 printf("Level %d: Mount point %s to %s\n", level, file1, file2);
472 /* Don't ovewrite a write protected directory (unless force: -f) */
473 if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
475 "Target %s is write protected against its owner; not changed\n",
481 printf(" Copy mount point %s for vol %s to %s\n", file1, blob.out, file2);
485 unlink(file2); /* Always make the new link (it was easier) */
487 strcat(blob.out, "."); /* stupid convention; these end with a period */
488 code = symlink(blob.out, file2);
490 fprintf(stderr, "Could not create mount point %s for vol %s\n", file2, blob.out);
491 perror("create mount point ");
495 } /*Dealing with mount point*/
497 else if (((s1.st_mode & S_IFMT) == S_IFDIR) && (recursive || (level == 0))) {
499 * ----------------------- Copy directory -----------------------
505 char f1[MAXPATHLEN], f2[MAXPATHLEN];
510 printf("Level %d: Directory %s to %s\n", level, file1, file2);
514 /* Don't ovewrite a write protected directory (unless force: -f) */
515 if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
517 "Directory %s is write protected against its owner; not changed\n",
524 p1 = f1 + strlen(f1);
525 p2 = f2 + strlen(f2);
526 if (p1 == f1 || p1[-1] != '/')
528 if (p2 == f2 || p2[-1] != '/')
531 dir = opendir(file1);
533 fprintf(stderr, "Couldn't open %s\n", file1);
537 while ((d = readdir(dir)) != NULL) {
538 if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0)
540 strcpy(p1, d->d_name);
541 strcpy(p2, d->d_name);
542 code = Copy(f1, f2, recursive, level + 1);
543 if (code && !rcode) rcode = 1; /* remember errors */
549 printf("Level %d: Copied directory %s to %s\n", level, file1, file2);
553 mkdir(file2, 0777); /* Handle case where MakeParent not invoked. */
556 printf(" Set owner-id for %s to %d\n", file2, s1.st_uid);
559 code = chown(file2, s1.st_uid, -1);
561 fprintf(stderr, "Unable to set owner-id for %s to %d\n", file2, s1.st_uid);
563 s1.st_mode &= ~04000; /* Don't set suid bit */
567 printf(" Set group-id for %s to %d\n", file2, s1.st_gid);
570 code = chown(file2, -1, s1.st_gid);
572 fprintf(stderr, "Unable to set group-id for %s to %d\n", file2, s1.st_gid);
574 s1.st_mode &= ~02000; /* Don't set sgid bit */
578 printf(" Set mode-bit for %s to %o\n", file2, (s1.st_mode & 07777));
581 code = chmod(file2, s1.st_mode);
583 fprintf(stderr, "Unable to set mode-bits for %s to %d\n", file2, s1.st_mode);
588 if (setacl == true) {
590 printf(" Set acls for %s\n", file2);
597 blob.out_size = MAXACL;
600 /* Get an old-style ACL and convert it */
601 for (i=1; i<strlen(file1); i++)
602 if (file1[i] == '/') break;
603 strcpy(aclspace, &file1[i]);
605 blob.in_size = 1+strlen(aclspace);
606 tfd = open(file1, O_RDONLY, 0);
608 perror("old-acl open ");
611 code = ioctl(tfd, _VICEIOCTL(4), &blob);
614 if (errno == EINVAL) {
621 /* Now convert the thing. */
622 oacl = (struct OldAcl *) (aclspace+4);
623 sprintf(tacl, "%d\n%d\n", oacl->nplus, oacl->nminus);
624 strcat(tacl, oacl->data);
625 strcpy(aclspace, tacl);
626 } /*Grab and convert old-style ACL*/
628 /* Get a new-style ACL */
629 code = pioctl(file1, _VICEIOCTL(2), &blob, 1);
631 if (errno == EINVAL) {
639 } /*Grab new-style ACL*/
642 * Now, set the new-style ACL.
644 if (setacl == true) {
648 blob.in_size = 1+strlen(aclspace);
649 code = pioctl(file2, _VICEIOCTL(1), &blob, 1);
651 if (errno == EINVAL) {
655 fprintf(stderr, "Couldn't set acls for %s\n", file2);
661 if (setacl == false) {
662 printf("Not setting acls\n");
671 int isMountPoint( name, blob )
673 struct ViceIoctl *blob;
676 char true_name[1024]; /*dirname*/
677 char parent_dir[1024]; /*Parent directory of true name*/
678 char *last_component; /*Last component of true name*/
680 sprintf(true_name, "%s%s",
681 (name[0] == '/') ? "" : "./",
685 * Find rightmost slash, if any.
687 last_component = (char *) rindex(true_name, '/');
688 if (last_component) {
690 * Found it. Designate everything before it as the parent directory,
691 * everything after it as the final component.
693 strncpy(parent_dir, true_name, last_component - true_name);
694 parent_dir[last_component - true_name] = 0;
695 last_component++; /*Skip the slash*/
699 * No slash appears in the given file name. Set parent_dir to the current
700 * directory, and the last component as the given name.
702 strcpy(parent_dir, ".");
703 last_component = true_name;
706 if (strcmp(last_component, ".") == 0 || strcmp(last_component, "..") == 0) {
707 fprintf(stderr, "up: you may not use '.' or '..' as the last component\n");
708 fprintf(stderr, "up: of a name in the 'up' command.\n");
712 blob->in = last_component;
713 blob->in_size = strlen(last_component)+1;
714 blob->out_size = MAXSIZE;
716 bzero(space, MAXSIZE);
718 code = pioctl(parent_dir, VIOC_AFS_STAT_MT_PT, blob, 0);
721 printf("'%s' is a mount point for volume '%s'\n", name, space);
726 if (errno == EINVAL) {
727 /* printf( "'%s' is not a mount point.\n", name);
733 fprintf( stderr, "problem examining '%s' in '%s'.\n", last_component, parent_dir );
735 /* Die(errno, (ti->data ? ti->data : parent_dir));