-static int pw_userdel(char *name, long id);
-static int print_user(struct passwd * pwd);
-static uid_t pw_uidpolicy(struct userconf * cnf, long id);
-static uid_t pw_gidpolicy(struct cargs * args, char *nam, gid_t prefer);
-static time_t pw_pwdpolicy(struct userconf * cnf, struct cargs * args);
-static time_t pw_exppolicy(struct userconf * cnf, struct cargs * args);
-static char *pw_homepolicy(struct userconf * cnf, struct cargs * args, char const * user);
-static char *pw_shellpolicy(struct userconf * cnf, struct cargs * args, char *newshell);
-static char *pw_password(struct userconf * cnf, char const * user);
-static char *shell_path(char const * path, char *shells[], char *sh);
-static void rmat(uid_t uid);
-static void rmopie(char const * name);
+static struct passwd fakeuser = {
+ "nouser",
+ "*",
+ -1,
+ -1,
+ 0,
+ "",
+ "User &",
+ "/nonexistent",
+ "/bin/sh",
+ 0,
+ 0
+};
+
+static int print_user(struct passwd *pwd, bool pretty, bool v7);
+static uid_t pw_uidpolicy(struct userconf *cnf, intmax_t id);
+static uid_t pw_gidpolicy(struct userconf *cnf, char *grname, char *nam,
+ gid_t prefer, bool dryrun);
+static char *pw_homepolicy(struct userconf * cnf, char *homedir,
+ const char *user);
+static char *pw_shellpolicy(struct userconf * cnf);
+static char *pw_password(struct userconf * cnf, char const * user,
+ bool dryrun);
+static char *shell_path(char const * path, char *shells[], char *sh);
+static void rmat(uid_t uid);
+static void rmopie(char const * name);
+
+static void
+mkdir_home_parents(int dfd, const char *dir)
+{
+ struct stat st;
+ char *dirs, *tmp;
+
+ if (*dir != '/')
+ errx(EX_DATAERR, "invalid base directory for home '%s'", dir);
+
+ dir++;
+
+ if (fstatat(dfd, dir, &st, 0) != -1) {
+ if (S_ISDIR(st.st_mode))
+ return;
+ errx(EX_OSFILE, "root home `/%s' is not a directory", dir);
+ }
+
+ dirs = strdup(dir);
+ if (dirs == NULL)
+ errx(EX_UNAVAILABLE, "out of memory");
+
+ tmp = strrchr(dirs, '/');
+ if (tmp == NULL) {
+ free(dirs);
+ return;
+ }
+ tmp[0] = '\0';
+
+ /*
+ * This is a kludge especially for Joerg :)
+ * If the home directory would be created in the root partition, then
+ * we really create it under /usr which is likely to have more space.
+ * But we create a symlink from cnf->home -> "/usr" -> cnf->home
+ */
+ if (strchr(dirs, '/') == NULL) {
+ asprintf(&tmp, "usr/%s", dirs);
+ if (tmp == NULL)
+ errx(EX_UNAVAILABLE, "out of memory");
+ if (mkdirat(dfd, tmp, _DEF_DIRMODE) != -1 || errno == EEXIST) {
+ fchownat(dfd, tmp, 0, 0, 0);
+ symlinkat(tmp, dfd, dirs);
+ }
+ free(tmp);
+ }
+ tmp = dirs;
+ if (fstatat(dfd, dirs, &st, 0) == -1) {
+ while ((tmp = strchr(tmp + 1, '/')) != NULL) {
+ *tmp = '\0';
+ if (fstatat(dfd, dirs, &st, 0) == -1) {
+ if (mkdirat(dfd, dirs, _DEF_DIRMODE) == -1)
+ err(EX_OSFILE, "'%s' (root home parent) is not a directory", dirs);
+ }
+ *tmp = '/';
+ }
+ }
+ if (fstatat(dfd, dirs, &st, 0) == -1) {
+ if (mkdirat(dfd, dirs, _DEF_DIRMODE) == -1)
+ err(EX_OSFILE, "'%s' (root home parent) is not a directory", dirs);
+ fchownat(dfd, dirs, 0, 0, 0);
+ }
+
+ free(dirs);
+}