2 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * Copyright (c) 1983 Regents of the University of California.
10 * Redistribution and use in source and binary forms are permitted
11 * provided that the above copyright notice and this paragraph are
12 * duplicated in all such forms and that any documentation,
13 * advertising materials, and other materials related to such
14 * distribution and use acknowledge that the software was developed
15 * by the University of California, Berkeley. The name of the
16 * University may not be used to endorse or promote products derived
17 * from this software without specific prior written permission.
29 * If we want to write *to* the client rdist program, *from* the server
30 * side (server-side child `rdist -Server' process exec'ed off of in.rshd),
31 * we write to stdout/stderr, since there is a pipe connecting stdout/stderr
32 * to the outside world (which is why we use `wrem' and not `rem').
36 #define ack() (void) write(wrem, "\0\n", 2)
37 #define err() (void) write(wrem, "\1\n", 2)
40 * Set when a desread() is reqd. in response()
43 struct linkbuf
*ihead
; /* list of files with more than one link */
44 char buf
[RDIST_BUFSIZ
]; /* general purpose buffer */
45 char source
[RDIST_BUFSIZ
]; /* base source directory name */
46 char destination
[RDIST_BUFSIZ
]; /* base destination directory name */
47 char target
[RDIST_BUFSIZ
]; /* target/source directory name */
48 char *tp
; /* pointer to end of target name */
49 char *Tdest
; /* pointer to last T dest */
50 int catname
; /* cat name to target name */
51 char *stp
[32]; /* stack of saved tp's for directories */
52 int oumask
; /* old umask for creating files */
54 extern FILE *lfp
; /* log file for mailing changes */
57 struct linkbuf
*savelink();
60 static void comment(char *s
);
62 static void hardlink(char *cmd
);
65 static void recursive_remove(struct stat
*stp
);
66 static void recvf(char *cmd
, int type
);
67 static void query(char *name
);
68 static void sendf(char *rname
, int opts
);
69 static void rmchk(int opts
);
70 static void dospecial(char *cmd
);
71 static void clean(char *cp
);
74 * Server routine to read requests and process them.
76 * Tname - Transmit file if out of date
77 * Vname - Verify if file out of date or not
78 * Qname - Query if file exists. Return mtime & size if it does.
83 char cmdbuf
[RDIST_BUFSIZ
];
86 signal(SIGHUP
, cleanup
);
87 signal(SIGINT
, cleanup
);
88 signal(SIGQUIT
, cleanup
);
89 signal(SIGTERM
, cleanup
);
90 signal(SIGPIPE
, cleanup
);
95 (void) sprintf(buf
, "V%d\n", VERSION
);
96 (void) write(wrem
, buf
, strlen(buf
));
100 if (read(rem
, cp
, 1) <= 0)
103 error("server: expected control record\n");
107 if (read(rem
, cp
, 1) != 1)
109 } while (*cp
++ != '\n' && cp
< &cmdbuf
[RDIST_BUFSIZ
]);
113 case 'T': /* init target file/directory name */
114 catname
= 1; /* target should be directory */
117 case 't': /* init target file/directory name */
120 if (exptilde(target
, sizeof (target
), cp
) == NULL
)
128 case 'R': /* Transfer a regular file. */
132 case 'D': /* Transfer a directory. */
136 case 'K': /* Transfer symbolic link. */
140 case 'k': /* Transfer hard link. */
144 case 'E': /* End. (of directory) */
147 error("server: too many 'E's\n");
155 case 'C': /* Clean. Cleanup a directory */
159 case 'Q': /* Query. Does the file/directory exist? */
163 case 'S': /* Special. Execute commands */
169 * These entries are reserved but not currently used.
170 * The intent is to allow remote hosts to have master copies.
171 * Currently, only the host rdist runs on can have masters.
173 case 'X': /* start a new list of files to exclude */
175 case 'x': /* add name to list of files to exclude */
181 if (exptilde(buf
, sizeof (buf
), cp
) == NULL
)
186 except
= bp
= expand(makeblock(NAME
, cp
),
189 bp
->b_next
= expand(makeblock(NAME
, cp
),
191 while (bp
->b_next
!= NULL
)
196 case 'I': /* Install. Transfer file if out of date. */
198 while (*cp
>= '0' && *cp
<= '7')
199 opts
= (opts
<< 3) | (*cp
++ - '0');
201 error("server: options not delimited\n");
207 case 'L': /* Log. save message in log file */
220 error("server: unknown command '%s'\n", cp
);
228 * Update the file(s) if they are different.
229 * destdir = 1 if destination should be a directory
230 * (i.e., more than one source is being copied to the same destination).
233 install(src
, dest
, destdir
, opts
)
238 char destcopy
[RDIST_BUFSIZ
];
241 opts
&= ~WHOLE
; /* WHOLE mode only useful if renaming */
245 if (nflag
|| debug
) {
246 printf("%s%s%s%s%s %s %s\n", opts
& VERIFY
? "verify":"install",
247 opts
& WHOLE
? " -w" : "",
248 opts
& YOUNGER
? " -y" : "",
249 opts
& COMPARE
? " -b" : "",
250 opts
& REMOVE
? " -R" : "", src
, dest
);
255 rname
= exptilde(target
, sizeof (target
), src
);
262 * If we are renaming a directory and we want to preserve
263 * the directory heirarchy (-w), we must strip off the leading
264 * directory name and preserve the rest.
267 while (*rname
== '/')
271 rname
= rindex(target
, '/');
278 printf("target = %s, rname = %s\n", target
, rname
);
280 * Pass the destination file/directory name to remote.
282 if (snprintf(buf
, sizeof (buf
), "%c%s\n", destdir
? 'T' : 't', dest
) >=
284 error("%s: Name too long\n", dest
);
288 printf("buf = %s", buf
);
289 (void) deswrite(rem
, buf
, strlen(buf
), 0);
296 strcpy(destcopy
, dest
);
298 strcpy(destination
, rname
);
300 strcpy(destination
, dest
);
306 #define protoname() (pw ? pw->pw_name : user)
307 #define protogroup() (gr ? gr->gr_name : group)
309 * Transfer the file or directory in target[].
310 * rname is the name of the file on the remote host.
317 register struct subcmd
*sc
;
319 int sizerr
, f
, u
, len
;
324 extern struct subcmd
*subcmds
;
325 static char user
[15], group
[15];
328 printf("sendf(%s, %x%s)\n", rname
, opts
, printb(opts
, OBITS
));
332 if ((opts
& FOLLOW
? stat(target
, &stb
) : lstat(target
, &stb
)) < 0) {
333 error("%s: %s\n", target
, strerror(errno
));
336 if (index(rname
, '\n')) {
337 error("file name '%s' contains an embedded newline - "
338 "can't update\n", rname
);
341 if ((u
= update(rname
, opts
, &stb
)) == 0) {
342 if ((stb
.st_mode
& S_IFMT
) == S_IFREG
&& stb
.st_nlink
> 1)
343 (void) savelink(&stb
, opts
);
347 if (pw
== NULL
|| pw
->pw_uid
!= stb
.st_uid
)
348 if ((pw
= getpwuid(stb
.st_uid
)) == NULL
) {
349 log(lfp
, "%s: no password entry for uid %d \n",
352 sprintf(user
, ":%d", stb
.st_uid
);
354 if (gr
== NULL
|| gr
->gr_gid
!= stb
.st_gid
)
355 if ((gr
= getgrgid(stb
.st_gid
)) == NULL
) {
356 log(lfp
, "%s: no name for group %d\n",
359 sprintf(group
, ":%d", stb
.st_gid
);
363 log(lfp
, "need to install: %s\n", target
);
366 log(lfp
, "installing: %s\n", target
);
367 opts
&= ~(COMPARE
|REMOVE
);
370 switch (stb
.st_mode
& S_IFMT
) {
372 if ((d
= opendir(target
)) == NULL
) {
373 error("%s: %s\n", target
, strerror(errno
));
376 if (snprintf(buf
, sizeof (buf
), "D%o %04o 0 0 %s %s %s\n",
377 opts
, stb
.st_mode
& 07777, protoname(), protogroup(),
378 rname
) >= sizeof (buf
)) {
379 error("%s: Name too long\n", rname
);
384 printf("buf = %s", buf
);
385 (void) deswrite(rem
, buf
, strlen(buf
), 0);
386 if (response() < 0) {
396 while (dp
= readdir(d
)) {
397 if ((strcmp(dp
->d_name
, ".") == 0)||
398 (strcmp(dp
->d_name
, "..") == 0))
400 if ((int)(len
+ 1 + strlen(dp
->d_name
)) >=
401 (int)(RDIST_BUFSIZ
- 1)) {
402 error("%.*s/%s: Name too long\n", len
, target
,
409 while (*tp
++ = *cp
++)
412 sendf(dp
->d_name
, opts
);
415 (void) deswrite(rem
, "E\n", 2, 0);
424 if (stb
.st_nlink
> 1) {
427 if ((lp
= savelink(&stb
, opts
)) != NULL
) {
429 if (*lp
->target
== 0)
430 len
= snprintf(buf
, sizeof (buf
),
431 "k%o %s %s\n", opts
, lp
->pathname
,
434 len
= snprintf(buf
, sizeof (buf
),
435 "k%o %s/%s %s\n", opts
, lp
->target
,
436 lp
->pathname
, rname
);
437 if (len
>= sizeof (buf
)) {
438 error("%s: Name too long\n", rname
);
442 printf("buf = %s", buf
);
443 (void) deswrite(rem
, buf
, strlen(buf
), 0);
448 (void) snprintf(buf
, sizeof (buf
), "K%o %o %ld %ld %s %s %s\n",
449 opts
, stb
.st_mode
& 07777, stb
.st_size
, stb
.st_mtime
,
450 protoname(), protogroup(), rname
);
452 printf("buf = %s", buf
);
453 (void) deswrite(rem
, buf
, strlen(buf
), 0);
456 sizerr
= (readlink(target
, buf
, RDIST_BUFSIZ
) != stb
.st_size
);
457 (void) deswrite(rem
, buf
, stb
.st_size
, 0);
459 printf("readlink = %.*s\n", (int)stb
.st_size
, buf
);
466 error("%s: not a file or directory\n", target
);
472 log(lfp
, "need to update: %s\n", target
);
475 log(lfp
, "updating: %s\n", target
);
478 if (stb
.st_nlink
> 1) {
481 if ((lp
= savelink(&stb
, opts
)) != NULL
) {
483 if (*lp
->target
== 0)
484 len
= snprintf(buf
, sizeof (buf
), "k%o %s %s\n",
485 opts
, lp
->pathname
, rname
);
487 len
= snprintf(buf
, sizeof (buf
),
488 "k%o %s/%s %s\n", opts
, lp
->target
,
489 lp
->pathname
, rname
);
490 if (len
>= sizeof (buf
)) {
491 error("%s: Name too long\n", rname
);
495 printf("buf = %s", buf
);
496 (void) deswrite(rem
, buf
, strlen(buf
), 0);
502 if ((f
= open(target
, 0)) < 0) {
503 error("%s: %s\n", target
, strerror(errno
));
506 (void) snprintf(buf
, sizeof (buf
), "R%o %o %ld %ld %s %s %s\n", opts
,
507 stb
.st_mode
& 07777, stb
.st_size
, stb
.st_mtime
,
508 protoname(), protogroup(), rname
);
510 printf("buf = %s", buf
);
511 (void) deswrite(rem
, buf
, strlen(buf
), 0);
513 if (response() < 0) {
520 for (i
= 0; i
< stb
.st_size
; i
+= RDIST_BUFSIZ
) {
521 int amt
= RDIST_BUFSIZ
;
522 if (i
+ amt
> stb
.st_size
)
523 amt
= stb
.st_size
- i
;
524 if (sizerr
== 0 && read(f
, buf
, amt
) != amt
)
526 (void) deswrite(rem
, buf
, amt
, 0);
531 error("%s: file changed size\n", target
);
532 (void) deswrite(rem
, "\1\n", 2, 0);
534 (void) deswrite(rem
, "\0\n", 2, 0);
537 if (f
< 0 || f
== 0 && (opts
& COMPARE
))
540 for (sc
= subcmds
; sc
!= NULL
; sc
= sc
->sc_next
) {
541 if (sc
->sc_type
!= SPECIAL
)
543 if (sc
->sc_args
!= NULL
&& !inlist(sc
->sc_args
, target
))
545 log(lfp
, "special \"%s\"\n", sc
->sc_name
);
548 (void) snprintf(buf
, sizeof (buf
), "SFILE=%s;%s\n", target
,
551 printf("buf = %s", buf
);
552 (void) deswrite(rem
, buf
, strlen(buf
), 0);
553 while (response() > 0)
565 for (lp
= ihead
; lp
!= NULL
; lp
= lp
->nextp
)
566 if (lp
->inum
== stp
->st_ino
&& lp
->devnum
== stp
->st_dev
) {
570 lp
= (struct linkbuf
*)malloc(sizeof (*lp
));
572 log(lfp
, "out of memory, link information lost\n");
576 lp
->inum
= stp
->st_ino
;
577 lp
->devnum
= stp
->st_dev
;
578 lp
->count
= stp
->st_nlink
- 1;
580 if (strlcpy(lp
->pathname
,
581 opts
& WHOLE
? target
: strsub(source
, destination
, target
),
582 sizeof (lp
->pathname
)) >= sizeof (lp
->pathname
)) {
583 error("%s: target name too long\n", target
);
587 if (strlcpy(lp
->target
, Tdest
,
588 sizeof (lp
->target
)) >= sizeof (lp
->target
))
589 error("%s: target name too long\n", Tdest
);
597 * Check to see if file needs to be updated on the remote machine.
598 * Returns 0 if no update, 1 if remote doesn't exist, 2 if out of date
599 * and 3 if comparing binaries to determine if out of date.
602 update(rname
, opts
, stp
)
607 register char *cp
, *s
;
609 register time_t mtime
;
612 printf("update(%s, %x%s, %x)\n", rname
, opts
,
613 printb(opts
, OBITS
), stp
);
616 * Check to see if the file exists on the remote machine.
618 if (snprintf(buf
, sizeof (buf
), "Q%s\n", rname
) >= sizeof (buf
)) {
619 error("%s: Name too long\n", rname
);
623 printf("buf = %s", buf
);
624 (void) deswrite(rem
, buf
, strlen(buf
), 0);
629 if (desread(rem
, cp
, 1, 0) != 1)
631 } while (*cp
++ != '\n' && cp
< &buf
[RDIST_BUFSIZ
]);
633 if (cp
< &buf
[RDIST_BUFSIZ
])
636 printf("update reply: ");
645 putchar('A' + *s
- 1);
647 printf("%#x", *s
& 0xff);
657 case 'N': /* file doesn't exist so install it */
665 (void) write(2, s
, cp
- s
);
668 (void) fwrite(s
, 1, cp
- s
, lfp
);
670 if (cp
== &buf
[RDIST_BUFSIZ
] && *(cp
- 1) != '\n') {
671 /* preserve status code */
681 log(lfp
, "update: note: %s\n", s
);
686 error("update: unexpected response '%s'\n", s
);
698 size
= size
* 10 + (*s
++ - '0');
700 error("update: size not delimited\n");
705 mtime
= mtime
* 10 + (*s
++ - '0');
707 error("update: mtime not delimited\n");
711 * File needs to be updated?
713 if (opts
& YOUNGER
) {
714 if (stp
->st_mtime
== mtime
)
716 if (stp
->st_mtime
< mtime
) {
717 log(lfp
, "Warning: %s: remote copy is newer\n", target
);
720 } else if (stp
->st_mtime
== mtime
&& stp
->st_size
== size
)
726 * Query. Check to see if file exists. Return one of the following:
727 * N\n - doesn't exist
728 * Ysize mtime\n - exists and its a regular file (size & mtime of file)
729 * Y\n - exists and its a directory or symbolic link
739 if (sizeof (target
) - (tp
- target
) >= strlen(name
) + 2) {
740 (void) sprintf(tp
, "/%s", name
);
742 error("%.*s/%s: Name too long\n", tp
- target
,
748 if (lstat(target
, &stb
) < 0) {
750 (void) write(wrem
, "N\n", 2);
752 error("%s:%s: %s\n", host
, target
, strerror(errno
));
757 switch (stb
.st_mode
& S_IFMT
) {
759 (void) sprintf(buf
, "Y%ld %ld\n", stb
.st_size
, stb
.st_mtime
);
760 (void) write(wrem
, buf
, strlen(buf
));
765 (void) write(wrem
, "Y\n", 2);
769 error("%s: not a file or directory\n", name
);
781 int f
, mode
, opts
, wrerr
, olderrno
;
785 struct timeval tvp
[2];
787 char new[RDIST_BUFSIZ
];
788 extern char *tmpname
;
792 while (*cp
>= '0' && *cp
<= '7')
793 opts
= (opts
<< 3) | (*cp
++ - '0');
795 error("recvf: options not delimited\n");
799 while (*cp
>= '0' && *cp
<= '7')
800 mode
= (mode
<< 3) | (*cp
++ - '0');
802 error("recvf: mode not delimited\n");
807 size
= size
* 10 + (*cp
++ - '0');
809 error("recvf: size not delimited\n");
814 mtime
= mtime
* 10 + (*cp
++ - '0');
816 error("recvf: mtime not delimited\n");
820 while (*cp
&& *cp
!= ' ')
823 error("recvf: owner name not delimited\n");
828 while (*cp
&& *cp
!= ' ')
831 error("recvf: group name not delimited\n");
836 if (type
== S_IFDIR
) {
839 if (strcmp(cp
, ".") == 0)
843 if (catname
>= sizeof (stp
) / sizeof (stp
[0])) {
844 error("%s:%s: too many directory levels\n",
851 while (*tp
++ = *cp
++)
859 if (lstat(target
, &stb
) == 0) {
860 if (ISDIR(stb
.st_mode
)) {
861 if ((stb
.st_mode
& 07777) == mode
) {
865 sendrem("%s: Warning: remote mode %o != "
866 "local mode %o", target
,
867 stb
.st_mode
& 07777, mode
);
871 } else if (errno
== ENOENT
&& (mkdir(target
, mode
) == 0 ||
872 chkparent(target
) == 0 &&
873 (isdot
== 1 || mkdir(target
, mode
) == 0))) {
874 if (chog(target
, owner
, group
, mode
) == 0)
878 error("%s:%s: %s\n", host
, target
, strerror(errno
));
885 if (sizeof (target
) - (tp
- target
) >= strlen(cp
) + 2) {
886 (void) sprintf(tp
, "/%s", cp
);
888 error("%.*s/%s: Name too long\n", tp
- target
,
893 cp
= rindex(target
, '/');
895 strcpy(new, tmpname
);
896 else if (cp
== target
)
897 (void) sprintf(new, "/%s", tmpname
);
902 * sizeof (target) = RDIST_BUFSIZ and sizeof (tmpname) = 11
903 * RDIST_BUFSIZ = 50*1024 is much greater than PATH_MAX that is
904 * allowed by the kernel, so it's safe to call snprintf() here
906 (void) snprintf(new, sizeof (new), "%s/%s", target
, tmpname
);
910 if (type
== S_IFLNK
) {
915 for (i
= 0; i
< size
; i
+= j
) {
916 if ((j
= read(rem
, cp
, size
- i
)) <= 0)
921 if (response() < 0) {
925 if (symlink(buf
, new) < 0) {
926 if (errno
!= ENOENT
|| chkparent(new) < 0 ||
927 symlink(buf
, new) < 0)
931 if (opts
& COMPARE
) {
932 char tbuf
[MAXPATHLEN
];
934 if ((i
= readlink(target
, tbuf
, MAXPATHLEN
)) >= 0 &&
935 i
== size
&& strncmp(buf
, tbuf
, size
) == 0) {
946 if ((f
= creat(new, mode
& ~06000)) < 0) {
947 if (errno
!= ENOENT
|| chkparent(new) < 0 ||
948 (f
= creat(new, mode
& ~06000)) < 0)
954 for (i
= 0; i
< size
; i
+= RDIST_BUFSIZ
) {
955 int amt
= RDIST_BUFSIZ
;
961 int j
= read(rem
, cp
, amt
);
973 if (wrerr
== 0 && write(f
, buf
, amt
) != amt
) {
980 if (response() < 0) {
986 error("%s:%s: %s\n", host
, new, strerror(olderrno
));
990 if (opts
& COMPARE
) {
994 if ((f1
= fopen(target
, "r")) == NULL
)
996 if ((f2
= fopen(new, "r")) == NULL
) {
998 error("%s:%s: %s\n", host
, new, strerror(errno
));
1002 while ((c
= getc(f1
)) == getc(f2
))
1012 if (opts
& VERIFY
) {
1015 sendrem("need to update: %s", target
);
1021 * Set last modified time. For type == S_IFDIR, the lstat above filled
1022 * in stb. Otherwise, do it now.
1024 if (type
!= S_IFDIR
)
1025 (void) lstat(new, &stb
);
1026 tvp
[0].tv_sec
= stb
.st_atime
; /* old atime from target */
1028 tvp
[1].tv_sec
= mtime
;
1030 if (utimes(new, tvp
) < 0) {
1031 note("%s:utimes failed %s: %s", host
, new, strerror(errno
));
1033 if (chog(new, owner
, group
, mode
) < 0) {
1038 if (rename(new, target
) < 0) {
1040 error("%s:%s: %s\n", host
, target
, strerror(errno
));
1044 if (opts
& COMPARE
) {
1045 sendrem("updated %s", target
);
1051 * Creat a hard link to existing file.
1060 int opts
, exists
= 0;
1061 char oldnamebuf
[RDIST_BUFSIZ
];
1065 while (*cp
>= '0' && *cp
<= '7')
1066 opts
= (opts
<< 3) | (*cp
++ - '0');
1068 error("hardlink: options not delimited\n");
1072 while (*cp
&& *cp
!= ' ')
1075 error("hardlink: oldname name not delimited\n");
1081 if (sizeof (target
) - (tp
- target
) >= strlen(cp
) + 2) {
1082 (void) sprintf(tp
, "/%s", cp
);
1084 error("%.*s/%s: Name too long\n", tp
- target
,
1089 if (lstat(target
, &stb
) == 0) {
1090 int mode
= stb
.st_mode
& S_IFMT
;
1091 if (mode
!= S_IFREG
&& mode
!= S_IFLNK
) {
1092 error("%s:%s: not a regular file\n", host
, target
);
1097 if (chkparent(target
) < 0) {
1098 error("%s:%s: %s (no parent)\n",
1099 host
, target
, strerror(errno
));
1102 if (opts
& VERIFY
) {
1105 if (exists
&& lstat(oldname
, &nstb
) == 0 &&
1106 nstb
.st_mode
== stb
.st_mode
&&
1107 nstb
.st_ino
== stb
.st_ino
&&
1108 nstb
.st_dev
== stb
.st_dev
) {
1112 sendrem("need to update: %s", target
);
1116 if (exists
&& (unlink(target
) < 0)) {
1117 error("%s:%s: %s (unlink)\n",
1118 host
, target
, strerror(errno
));
1121 if (*oldname
== '~')
1122 oldname
= exptilde(oldnamebuf
, sizeof (oldnamebuf
), oldname
);
1123 if (link(oldname
, target
) < 0) {
1124 error("%s:can't link %s to %s\n",
1125 host
, target
, oldname
);
1132 * Check to see if parent directory exists and create one if not.
1141 cp
= rindex(name
, '/');
1142 if (cp
== NULL
|| cp
== name
)
1145 if (lstat(name
, &stb
) < 0) {
1146 if (errno
== ENOENT
&& chkparent(name
) >= 0 &&
1147 mkdir(name
, 0777 & ~oumask
) >= 0) {
1151 } else if (ISDIR(stb
.st_mode
)) {
1160 * Change owner, group and mode of file.
1163 chog(file
, owner
, group
, mode
)
1164 char *file
, *owner
, *group
;
1172 * by default, set uid of file to the uid of the person running
1178 * We'll use available privileges so we just try to do what
1179 * the client specifies. If the chown() fails we'll not
1180 * add the set-[ug]id bits; and if we want to add the set-[ug]id
1181 * bits and we're not permitted to do so, the OS will prevent us
1184 if (*owner
== ':') {
1185 uid
= atoi(owner
+ 1);
1186 } else if (pw
== NULL
|| strcmp(owner
, pw
->pw_name
) != 0) {
1187 if ((pw
= getpwnam(owner
)) == NULL
) {
1189 note("%s:%s: unknown login name, "
1190 "clearing setuid", host
, owner
);
1200 if (*group
== ':') {
1201 gid
= atoi(group
+ 1);
1206 if (gr
== NULL
|| strcmp(group
, gr
->gr_name
) != 0) {
1207 if ((*group
== ':' &&
1208 (getgrgid(gid
= atoi(group
+ 1)) == NULL
)) ||
1209 ((gr
= getgrnam(group
)) == NULL
)) {
1211 note("%s:%s: unknown group", host
, group
);
1219 if (chown(file
, uid
, gid
) < 0 ||
1220 (mode
& 07000) && chmod(file
, mode
) < 0) {
1221 note("%s: chown or chmod failed: file %s: %s",
1222 host
, file
, strerror(errno
));
1228 * Check for files on the machine being updated that are not on the master
1229 * machine and remove them.
1235 register char *cp
, *s
;
1239 printf("rmchk()\n");
1242 * Tell the remote to clean the files from the last directory sent.
1244 (void) sprintf(buf
, "C%o\n", opts
& VERIFY
);
1246 printf("buf = %s", buf
);
1247 (void) deswrite(rem
, buf
, strlen(buf
), 0);
1253 if (desread(rem
, cp
, 1, 0) != 1)
1255 } while (*cp
++ != '\n' && cp
< &buf
[RDIST_BUFSIZ
]);
1258 case 'Q': /* Query if file should be removed */
1260 * Return the following codes to remove query.
1261 * N\n -- file exists - DON'T remove.
1262 * Y\n -- file doesn't exist - REMOVE.
1265 (void) sprintf(tp
, "/%s", s
);
1267 printf("check %s\n", target
);
1269 (void) deswrite(rem
, "N\n", 2, 0);
1270 else if (lstat(target
, &stb
) < 0)
1271 (void) deswrite(rem
, "Y\n", 2, 0);
1273 (void) deswrite(rem
, "N\n", 2, 0);
1279 log(lfp
, "%s\n", s
);
1284 (void) deswrite(rem
, "\0\n", 2, 0);
1293 (void) write(2, s
, cp
- s
);
1296 (void) fwrite(s
, 1, cp
- s
, lfp
);
1303 error("rmchk: unexpected response '%s'\n", buf
);
1304 (void) deswrite(rem
, "\1\n", 2, 0);
1310 * Check the current directory (initialized by the 'T' command to server())
1311 * for extraneous files and remove them.
1318 register struct dirent
*dp
;
1324 while (*cp
>= '0' && *cp
<= '7')
1325 opts
= (opts
<< 3) | (*cp
++ - '0');
1327 error("clean: options not delimited\n");
1330 if ((d
= opendir(target
)) == NULL
) {
1331 error("%s:%s: %s\n", host
, target
, strerror(errno
));
1338 while (dp
= readdir(d
)) {
1339 if ((strcmp(dp
->d_name
, ".") == 0) ||
1340 (strcmp(dp
->d_name
, "..") == 0))
1342 if ((int)(len
+ 1 + strlen(dp
->d_name
)) >=
1343 (int)(RDIST_BUFSIZ
- 1)) {
1344 error("%s:%s/%s: Name too long\n",
1345 host
, target
, dp
->d_name
);
1351 while (*tp
++ = *cp
++)
1354 if (lstat(target
, &stb
) < 0) {
1355 error("%s:%s: %s\n", host
, target
, strerror(errno
));
1358 (void) snprintf(buf
, sizeof (buf
), "Q%s\n", dp
->d_name
);
1359 (void) write(wrem
, buf
, strlen(buf
));
1362 if (read(rem
, cp
, 1) != 1)
1364 } while (*cp
++ != '\n' && cp
< &buf
[RDIST_BUFSIZ
]);
1369 if (opts
& VERIFY
) {
1370 sendrem("need to remove: %s", target
);
1372 (void) recursive_remove(&stb
);
1375 (void) write(wrem
, "E\n", 2);
1382 * Remove a file or directory (recursively) and send back an acknowledge
1383 * or an error message.
1386 recursive_remove(stp
)
1396 switch (stp
->st_mode
& S_IFMT
) {
1399 if (unlink(target
) < 0)
1407 error("%s:%s: not a plain file\n", host
, target
);
1411 if ((d
= opendir(target
)) == NULL
)
1416 while (dp
= readdir(d
)) {
1417 if ((strcmp(dp
->d_name
, ".") == 0) ||
1418 (strcmp(dp
->d_name
, "..") == 0))
1420 if ((int)(len
+ 1 + strlen(dp
->d_name
)) >=
1421 (int)(RDIST_BUFSIZ
- 1)) {
1422 error("%s:%s/%s: Name too long\n",
1423 host
, target
, dp
->d_name
);
1429 while (*tp
++ = *cp
++)
1432 if (lstat(target
, &stb
) < 0) {
1433 error("%s:%s: %s\n", host
, target
, strerror(errno
));
1436 recursive_remove(&stb
);
1441 if (rmdir(target
) < 0) {
1443 error("%s:%s: %s\n", host
, target
, strerror(errno
));
1447 sendrem("removed %s", target
);
1451 * Execute a shell command to handle special cases.
1457 int fd
[2], status
, pid
, i
;
1458 register char *cp
, *s
;
1459 char sbuf
[RDIST_BUFSIZ
];
1462 error("%s\n", strerror(errno
));
1465 if ((pid
= fork()) == 0) {
1467 * Return everything the shell commands print.
1472 (void) open("/dev/null", 0);
1475 (void) close(fd
[0]);
1476 (void) close(fd
[1]);
1477 execl("/bin/sh", "sh", "-c", cmd
, 0);
1480 (void) close(fd
[1]);
1483 while ((i
= read(fd
[0], buf
, RDIST_BUFSIZ
)) > 0) {
1487 if (cp
[-1] != '\n') {
1488 if (s
< &sbuf
[RDIST_BUFSIZ
- 1])
1493 * Throw away blank lines.
1495 if (s
== &sbuf
[2]) {
1499 (void) write(wrem
, sbuf
, s
- sbuf
);
1505 (void) write(wrem
, sbuf
, s
- sbuf
);
1507 while ((i
= wait(&status
)) != pid
&& i
!= -1)
1511 (void) close(fd
[0]);
1513 error("shell returned %d\n", status
);
1520 log(fp
, fmt
, a1
, a2
, a3
)
1525 /* Print changes locally if not quiet mode */
1527 printf(fmt
, a1
, a2
, a3
);
1529 /* Save changes (for mailing) if really updating files */
1530 if (!(options
& VERIFY
) && fp
!= NULL
)
1531 fprintf(fp
, fmt
, a1
, a2
, a3
);
1536 error(fmt
, a1
, a2
, a3
)
1543 if (!fp
&& !(fp
= fdopen(rem
, "w")))
1546 (void) fprintf(fp
, "%crdist: ", 0x01);
1547 (void) fprintf(fp
, fmt
, a1
, a2
, a3
);
1551 (void) fprintf(stderr
, "rdist: ");
1552 (void) fprintf(stderr
, fmt
, a1
, a2
, a3
);
1556 (void) fprintf(lfp
, "rdist: ");
1557 (void) fprintf(lfp
, fmt
, a1
, a2
, a3
);
1564 fatal(fmt
, a1
, a2
, a3
)
1571 if (!fp
&& !(fp
= fdopen(rem
, "w")))
1574 (void) fprintf(fp
, "%crdist: ", 0x02);
1575 (void) fprintf(fp
, fmt
, a1
, a2
, a3
);
1579 (void) fprintf(stderr
, "rdist: ");
1580 (void) fprintf(stderr
, fmt
, a1
, a2
, a3
);
1584 (void) fprintf(lfp
, "rdist: ");
1585 (void) fprintf(lfp
, fmt
, a1
, a2
, a3
);
1595 char resp
[RDIST_BUFSIZ
];
1598 printf("response()\n");
1603 if (desread(rem
, cp
, 1, 0) != 1)
1605 } while (*cp
++ != '\n' && cp
< &resp
[RDIST_BUFSIZ
]);
1611 log(lfp
, "%s\n", s
);
1617 log(lfp
, "Note: %s\n", s
);
1618 return (response());
1629 (void) write(2, s
, cp
- s
);
1632 (void) fwrite(s
, 1, cp
- s
, lfp
);
1634 if (cp
== &resp
[RDIST_BUFSIZ
] && *(cp
- 1) != '\n') {
1635 /* preserve status code */
1640 if (resp
[0] == '\2')
1647 * Remove temporary files and do any cleanup operations before exiting.
1652 (void) unlink(Tmpfile
);
1657 note(fmt
, a1
, a2
, a3
)
1661 static char buf
[RDIST_BUFSIZ
];
1662 (void) snprintf(buf
, sizeof (buf
) - 1, fmt
, a1
, a2
, a3
);
1672 struct iovec iov
[3];
1674 iov
[0].iov_base
= &three
;
1675 iov
[0].iov_len
= sizeof (char);
1676 iov
[1].iov_base
= s
;
1677 iov
[1].iov_len
= strlen(s
);
1678 iov
[2].iov_base
= &nl
;
1679 iov
[2].iov_len
= sizeof (char);
1680 (void) writev(rem
, iov
, 3);
1684 * Send message to other end.
1688 sendrem(fmt
, a1
, a2
, a3
)
1695 len
= snprintf(buf
+ 1, sizeof (buf
) - 1, fmt
, a1
, a2
, a3
) + 2;
1696 if (len
> sizeof (buf
))
1698 buf
[len
- 1] = '\n';
1699 (void) write(wrem
, buf
, len
);
1703 * strsub(old, new, s)
1705 * Return a pointer to a new string created by replacing substring old
1706 * with substring new in string s. String s is assumed to begin with
1711 char *old
, *new, *s
;
1713 static char pbuf
[PATH_MAX
];
1714 register char *p
, *q
, *r
, *plim
;
1716 /* prepend new to pbuf */
1717 for (p
= pbuf
, q
= new, plim
= pbuf
+ sizeof (pbuf
) - 1;
1721 /* p now points to the byte in pbuf where more copying should begin */
1723 /* skip over the part of s which begins with old */
1724 for (r
= old
, q
= s
; *r
; q
++, r
++)
1726 /* q now points to the byte in s where more copying should begin */
1728 while (*q
&& (p
< plim
))