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 /* missing type from C language */
15 /* ************************************************************* */
17 #include <afs/param.h>
18 #include <afsconfig.h>
25 #include <afs/afs_args.h>
26 #include <sys/param.h>
36 #include <sys/ioctl.h>
40 #include <sys/ioctl.h>
42 #ifdef HAVE_NETINET_IN_H
43 #include <netinet/in.h>
45 #include <afs/venus.h>
47 /* ************************************************************* */
51 extern char *index ();
52 extern char *rindex ();
53 #if !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
55 extern char *sys_errlist[];
58 Boolean verbose = false;
59 Boolean renameTargets = false;
60 Boolean oneLevel = false;
61 Boolean preserveDate = true;
62 Boolean preserveMountPoints = false;
63 Boolean forceOverwrite = false;
66 Boolean setacl = true;
67 Boolean oldAcl = false;
68 char file1[MAXPATHLEN], file2[MAXPATHLEN];
71 static char space[MAXSIZE];
80 /* ************************************************************ */
84 /* ************************************************************ */
86 #include "AFS_component_version_number.c"
95 * The following signal action for AIX is necessary so that in case of a
96 * crash (i.e. core is generated) we can include the user's data section
97 * in the core dump. Unfortunately, by default, only a partial core is
98 * generated which, in many cases, isn't too useful.
100 struct sigaction nsa;
102 sigemptyset(&nsa.sa_mask);
103 nsa.sa_handler = SIG_DFL;
104 nsa.sa_flags = SA_FULLDUMP;
105 sigaction(SIGSEGV, &nsa, NULL);
107 #if !defined (AFS_AIX_ENV) && !defined (AFS_HPUX_ENV)
108 pageSize = getpagesize();
110 ScanArgs(argc, argv);
112 /* now read each line of the CopyList */
113 if (Copy(file1, file2, !oneLevel, 0))
114 exit(1); /* some type of failure */
125 /* skip program name */
128 /* check for -flag options */
129 while (argc > 0 && *argv[0] == '-') {
142 renameTargets = true;
146 forceOverwrite = true;
150 preserveDate = false;
154 preserveMountPoints = true;
158 fprintf(stderr, "Unknown option: '%c'\n", *cp);
159 fprintf(stderr, "usage: up [-v1frxm] from to\n");
166 fprintf(stderr, "usage: up [-v1frx] from to\n");
170 strncpy(file1, argv[0], MAXPATHLEN);
171 strncpy(file2, argv[1], MAXPATHLEN);
179 * Make sure the parent directory of this file exists. Returns
180 * true if it exists, false otherwise. Note: the owner argument
181 * is a hack. All directories made will have this owner.
183 Boolean MakeParent(file, owner)
187 char parent[MAXPATHLEN];
191 strcpy(parent, file);
193 p = rindex(parent, '/');
197 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
225 Copy(file1, file2, recursive, level)
226 char *file1; /* input file name */
227 char *file2; /* output file name */
228 Boolean recursive; /* true if directory should be copied */
229 int level; /* level of recursion: 0, 1, ... */
232 struct stat s1, s2; /*Stat blocks*/
233 struct ViceIoctl blob;
234 char aclspace[MAXACL];
235 afs_int32 rcode = 0, code;
238 code = lstat(file1, &s1);
240 fprintf(stderr,"Can't find %s\n",file1);
244 code = lstat(file2, &s2);
246 if (!MakeParent(file2,s1.st_uid))
251 if ((s1.st_mode & S_IFMT) == S_IFREG) {
253 * -------------------- Copy regular file --------------------
256 char buf[4096]; /* Must be bigger than sizeof (*head) */
257 struct timeval tv[2];
258 char tmpfile[MAXPATHLEN], newName[MAXPATHLEN];
261 printf("Level %d: File %s to %s\n", level, file1, file2);
265 /* Wonder if there is a security hole */
266 if ( ((s1.st_mode & 04002) == 04002) ||
267 ((s1.st_mode & 04020) == 04020) ||
268 ((s1.st_mode & 02002) == 02002) ) {
269 fprintf(stderr, "WARNING: Mode-bits security hole in files %s and %s\n",
273 if (!goods2 || (s1.st_mtime != s2.st_mtime) || (s1.st_size != s2.st_size)) { /*c*/
274 /* Don't ovewrite a write protected file (unless force: -f) */
275 if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
277 "File %s is write protected against its owner; not changed\n",
283 printf(" Copy file %s to %s (%u Bytes)\n", file1, file2, s1.st_size);
287 strcpy(tmpfile, file2); /* Name of temporary file */
288 strcat(tmpfile,".UPD");
290 /* open file1 for input */
291 f1 = open(file1, O_RDONLY);
293 fprintf(stderr, "Unable to open input file %s, ", file1);
294 if (errno >= sys_nerr)
295 fprintf(stderr, "error code = %d\n", errno);
297 fprintf(stderr, "%s\n", sys_errlist[errno]);
301 /* open temporary output file */
302 f2 = open(tmpfile, (O_WRONLY | O_CREAT | O_TRUNC), s1.st_mode);
304 fprintf(stderr, "Unable to open output file %s, ", tmpfile);
305 if (errno >= sys_nerr)
306 fprintf(stderr, "error code = %d\n", errno);
308 fprintf(stderr, "%s\n", sys_errlist[errno]);
314 /* Copy file1 to temporary file */
315 while ((n = read(f1, buf, sizeof(buf))) > 0) {
316 if (write(f2, buf, n) != n) {
317 fprintf(stderr,"Write failed, file %s must be copied again.\n", file2);
321 /* preserve access and modification times: ("-x" disables)*/
323 tv[0].tv_sec = s1.st_atime;
325 tv[1].tv_sec = s1.st_mtime;
330 /* Close the files */
338 /* Rename file2 to file2.old. [-r] */
339 if (renameTargets && goods2) {
340 strcpy(newName, file2);
341 strcat(newName, ".old");
343 printf(" Renaming %s to %s\n", file2, newName);
346 if (rename(file2, newName) < 0) {
347 fprintf(stderr, "Rename of %s to %s failed.\n", file2, newName);
351 /* Rename temporary file to file2 */
352 code = rename(tmpfile, file2);
354 fprintf(stderr, "Rename of %s to %s failed.\n", tmpfile, file2);
358 /* Re-stat file2 and compare file sizes */
359 code = lstat(file2, &s2);
361 fprintf(stderr, "WARNING: Unable to stat new file %s\n", file2);
364 if (s1.st_size != s2.st_size) {
365 fprintf(stderr, "WARNING: New file %s is %u bytes long; should be %u\n",
366 file2, s2.st_size, s1.st_size);
370 /* Set the user-id */
371 if (s2.st_uid != s1.st_uid) {
373 printf(" Set owner-id for %s to %d\n", file2, s1.st_uid);
376 code = chown(file2, s1.st_uid, -1);
378 fprintf(stderr, "Unable to set owner-id for %s to %d\n", file2, s1.st_uid);
381 s1.st_mode &= ~04000; /* Don't set suid bit */
385 /* Set the group-id */
386 if (s2.st_gid != s1.st_gid) {
388 printf(" Set group-id for %s to %d\n", file2, s1.st_gid);
391 code = chown(file2, -1, s1.st_gid);
393 fprintf(stderr, "Unable to set group-id for %s to %d\n", file2, s1.st_gid);
396 s1.st_mode &= ~02000; /* Don't set sgid bit */
400 /* Set the mode bits */
401 if (s1.st_mode != s2.st_mode) {
403 printf(" Set mode-bit for %s to %o\n", file2, (s1.st_mode & 07777));
406 code = chmod(file2, s1.st_mode);
408 fprintf(stderr, "Unable to set mode-bits for %s to %d\n", file2, s1.st_mode);
414 else if ((s1.st_mode & S_IFMT) == S_IFLNK) {
416 * --------------------- Copy symlink --------------------
418 char linkvalue[MAXPATHLEN+1];
422 printf("Level %d: Symbolic link %s to %s\n", level, file1, file2);
426 /* Don't ovewrite a write protected directory (unless force: -f) */
427 if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
429 "Link %s is write protected against its owner; not changed\n",
435 printf(" Copy symbolic link %s->%s to %s\n", file1, linkvalue, file2);
439 n = readlink(file1, linkvalue, sizeof(linkvalue));
441 fprintf(stderr, "Could not read symbolic link %s\n", file1);
442 perror("read link ");
447 unlink(file2); /* Always make the new link (it was easier) */
449 code = symlink(linkvalue, file2);
451 fprintf(stderr, "Could not create symbolic link %s\n", file2);
452 perror("create link ");
455 } /*Dealing with symlink*/
457 else if ( preserveMountPoints && (code=isMountPoint( file1, &blob )) ) {
459 * --------------------- Copy mount point --------------------
463 perror("checking for mount point ");
467 printf("Level %d: Mount point %s to %s\n", level, file1, file2);
471 /* Don't ovewrite a write protected directory (unless force: -f) */
472 if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
474 "Target %s is write protected against its owner; not changed\n",
480 printf(" Copy mount point %s for vol %s to %s\n", file1, blob.out, file2);
484 unlink(file2); /* Always make the new link (it was easier) */
486 strcat(blob.out, "."); /* stupid convention; these end with a period */
487 code = symlink(blob.out, file2);
489 fprintf(stderr, "Could not create mount point %s for vol %s\n", file2, blob.out);
490 perror("create mount point ");
494 } /*Dealing with mount point*/
496 else if (((s1.st_mode & S_IFMT) == S_IFDIR) && (recursive || (level == 0))) {
498 * ----------------------- Copy directory -----------------------
504 char f1[MAXPATHLEN], f2[MAXPATHLEN];
509 printf("Level %d: Directory %s to %s\n", level, file1, file2);
513 /* Don't ovewrite a write protected directory (unless force: -f) */
514 if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
516 "Directory %s is write protected against its owner; not changed\n",
523 p1 = f1 + strlen(f1);
524 p2 = f2 + strlen(f2);
525 if (p1 == f1 || p1[-1] != '/')
527 if (p2 == f2 || p2[-1] != '/')
530 dir = opendir(file1);
532 fprintf(stderr, "Couldn't open %s\n", file1);
536 while ((d = readdir(dir)) != NULL) {
537 if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0)
539 strcpy(p1, d->d_name);
540 strcpy(p2, d->d_name);
541 code = Copy(f1, f2, recursive, level + 1);
542 if (code && !rcode) rcode = 1; /* remember errors */
548 printf("Level %d: Copied directory %s to %s\n", level, file1, file2);
552 mkdir(file2, 0777); /* Handle case where MakeParent not invoked. */
555 printf(" Set owner-id for %s to %d\n", file2, s1.st_uid);
558 code = chown(file2, s1.st_uid, -1);
560 fprintf(stderr, "Unable to set owner-id for %s to %d\n", file2, s1.st_uid);
562 s1.st_mode &= ~04000; /* Don't set suid bit */
566 printf(" Set group-id for %s to %d\n", file2, s1.st_gid);
569 code = chown(file2, -1, s1.st_gid);
571 fprintf(stderr, "Unable to set group-id for %s to %d\n", file2, s1.st_gid);
573 s1.st_mode &= ~02000; /* Don't set sgid bit */
577 printf(" Set mode-bit for %s to %o\n", file2, (s1.st_mode & 07777));
580 code = chmod(file2, s1.st_mode);
582 fprintf(stderr, "Unable to set mode-bits for %s to %d\n", file2, s1.st_mode);
587 if (setacl == true) {
589 printf(" Set acls for %s\n", file2);
596 blob.out_size = MAXACL;
599 /* Get an old-style ACL and convert it */
600 for (i=1; i<strlen(file1); i++)
601 if (file1[i] == '/') break;
602 strcpy(aclspace, &file1[i]);
604 blob.in_size = 1+strlen(aclspace);
605 tfd = open(file1, O_RDONLY, 0);
607 perror("old-acl open ");
610 code = ioctl(tfd, _VICEIOCTL(4), &blob);
613 if (errno == EINVAL) {
620 /* Now convert the thing. */
621 oacl = (struct OldAcl *) (aclspace+4);
622 sprintf(tacl, "%d\n%d\n", oacl->nplus, oacl->nminus);
623 strcat(tacl, oacl->data);
624 strcpy(aclspace, tacl);
625 } /*Grab and convert old-style ACL*/
627 /* Get a new-style ACL */
628 code = pioctl(file1, _VICEIOCTL(2), &blob, 1);
630 if (errno == EINVAL) {
638 } /*Grab new-style ACL*/
641 * Now, set the new-style ACL.
643 if (setacl == true) {
647 blob.in_size = 1+strlen(aclspace);
648 code = pioctl(file2, _VICEIOCTL(1), &blob, 1);
650 if (errno == EINVAL) {
654 fprintf(stderr, "Couldn't set acls for %s\n", file2);
660 if (setacl == false) {
661 printf("Not setting acls\n");
670 int isMountPoint( name, blob )
672 struct ViceIoctl *blob;
675 char true_name[1024]; /*dirname*/
676 char parent_dir[1024]; /*Parent directory of true name*/
677 char *last_component; /*Last component of true name*/
679 sprintf(true_name, "%s%s",
680 (name[0] == '/') ? "" : "./",
684 * Find rightmost slash, if any.
686 last_component = (char *) rindex(true_name, '/');
687 if (last_component) {
689 * Found it. Designate everything before it as the parent directory,
690 * everything after it as the final component.
692 strncpy(parent_dir, true_name, last_component - true_name);
693 parent_dir[last_component - true_name] = 0;
694 last_component++; /*Skip the slash*/
698 * No slash appears in the given file name. Set parent_dir to the current
699 * directory, and the last component as the given name.
701 strcpy(parent_dir, ".");
702 last_component = true_name;
705 if (strcmp(last_component, ".") == 0 || strcmp(last_component, "..") == 0) {
706 fprintf(stderr, "up: you may not use '.' or '..' as the last component\n");
707 fprintf(stderr, "up: of a name in the 'up' command.\n");
711 blob->in = last_component;
712 blob->in_size = strlen(last_component)+1;
713 blob->out_size = MAXSIZE;
715 bzero(space, MAXSIZE);
717 code = pioctl(parent_dir, VIOC_AFS_STAT_MT_PT, blob, 0);
720 printf("'%s' is a mount point for volume '%s'\n", name, space);
725 if (errno == EINVAL) {
726 /* printf( "'%s' is not a mount point.\n", name);
732 fprintf( stderr, "problem examining '%s' in '%s'.\n", last_component, parent_dir );
734 /* Die(errno, (ti->data ? ti->data : parent_dir));