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>
24 #include <sys/param.h>
34 #include <sys/ioctl.h>
39 /* ************************************************************* */
43 extern char *index ();
44 extern char *rindex ();
45 #ifndef AFS_LINUX20_ENV
47 extern char *sys_errlist[];
50 Boolean verbose = false;
51 Boolean renameTargets = false;
52 Boolean oneLevel = false;
53 Boolean preserveDate = true;
54 Boolean forceOverwrite = false;
57 Boolean setacl = true;
58 Boolean oldAcl = false;
59 char file1[MAXPATHLEN], file2[MAXPATHLEN];
68 /* ************************************************************ */
72 /* ************************************************************ */
74 #include "AFS_component_version_number.c"
83 * The following signal action for AIX is necessary so that in case of a
84 * crash (i.e. core is generated) we can include the user's data section
85 * in the core dump. Unfortunately, by default, only a partial core is
86 * generated which, in many cases, isn't too useful.
90 sigemptyset(&nsa.sa_mask);
91 nsa.sa_handler = SIG_DFL;
92 nsa.sa_flags = SA_FULLDUMP;
93 sigaction(SIGSEGV, &nsa, NULL);
95 #if !defined (AFS_AIX_ENV) && !defined (AFS_HPUX_ENV)
96 pageSize = getpagesize();
100 /* now read each line of the CopyList */
101 if (Copy(file1, file2, !oneLevel, 0))
102 exit(1); /* some type of failure */
113 /* skip program name */
116 /* check for -flag options */
117 while (argc > 0 && *argv[0] == '-') {
130 renameTargets = true;
134 forceOverwrite = true;
138 preserveDate = false;
142 fprintf(stderr, "Unknown option: '%c'\n", *cp);
143 fprintf(stderr, "usage: up [-v1frx] from to\n");
150 fprintf(stderr, "usage: up [-v1frx] from to\n");
154 strcpy(file1, argv[0]);
155 strcpy(file2, argv[1]);
163 * Make sure the parent directory of this file exists. Returns
164 * true if it exists, false otherwise. Note: the owner argument
165 * is a hack. All directories made will have this owner.
167 Boolean MakeParent(file, owner)
171 char parent[MAXPATHLEN];
175 strcpy(parent, file);
177 p = rindex(parent, '/');
181 else if (p > parent) {
188 if (stat(parent, &s) < 0) {
189 if (!MakeParent(parent, owner))
193 printf("Creating directory %s\n", parent);
198 chown(parent, owner, -1);
206 * This does the bulk of the work of the program. Handle one file,
207 * possibly copying subfiles if this is a directory
209 Copy(file1, file2, recursive, level)
210 char *file1; /* input file name */
211 char *file2; /* output file name */
212 Boolean recursive; /* true if directory should be copied */
213 int level; /* level of recursion: 0, 1, ... */
216 struct stat s1, s2; /*Stat blocks*/
217 struct ViceIoctl blob;
218 char aclspace[MAXACL];
219 afs_int32 rcode = 0, code;
222 code = lstat(file1, &s1);
224 fprintf(stderr,"Can't find %s\n",file1);
228 code = lstat(file2, &s2);
230 if (!MakeParent(file2,s1.st_uid))
235 if ((s1.st_mode & S_IFMT) == S_IFREG) {
237 * -------------------- Copy regular file --------------------
240 char buf[4096]; /* Must be bigger than sizeof (*head) */
241 struct timeval tv[2];
242 char tmpfile[MAXPATHLEN], newName[MAXPATHLEN];
245 printf("Level %d: File %s to %s\n", level, file1, file2);
249 /* Wonder if there is a security hole */
250 if ( ((s1.st_mode & 04002) == 04002) ||
251 ((s1.st_mode & 04020) == 04020) ||
252 ((s1.st_mode & 02002) == 02002) ) {
253 fprintf(stderr, "WARNING: Mode-bits security hole in files %s and %s\n",
257 if (!goods2 || (s1.st_mtime != s2.st_mtime) || (s1.st_size != s2.st_size)) { /*c*/
258 /* Don't ovewrite a write protected file (unless force: -f) */
259 if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
261 "File %s is write protected against its owner; not changed\n",
267 printf(" Copy file %s to %s (%u Bytes)\n", file1, file2, s1.st_size);
271 strcpy(tmpfile, file2); /* Name of temporary file */
272 strcat(tmpfile,".UPD");
274 /* open file1 for input */
275 f1 = open(file1, O_RDONLY);
277 fprintf(stderr, "Unable to open input file %s, ", file1);
278 if (errno >= sys_nerr)
279 fprintf(stderr, "error code = %d\n", errno);
281 fprintf(stderr, "%s\n", sys_errlist[errno]);
285 /* open temporary output file */
286 f2 = open(tmpfile, (O_WRONLY | O_CREAT | O_TRUNC), s1.st_mode);
288 fprintf(stderr, "Unable to open output file %s, ", tmpfile);
289 if (errno >= sys_nerr)
290 fprintf(stderr, "error code = %d\n", errno);
292 fprintf(stderr, "%s\n", sys_errlist[errno]);
298 /* Copy file1 to temporary file */
299 while ((n = read(f1, buf, sizeof(buf))) > 0) {
300 if (write(f2, buf, n) != n) {
301 fprintf(stderr,"Write failed, file %s must be copied again.\n", file2);
305 /* preserve access and modification times: ("-x" disables)*/
307 tv[0].tv_sec = s1.st_atime;
309 tv[1].tv_sec = s1.st_mtime;
314 /* Close the files */
322 /* Rename file2 to file2.old. [-r] */
323 if (renameTargets && goods2) {
324 strcpy(newName, file2);
325 strcat(newName, ".old");
327 printf(" Renaming %s to %s\n", file2, newName);
330 if (rename(file2, newName) < 0) {
331 fprintf(stderr, "Rename of %s to %s failed.\n", file2, newName);
335 /* Rename temporary file to file2 */
336 code = rename(tmpfile, file2);
338 fprintf(stderr, "Rename of %s to %s failed.\n", tmpfile, file2);
342 /* Re-stat file2 and compare file sizes */
343 code = lstat(file2, &s2);
345 fprintf(stderr, "WARNING: Unable to stat new file %s\n", file2);
348 if (s1.st_size != s2.st_size) {
349 fprintf(stderr, "WARNING: New file %s is %u bytes long; should be %u\n",
350 file2, s2.st_size, s1.st_size);
354 /* Set the user-id */
355 if (s2.st_uid != s1.st_uid) {
357 printf(" Set owner-id for %s to %d\n", file2, s1.st_uid);
360 code = chown(file2, s1.st_uid, -1);
362 fprintf(stderr, "Unable to set owner-id for %s to %d\n", file2, s1.st_uid);
365 s1.st_mode &= ~04000; /* Don't set suid bit */
369 /* Set the group-id */
370 if (s2.st_gid != s1.st_gid) {
372 printf(" Set group-id for %s to %d\n", file2, s1.st_gid);
375 code = chown(file2, -1, s1.st_gid);
377 fprintf(stderr, "Unable to set group-id for %s to %d\n", file2, s1.st_gid);
380 s1.st_mode &= ~02000; /* Don't set sgid bit */
384 /* Set the mode bits */
385 if (s1.st_mode != s2.st_mode) {
387 printf(" Set mode-bit for %s to %o\n", file2, (s1.st_mode & 07777));
390 code = chmod(file2, s1.st_mode);
392 fprintf(stderr, "Unable to set mode-bits for %s to %d\n", file2, s1.st_mode);
398 else if ((s1.st_mode & S_IFMT) == S_IFLNK) {
400 * --------------------- Copy symlink --------------------
402 char linkvalue[MAXPATHLEN+1];
406 printf("Level %d: Symbolic link %s to %s\n", level, file1, file2);
410 /* Don't ovewrite a write protected directory (unless force: -f) */
411 if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
413 "Link %s is write protected against its owner; not changed\n",
419 printf(" Copy symbolic link %s->%s to %s\n", file1, linkvalue, file2);
423 n = readlink(file1, linkvalue, sizeof(linkvalue));
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 ");
439 } /*Dealing with symlink*/
441 else if (((s1.st_mode & S_IFMT) == S_IFDIR) && (recursive || (level == 0))) {
443 * ----------------------- Copy directory -----------------------
449 char f1[MAXPATHLEN], f2[MAXPATHLEN];
454 printf("Level %d: Directory %s to %s\n", level, file1, file2);
458 /* Don't ovewrite a write protected directory (unless force: -f) */
459 if (!forceOverwrite && goods2 && (s2.st_mode & 0200) == 0) {
461 "Directory %s is write protected against its owner; not changed\n",
468 p1 = f1 + strlen(f1);
469 p2 = f2 + strlen(f2);
470 if (p1 == f1 || p1[-1] != '/')
472 if (p2 == f2 || p2[-1] != '/')
475 dir = opendir(file1);
477 fprintf(stderr, "Couldn't open %s\n", file1);
481 while ((d = readdir(dir)) != NULL) {
482 if (strcmp(d->d_name, ".") == 0 || strcmp(d->d_name, "..") == 0)
484 strcpy(p1, d->d_name);
485 strcpy(p2, d->d_name);
486 code = Copy(f1, f2, recursive, level + 1);
487 if (code && !rcode) rcode = 1; /* remember errors */
493 printf("Level %d: Copied directory %s to %s\n", level, file1, file2);
497 mkdir(file2, 0777); /* Handle case where MakeParent not invoked. */
500 printf(" Set owner-id for %s to %d\n", file2, s1.st_uid);
503 code = chown(file2, s1.st_uid, -1);
505 fprintf(stderr, "Unable to set owner-id for %s to %d\n", file2, s1.st_uid);
507 s1.st_mode &= ~04000; /* Don't set suid bit */
511 printf(" Set group-id for %s to %d\n", file2, s1.st_gid);
514 code = chown(file2, -1, s1.st_gid);
516 fprintf(stderr, "Unable to set group-id for %s to %d\n", file2, s1.st_gid);
518 s1.st_mode &= ~02000; /* Don't set sgid bit */
522 printf(" Set mode-bit for %s to %o\n", file2, (s1.st_mode & 07777));
525 code = chmod(file2, s1.st_mode);
527 fprintf(stderr, "Unable to set mode-bits for %s to %d\n", file2, s1.st_mode);
532 if (setacl == true) {
534 printf(" Set acls for %s\n", file2);
541 blob.out_size = MAXACL;
544 /* Get an old-style ACL and convert it */
545 for (i=1; i<strlen(file1); i++)
546 if (file1[i] == '/') break;
547 strcpy(aclspace, &file1[i]);
549 blob.in_size = 1+strlen(aclspace);
550 tfd = open(file1, O_RDONLY, 0);
552 perror("old-acl open ");
555 code = ioctl(tfd, _VICEIOCTL(4), &blob);
558 if (errno == EINVAL) {
565 /* Now convert the thing. */
566 oacl = (struct OldAcl *) (aclspace+4);
567 sprintf(tacl, "%d\n%d\n", oacl->nplus, oacl->nminus);
568 strcat(tacl, oacl->data);
569 strcpy(aclspace, tacl);
570 } /*Grab and convert old-style ACL*/
572 /* Get a new-style ACL */
573 code = pioctl(file1, _VICEIOCTL(2), &blob, 1);
575 if (errno == EINVAL) {
583 } /*Grab new-style ACL*/
586 * Now, set the new-style ACL.
588 if (setacl == true) {
592 blob.in_size = 1+strlen(aclspace);
593 code = pioctl(file2, _VICEIOCTL(1), &blob, 1);
595 if (errno == EINVAL) {
599 fprintf(stderr, "Couldn't set acls for %s\n", file2);
605 if (setacl == false) {
606 printf("Not setting acls\n");