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>
15 #include <afs/afs_args.h>
21 #include <afs/venus.h>
22 #include <afs/sys_prototypes.h>
23 #include <afs/afsutil.h>
24 #include <afs/afs_consts.h>
26 /* ************************************************************* */
28 #define MAXACL AFS_PIOCTL_MAXSIZE
31 short renameTargets
= 0;
33 short preserveDate
= 1;
34 short preserveMountPoints
= 0;
35 short forceOverwrite
= 0;
39 char file1
[MAXPATHLEN
], file2
[MAXPATHLEN
];
41 static char space
[AFS_PIOCTL_MAXSIZE
];
50 static void ScanArgs(int argc
, char *argv
[]);
51 static short MakeParent(char *file
, afs_int32 owner
);
52 static int Copy(char *file1
, char *file2
, short recursive
, int level
);
53 static int isMountPoint(char *name
, struct ViceIoctl
*blob
);
56 /* ************************************************************ */
60 /* ************************************************************ */
62 #include "AFS_component_version_number.c"
65 main(int argc
, char *argv
[])
69 * The following signal action for AIX is necessary so that in case of a
70 * crash (i.e. core is generated) we can include the user's data section
71 * in the core dump. Unfortunately, by default, only a partial core is
72 * generated which, in many cases, isn't too useful.
76 sigemptyset(&nsa
.sa_mask
);
77 nsa
.sa_handler
= SIG_DFL
;
78 nsa
.sa_flags
= SA_FULLDUMP
;
79 sigaction(SIGSEGV
, &nsa
, NULL
);
83 /* now read each line of the CopyList */
84 if (Copy(file1
, file2
, !oneLevel
, 0))
85 return(1); /* some type of failure */
91 #define USAGE "usage: up [-v1frxm] from to\n"
93 ScanArgs(int argc
, char *argv
[])
95 /* skip program name */
98 /* check for -flag options */
99 while (argc
> 0 && *argv
[0] == '-') {
102 if (strlen(cp
) > 2) {
128 preserveMountPoints
= 1;
135 fprintf(stderr
, "Unknown option: '%s'\n", cp
);
136 fprintf(stderr
, USAGE
);
143 fprintf(stderr
, USAGE
);
147 strncpy(file1
, argv
[0], MAXPATHLEN
);
148 strncpy(file2
, argv
[1], MAXPATHLEN
);
156 * Make sure the parent directory of this file exists. Returns
157 * 1 if it exists, 0 otherwise. Note: the owner argument
158 * is a hack. All directories made will have this owner.
161 MakeParent(char *file
, afs_int32 owner
)
163 char parent
[MAXPATHLEN
];
167 strlcpy(parent
, file
, sizeof parent
);
169 p
= strrchr(parent
, '/');
171 strlcpy(parent
, ".", sizeof parent
);
172 } else if (p
> parent
) {
178 if (stat(parent
, &s
) < 0) {
179 if (!MakeParent(parent
, owner
))
183 printf("Creating directory %s\n", parent
);
187 if (mkdir(parent
, 0777))
189 if (chown(parent
, owner
, -1))
198 * This does the bulk of the work of the program. Handle one file,
199 * possibly copying subfiles if this is a directory
202 Copy(char *file1
, char *file2
, short recursive
, int level
)
204 struct stat s1
, s2
; /*Stat blocks */
205 struct ViceIoctl blob
;
206 char aclspace
[MAXACL
];
207 afs_int32 rcode
= 0, code
;
210 code
= lstat(file1
, &s1
);
212 fprintf(stderr
, "Can't find %s\n", file1
);
216 code
= lstat(file2
, &s2
);
218 if (!MakeParent(file2
, s1
.st_uid
))
223 if ((s1
.st_mode
& S_IFMT
) == S_IFREG
) {
225 * -------------------- Copy regular file --------------------
228 char buf
[4096]; /* Must be bigger than sizeof (*head) */
229 struct timeval tv
[2];
230 char tmpfile
[MAXPATHLEN
], newName
[MAXPATHLEN
];
233 printf("Level %d: File %s to %s\n", level
, file1
, file2
);
237 /* Wonder if there is a security hole */
238 if (((s1
.st_mode
& 04002) == 04002) || ((s1
.st_mode
& 04020) == 04020)
239 || ((s1
.st_mode
& 02002) == 02002)) {
241 "WARNING: Mode-bits security hole in files %s and %s\n",
245 if (!goods2
|| (s1
.st_mtime
!= s2
.st_mtime
) || (s1
.st_size
!= s2
.st_size
)) { /*c */
246 /* Don't ovewrite a write protected file (unless force: -f) */
247 if (!forceOverwrite
&& goods2
&& (s2
.st_mode
& 0200) == 0) {
249 "File %s is write protected against its owner; not changed\n",
255 printf(" Copy file %s to %s (%u Bytes)\n", file1
, file2
,
256 (unsigned int) s1
.st_size
);
260 strlcpy(tmpfile
, file2
, sizeof tmpfile
); /* Name of temporary file */
261 strlcat(tmpfile
, ".UPD", sizeof tmpfile
);
263 /* open file1 for input */
264 f1
= open(file1
, O_RDONLY
);
266 fprintf(stderr
, "Unable to open input file %s: %s\n",
267 file1
, strerror(errno
));
271 /* open temporary output file */
272 f2
= open(tmpfile
, (O_WRONLY
| O_CREAT
| O_TRUNC
), s1
.st_mode
);
274 fprintf(stderr
, "Unable to open output file %s: %s\n",
275 tmpfile
, strerror(errno
));
281 /* Copy file1 to temporary file */
282 while ((n
= read(f1
, buf
, sizeof(buf
))) > 0) {
283 if (write(f2
, buf
, n
) != n
) {
285 "Write failed, file %s must be copied again.\n",
290 /* preserve access and modification times: ("-x" disables) */
292 tv
[0].tv_sec
= s1
.st_atime
;
294 tv
[1].tv_sec
= s1
.st_mtime
;
299 /* Close the files */
311 /* Rename file2 to file2.old. [-r] */
312 if (renameTargets
&& goods2
) {
313 strlcpy(newName
, file2
, sizeof newName
);
314 strlcat(newName
, ".old", sizeof newName
);
316 printf(" Renaming %s to %s\n", file2
, newName
);
319 if (rename(file2
, newName
) < 0) {
320 fprintf(stderr
, "Rename of %s to %s failed.\n", file2
,
325 /* Rename temporary file to file2 */
326 code
= rename(tmpfile
, file2
);
328 fprintf(stderr
, "Rename of %s to %s failed.\n", tmpfile
,
333 /* Re-stat file2 and compare file sizes */
334 code
= lstat(file2
, &s2
);
336 fprintf(stderr
, "WARNING: Unable to stat new file %s\n",
340 if (s1
.st_size
!= s2
.st_size
) {
342 "WARNING: New file %s is %u bytes long; should be %u\n",
343 file2
, (unsigned int) s2
.st_size
,
344 (unsigned int) s1
.st_size
);
349 /* Set the user-id */
350 if (s2
.st_uid
!= s1
.st_uid
) {
352 printf(" Set owner-id for %s to %d\n", file2
, s1
.st_uid
);
355 code
= chown(file2
, s1
.st_uid
, -1);
357 fprintf(stderr
, "Unable to set owner-id for %s to %d\n",
361 s1
.st_mode
&= ~04000; /* Don't set suid bit */
365 /* Set the group-id */
366 if (s2
.st_gid
!= s1
.st_gid
) {
368 printf(" Set group-id for %s to %d\n", file2
, s1
.st_gid
);
371 code
= chown(file2
, -1, s1
.st_gid
);
373 fprintf(stderr
, "Unable to set group-id for %s to %d\n",
377 s1
.st_mode
&= ~02000; /* Don't set sgid bit */
381 /* Set the mode bits */
382 if (s1
.st_mode
!= s2
.st_mode
) {
384 printf(" Set mode-bit for %s to %o\n", file2
,
385 (s1
.st_mode
& 07777));
388 code
= chmod(file2
, s1
.st_mode
);
390 fprintf(stderr
, "Unable to set mode-bits for %s to %d\n",
397 else if ((s1
.st_mode
& S_IFMT
) == S_IFLNK
) {
399 * --------------------- Copy symlink --------------------
401 char linkvalue
[MAXPATHLEN
+ 1];
405 printf("Level %d: Symbolic link %s to %s\n", level
, file1
, file2
);
409 /* Don't ovewrite a write protected directory (unless force: -f) */
410 if (!forceOverwrite
&& goods2
&& (s2
.st_mode
& 0200) == 0) {
412 "Link %s is write protected against its owner; not changed\n",
418 printf(" Copy symbolic link %s->%s to %s\n", file1
, linkvalue
,
423 n
= readlink(file1
, linkvalue
, sizeof(linkvalue
)-1);
425 fprintf(stderr
, "Could not read symbolic link %s\n", file1
);
426 perror("read link ");
431 unlink(file2
); /* Always make the new link (it was easier) */
433 code
= symlink(linkvalue
, file2
);
435 fprintf(stderr
, "Could not create symbolic link %s\n", file2
);
436 perror("create link ");
440 /*Dealing with symlink */
441 else if (preserveMountPoints
&& (code
= isMountPoint(file1
, &blob
))) {
443 * --------------------- Copy mount point --------------------
447 perror("checking for mount point ");
451 printf("Level %d: Mount point %s to %s\n", level
, file1
, file2
);
455 /* Don't ovewrite a write protected directory (unless force: -f) */
456 if (!forceOverwrite
&& goods2
&& (s2
.st_mode
& 0200) == 0) {
458 "Target %s is write protected against its owner; not changed\n",
464 printf(" Copy mount point %s for vol %s to %s\n", file1
,
469 unlink(file2
); /* Always make the new link (it was easier) */
471 strcat(blob
.out
, "."); /* stupid convention; these end with a period */
472 code
= symlink(blob
.out
, file2
);
474 fprintf(stderr
, "Could not create mount point %s for vol %s\n",
476 perror("create mount point ");
481 /*Dealing with mount point */
482 else if (((s1
.st_mode
& S_IFMT
) == S_IFDIR
)
483 && (recursive
|| (level
== 0))) {
485 * ----------------------- Copy directory -----------------------
491 char f1
[MAXPATHLEN
], f2
[MAXPATHLEN
];
494 struct timeval tv
[2];
497 printf("Level %d: Directory %s to %s\n", level
, file1
, file2
);
501 /* Don't ovewrite a write protected directory (unless force: -f) */
502 if (!forceOverwrite
&& goods2
&& (s2
.st_mode
& 0200) == 0) {
504 "Directory %s is write protected against its owner; not changed\n",
509 strlcpy(f1
, file1
, sizeof f1
);
510 strlcpy(f2
, file2
, sizeof f2
);
511 p1
= f1
+ strlen(f1
);
512 p2
= f2
+ strlen(f2
);
513 if (p1
== f1
|| p1
[-1] != '/')
515 if (p2
== f2
|| p2
[-1] != '/')
518 dir
= opendir(file1
);
520 fprintf(stderr
, "Couldn't open %s\n", file1
);
524 while ((d
= readdir(dir
)) != NULL
) {
525 if (strcmp(d
->d_name
, ".") == 0 || strcmp(d
->d_name
, "..") == 0)
527 strlcpy(p1
, d
->d_name
, sizeof f1
- (p1
- f1
));
528 strlcpy(p2
, d
->d_name
, sizeof f2
- (p2
- f2
));
529 code
= Copy(f1
, f2
, recursive
, level
+ 1);
531 rcode
= 1; /* remember errors */
537 printf("Level %d: Copied directory %s to %s\n", level
, file1
,
542 mkdir(file2
, 0777); /* Handle case where MakeParent not invoked. */
545 printf(" Set owner-id for %s to %d\n", file2
, s1
.st_uid
);
548 code
= chown(file2
, s1
.st_uid
, -1);
550 fprintf(stderr
, "Unable to set owner-id for %s to %d\n", file2
,
553 s1
.st_mode
&= ~04000; /* Don't set suid bit */
557 printf(" Set group-id for %s to %d\n", file2
, s1
.st_gid
);
560 code
= chown(file2
, -1, s1
.st_gid
);
562 fprintf(stderr
, "Unable to set group-id for %s to %d\n", file2
,
565 s1
.st_mode
&= ~02000; /* Don't set sgid bit */
569 printf(" Set mode-bit for %s to %o\n", file2
,
570 (s1
.st_mode
& 07777));
573 code
= chmod(file2
, s1
.st_mode
);
575 fprintf(stderr
, "Unable to set mode-bits for %s to %d\n", file2
,
583 printf(" Set acls for %s\n", file2
);
590 blob
.out_size
= MAXACL
;
593 /* Get an old-style ACL and convert it */
595 printf(" Getting old style acl\n");
599 for (i
= 1; i
< strlen(file1
); i
++)
602 strlcpy(aclspace
, &file1
[i
], sizeof aclspace
);
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
) {
616 printf(" _VICEIOCTL(4) returns EINVAL\n");
623 /* Now convert the thing. */
624 oacl
= (struct OldAcl
*)(aclspace
+ 4);
625 sprintf(tacl
, "%d\n%d\n", oacl
->nplus
, oacl
->nminus
);
626 strlcat(tacl
, oacl
->data
, sizeof tacl
);
627 strlcpy(aclspace
, tacl
, sizeof aclspace
);
628 } /*Grab and convert old-style ACL */
630 /* Get a new-style ACL */
632 printf(" Getting new style acl\n");
636 code
= pioctl(file1
, _VICEIOCTL(2), &blob
, 1);
638 if (errno
== EINVAL
) {
641 printf(" _VICEIOCTL(2) returns EINVAL\n");
649 } /*Grab new-style ACL */
652 * Now, set the new-style ACL.
656 printf(" Setting new style acl\n");
662 blob
.in_size
= 1 + strlen(aclspace
);
663 code
= pioctl(file2
, _VICEIOCTL(1), &blob
, 1);
665 if (errno
== EINVAL
) {
668 printf(" _VICEIOCTL(1) returns EINVAL\n");
672 fprintf(stderr
, "Couldn't set acls for %s\n", file2
);
679 printf("Not setting acls\n");
683 /* preserve access and modification times: ("-x" disables) */
685 tv
[0].tv_sec
= s1
.st_atime
;
687 tv
[1].tv_sec
= s1
.st_mtime
;
698 isMountPoint(char *name
, struct ViceIoctl
*blob
)
701 char true_name
[1024]; /*dirname */
702 char parent_dir
[1024]; /*Parent directory of true name */
703 char *last_component
; /*Last component of true name */
705 sprintf(true_name
, "%s%s", (name
[0] == '/') ? "" : "./", name
);
708 * Find rightmost slash, if any.
710 last_component
= (char *)strrchr(true_name
, '/');
711 if (last_component
) {
713 * Found it. Designate everything before it as the parent directory,
714 * everything after it as the final component.
716 strncpy(parent_dir
, true_name
, last_component
- true_name
);
717 parent_dir
[last_component
- true_name
] = 0;
718 last_component
++; /*Skip the slash */
721 * No slash appears in the given file name. Set parent_dir to the current
722 * directory, and the last component as the given name.
724 strlcpy(parent_dir
, ".", sizeof parent_dir
);
725 last_component
= true_name
;
728 if (strcmp(last_component
, ".") == 0 || strcmp(last_component
, "..") == 0) {
730 "up: you may not use '.' or '..' as the last component\n");
731 fprintf(stderr
, "up: of a name in the 'up' command.\n");
735 blob
->in
= last_component
;
736 blob
->in_size
= strlen(last_component
) + 1;
737 blob
->out_size
= AFS_PIOCTL_MAXSIZE
;
739 memset(space
, 0, AFS_PIOCTL_MAXSIZE
);
741 code
= pioctl(parent_dir
, VIOC_AFS_STAT_MT_PT
, blob
, 0);
744 printf("'%s' is a mount point for volume '%s'\n", name
, space
);
748 if (errno
== EINVAL
) {
749 /* printf( "'%s' is not a mount point.\n", name);
754 fprintf(stderr
, "problem examining '%s' in '%s'.\n",
755 last_component
, parent_dir
);
757 /* Die(errno, (ti->data ? ti->data : parent_dir));