Improved to include configure support and documentation.
[rsync/rsync-patches.git] / pre-post-exec.diff
1 A patch to add two new daemon module options:
2
3     pre-xfer exec = COMMAND
4     post-xfer exec = COMMAND
5
6 The "pre-xfer exec" command runs before the transfer happens, while the
7 'post-xfer exec" command runs after the transfer completes, even if the
8 transfer failed.  The following environment variables will be set in
9 both cases:
10
11     RSYNC_MODULE_NAME  The name of the module being accessed.
12     RSYNC_MODULE_PATH  The path configured for the module.
13     RSYNC_HOST_ADDR    The accessing host's IP address.
14     RSYNC_HOST_NAME    The accessing host's name.
15     RSYNC_USER_NAME    The accessing user's name.
16
17 These environment variables will also be set for the "post-xfer exec"
18 command:
19
20     RSYNC_EXIT_STATUS  rsync's exit value.  This will be 0 for a
21                        successful run, a positive value for an error
22                        that rsync returned (e.g. 23=partial xfer),
23                        or a -1 if rsync failed to exit properly.
24     RSYNC_RAW_STATUS  the raw exit value from waitpid().
25
26 Both commands are run by the user that started the daemon (not the
27 module's uid/gid setting) without any chroot() restrictions (even if
28 the module will/has run chroot()ed).
29
30 After applying this patch, run these commands for a successful build:
31
32     autoconf
33     autoheader
34     ./configure
35     make proto
36     make
37
38 --- orig/clientserver.c 2005-06-10 21:33:27
39 +++ clientserver.c      2005-07-28 10:27:33
40 @@ -227,6 +227,9 @@ static int rsync_module(int f_in, int f_
41         uid_t uid = (uid_t)-2;  /* canonically "nobody" */
42         gid_t gid = (gid_t)-2;
43         char *p;
44 +#ifdef HAVE_PUTENV
45 +       char *s;
46 +#endif
47         char *addr = client_addr(f_in);
48         char *host = client_name(f_in);
49         char *name = lp_name(i);
50 @@ -347,6 +350,58 @@ static int rsync_module(int f_in, int f_
51  
52         log_init();
53  
54 +#ifdef HAVE_PUTENV
55 +       s = lp_prexfer_exec(i);
56 +       p = lp_postxfer_exec(i);
57 +       if ((s && *s) || (p && *p)) {
58 +               char *modname, *modpath, *hostaddr, *hostname, *username;
59 +               int status;
60 +               if (asprintf(&modname, "RSYNC_MODULE_NAME=%s", name) < 0
61 +                || asprintf(&modpath, "RSYNC_MODULE_PATH=%s", lp_path(i)) < 0
62 +                || asprintf(&hostaddr, "RSYNC_HOST_ADDR=%s", addr) < 0
63 +                || asprintf(&hostname, "RSYNC_HOST_NAME=%s", host) < 0
64 +                || asprintf(&username, "RSYNC_USER_NAME=%s", auth_user) < 0)
65 +                       out_of_memory("rsync_module");
66 +               putenv(modname);
67 +               putenv(modpath);
68 +               putenv(hostaddr);
69 +               putenv(hostname);
70 +               putenv(username);
71 +               umask(orig_umask);
72 +               if (s && *s) {
73 +                       status = system(s);
74 +                       if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
75 +                               rprintf(FLOG, "prexfer-exec failed\n");
76 +                               io_printf(f_out, "@ERROR: prexfer-exec failed\n");
77 +                               return -1;
78 +                       }
79 +               }
80 +               if (p && *p) {
81 +                       pid_t pid = fork();
82 +                       if (pid < 0) {
83 +                               rsyserr(FLOG, errno, "fork failed");
84 +                               io_printf(f_out, "@ERROR: fork failed\n");
85 +                               return -1;
86 +                       }
87 +                       if (pid) {
88 +                               char *ret1, *ret2;
89 +                               waitpid(pid, &status, 0);
90 +                               if (asprintf(&ret1, "RSYNC_RAW_STATUS=%d", status) > 0)
91 +                                       putenv(ret1);
92 +                               if (WIFEXITED(status))
93 +                                       status = WEXITSTATUS(status);
94 +                               else
95 +                                       status = -1;
96 +                               if (asprintf(&ret2, "RSYNC_EXIT_STATUS=%d", status) > 0)
97 +                                       putenv(ret2);
98 +                               system(p);
99 +                               _exit(0);
100 +                       }
101 +               }
102 +               umask(0);
103 +       }
104 +#endif
105 +
106         if (use_chroot) {
107                 /*
108                  * XXX: The 'use chroot' flag is a fairly reliable
109 --- orig/configure.in   2005-07-27 23:31:12
110 +++ configure.in        2005-07-28 10:27:34
111 @@ -501,7 +501,7 @@ AC_CHECK_FUNCS(waitpid wait4 getcwd strd
112      memmove lchown vsnprintf snprintf vasprintf asprintf setsid glob strpbrk \
113      strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \
114      setlocale setmode open64 lseek64 mkstemp64 mtrace va_copy __va_copy \
115 -    strerror)
116 +    strerror putenv)
117  
118  AC_CHECK_FUNCS(getpgrp tcgetpgrp)
119  if test $ac_cv_func_getpgrp = yes; then
120 --- orig/loadparm.c     2005-06-10 21:33:28
121 +++ loadparm.c  2005-07-28 10:27:34
122 @@ -140,6 +140,8 @@ typedef struct
123         char *log_format;
124         char *refuse_options;
125         char *dont_compress;
126 +       char *prexfer_exec;
127 +       char *postxfer_exec;
128         int timeout;
129         int max_connections;
130         int max_verbosity;
131 @@ -175,6 +177,8 @@ static service sDefault =
132         "%o %h [%a] %m (%u) %f %l",    /* log format */
133         NULL,    /* refuse options */
134         "*.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz",    /* dont compress */
135 +       NULL,     /* prexfer_exec */
136 +       NULL,     /* postxfer_exec */
137         0,        /* timeout */
138         0,        /* max connections */
139         1,        /* max verbosity */
140 @@ -298,6 +302,10 @@ static struct parm_struct parm_table[] =
141    {"log format",       P_STRING,  P_LOCAL,  &sDefault.log_format,  NULL,   0},
142    {"refuse options",   P_STRING,  P_LOCAL,  &sDefault.refuse_options,NULL, 0},
143    {"dont compress",    P_STRING,  P_LOCAL,  &sDefault.dont_compress,NULL,  0},
144 +#ifdef HAVE_PUTENV
145 +  {"pre-xfer exec",    P_STRING,  P_LOCAL,  &sDefault.prexfer_exec, NULL,  0},
146 +  {"post-xfer exec",   P_STRING,  P_LOCAL,  &sDefault.postxfer_exec,NULL,  0},
147 +#endif
148    {NULL,               P_BOOL,    P_NONE,   NULL,                  NULL,   0}
149  };
150  
151 @@ -379,6 +387,8 @@ FN_LOCAL_STRING(lp_include_from, include
152  FN_LOCAL_STRING(lp_log_format, log_format)
153  FN_LOCAL_STRING(lp_refuse_options, refuse_options)
154  FN_LOCAL_STRING(lp_dont_compress, dont_compress)
155 +FN_LOCAL_STRING(lp_prexfer_exec, prexfer_exec)
156 +FN_LOCAL_STRING(lp_postxfer_exec, postxfer_exec)
157  FN_LOCAL_INTEGER(lp_timeout, timeout)
158  FN_LOCAL_INTEGER(lp_max_connections, max_connections)
159  FN_LOCAL_INTEGER(lp_max_verbosity, max_verbosity)
160 --- orig/rsyncd.conf.yo 2005-07-28 09:59:28
161 +++ rsyncd.conf.yo      2005-07-28 10:27:35
162 @@ -454,6 +454,35 @@ of the patterns will not be compressed d
163  
164  The default setting is tt(*.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz)
165  
166 +dit(bf(pre-xfer exec), bf(post-xfer exec)) You may specify a command to be run
167 +before and/or after the transfer.  If the bf(pre-xfer exec) command fails, the
168 +transfer is aborted before it begins.
169 +
170 +The following environment variables are set for both commands:
171 +
172 +quote(itemize(
173 +  it() bf(RSYNC_MODULE_NAME): The name of the module being accessed.
174 +  it() bf(RSYNC_MODULE_PATH): The path configured for the module.
175 +  it() bf(RSYNC_HOST_ADDR): The accessing host's IP address.
176 +  it() bf(RSYNC_HOST_NAME): The accessing host's name.
177 +  it() bf(RSYNC_USER_NAME): The accessing user's name (empty if no user).
178 +))
179 +
180 +These environment variables will also be set for the bf(post-xfer exec)
181 +command:
182 +
183 +quote(itemize(
184 +  it() bf(RSYNC_EXIT_STATUS): rsync's exit value.  This will be 0 for a
185 +  successful run, a positive value for an error that rsync returned
186 +  (e.g. 23=partial xfer), or a -1 if rsync failed to exit properly.
187 +  it() bf(RSYNC_RAW_STATUS): the raw exit value from waitpid().
188 +))
189 +
190 +Even though the commands can be associated with a particular module, they
191 +are run using the permissions of the user that started the daemon (not the
192 +module's uid/gid setting) without any chroot restrictions (even if the
193 +module will/has run chroot()ed).
194 +
195  enddit()
196  
197  manpagesection(AUTHENTICATION STRENGTH)