+ 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;
+}
+#endif
+
+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;
+}
+
+#ifdef HAVE_GETGROUPLIST
+static int want_all_groups(int f_out, uid_t uid)
+{
+ const char *err;
+ gid_count = MAX_GID_LIST;
+ if ((err = getallgroups(uid, gid_list, &gid_count)) != NULL) {
+ rsyserr(FLOG, errno, "%s", err);
+ io_printf(f_out, "@ERROR: %s\n", err);
+ return -1;
+ }
+ return 0;
+}
+#elif defined HAVE_INITGROUPS
+static struct passwd *want_all_groups(int f_out, uid_t uid)
+{
+ struct passwd *pw;
+ if ((pw = getpwuid(uid)) == NULL) {
+ rsyserr(FLOG, errno, "getpwuid failed");
+ io_printf(f_out, "@ERROR: getpwuid failed\n");
+ return NULL;
+ }
+ /* Start with the default group and initgroups() will add the reset. */
+ gid_count = 1;
+ gid_list[0] = pw->pw_gid;
+ return pw;
+}
+#endif
+
+static void set_env_str(const char *var, const char *str)
+{
+#ifdef HAVE_PUTENV
+ char *mem;
+ if (asprintf(&mem, "%s=%s", var, str) < 0)
+ out_of_memory("set_env_str");
+ putenv(mem);
+#endif
+}
+
+#ifdef HAVE_PUTENV
+static void set_env_num(const char *var, long num)
+{
+ char *mem;
+ if (asprintf(&mem, "%s=%ld", var, num) < 0)
+ out_of_memory("set_env_num");
+ putenv(mem);
+}
+#endif
+
+static int rsync_module(int f_in, int f_out, int i, const char *addr, const char *host)
+{
+ int argc;
+ char **argv, **orig_argv, **orig_early_argv, *module_chdir;
+ char line[BIGPATHBUFLEN];
+#if defined HAVE_INITGROUPS && !defined HAVE_GETGROUPLIST
+ struct passwd *pw = NULL;
+#endif
+ uid_t uid;
+ int set_uid;
+ char *p, *err_msg = NULL;