+ write_buf(fd, request, strlen(request)+1);
+ if (early_argv) {
+ for ( ; *early_argv; early_argv++)
+ write_buf(fd, *early_argv, strlen(*early_argv)+1);
+ j = 1; /* Skip arg0 name in argv. */
+ }
+ for ( ; argv[j]; j++) {
+ write_buf(fd, argv[j], strlen(argv[j])+1);
+ if (argv[j][0] == '.' && argv[j][1] == '\0')
+ break;
+ }
+ write_byte(fd, 0);
+
+ close(fd);
+
+ if (wait_process(pid, &status, 0) < 0
+ || !WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+ char *e;
+ if (asprintf(&e, "pre-xfer exec returned failure (%d)%s%s\n",
+ status, status < 0 ? ": " : "",
+ status < 0 ? strerror(errno) : "") < 0)
+ out_of_memory("finish_pre_exec");
+ return e;
+ }
+ return NULL;
+}
+
+static int read_arg_from_pipe(int fd, char *buf, int limit)
+{
+ char *bp = buf, *eob = buf + limit - 1;
+
+ while (1) {
+ int got = read(fd, bp, 1);
+ if (got != 1) {
+ if (got < 0 && errno == EINTR)
+ continue;
+ return -1;
+ }
+ if (*bp == '\0')
+ break;
+ if (bp < eob)
+ bp++;
+ }
+ *bp = '\0';
+
+ return bp - buf;
+}
+
+static int path_failure(int f_out, const char *dir, BOOL was_chdir)
+{
+ if (was_chdir)
+ rsyserr(FLOG, errno, "chdir %s failed\n", dir);
+ else
+ rprintf(FLOG, "normalize_path(%s) failed\n", dir);
+ io_printf(f_out, "@ERROR: chdir failed\n");
+ return -1;
+}
+
+static int add_a_group(int f_out, const char *gname)
+{
+ gid_t gid;
+ if (!group_to_gid(gname, &gid, True)) {
+ rprintf(FLOG, "Invalid gid %s\n", gname);
+ io_printf(f_out, "@ERROR: invalid gid %s\n", gname);
+ return -1;
+ }
+ if (gid_count == MAX_GID_LIST) {
+ rprintf(FLOG, "Too many groups specified via gid parameter.\n");
+ io_printf(f_out, "@ERROR: too many groups\n");
+ return -1;
+ }
+ gid_list[gid_count++] = gid;
+ return 0;
+}
+
+static struct passwd *want_all_groups(int f_out, uid_t uid)
+{
+#if defined HAVE_GETGROUPLIST || defined HAVE_INITGROUPS
+ struct passwd *pw;
+ if ((pw = getpwuid(uid)) == NULL) {
+ rsyserr(FLOG, errno, "getpwuid failed");
+ io_printf(f_out, "@ERROR: getpwuid failed\n");
+ return NULL;
+ }
+# ifdef HAVE_GETGROUPLIST
+ /* Get all the process's groups, with the pw_gid group first. */
+ gid_count = MAX_GID_LIST;
+ if (getgrouplist(pw->pw_name, pw->pw_gid, gid_list, &gid_count) < 0) {
+ rsyserr(FLOG, errno, "getgrouplist failed");
+ io_printf(f_out, "@ERROR: getgrouplist failed\n");
+ return NULL;
+ }
+ /* Paranoia: is the default group not first in the list? */
+ if (gid_list[0] != pw->pw_gid) {
+ int j;
+ for (j = 0; j < gid_count; j++) {
+ if (gid_list[j] == pw->pw_gid) {
+ gid_list[j] = gid_list[0];
+ gid_list[0] = pw->pw_gid;
+ break;
+ }
+ }
+ }
+# else
+ /* Start with the default group and initgroups() will add the reset. */
+ gid_count = 1;
+ gid_list[0] = pw->pw_gid;
+# endif
+ return pw;
+#else
+ rprintf(FLOG, "This rsync does not support a gid of \"*\"\n");
+ io_printf(f_out, "@ERROR: invalid gid setting.\n");
+ return NULL;
+#endif
+}