Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 3 Jul 2015 14:22:45 +0000 (UTC)
From:      Baptiste Daroussin <bapt@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r285092 - in stable/10: share/mk usr.sbin/pw usr.sbin/pw/tests
Message-ID:  <201507031422.t63EMjx6044022@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bapt
Date: Fri Jul  3 14:22:44 2015
New Revision: 285092
URL: https://svnweb.freebsd.org/changeset/base/285092

Log:
  MFC: r274011,r274022,r274453,r274542,r274632,r274727,r275653,r275656,r275657,
       r275658,r275829,r277652,r277764,r278475,r278767,r278819,r278902,r279256,
       r282681,r282683,r282685,r282686,r282687,r282697,r282698,r282699,r282700,
       r282709,r282712,r282713,r282716,r282718,r282719,r282720,r282721,r283809,
       r283810,r283811,r283814,r283815,r283816,r283818,r283841,r283842,r283843,
       r283961,r283962,r284110,r284111,r284112,r284113,r284114,r284117,r284118,
       r284119,r284120,r284121,r284122,r284123,r284124,r284126,r284128,r284129,
       r284130,r284133,r284135,r284137,r284139,r284140,r284148,r284149,r284392
  
  Lots of cleanup in the pw(8) code
  Add pw -R <rootdir>
  Add lots of regression tests
  More accurate error messages
  
  Approved by:	re (kib)
  Sponsored by:	gandi.net

Added:
  stable/10/usr.sbin/pw/tests/pw-modified.conf
     - copied unchanged from r284137, head/usr.sbin/pw/tests/pw-modified.conf
  stable/10/usr.sbin/pw/tests/pw.conf
     - copied unchanged from r284135, head/usr.sbin/pw/tests/pw.conf
  stable/10/usr.sbin/pw/tests/pw_config.sh
     - copied, changed from r284135, head/usr.sbin/pw/tests/pw_config.sh
  stable/10/usr.sbin/pw/tests/pw_etcdir.sh
     - copied, changed from r274453, head/usr.sbin/pw/tests/pw_etcdir.sh
  stable/10/usr.sbin/pw/tests/pw_groupdel.sh
     - copied unchanged from r275656, head/usr.sbin/pw/tests/pw_groupdel.sh
  stable/10/usr.sbin/pw/tests/pw_groupmod.sh
     - copied, changed from r275656, head/usr.sbin/pw/tests/pw_groupmod.sh
  stable/10/usr.sbin/pw/tests/pw_lock.sh
     - copied, changed from r274542, head/usr.sbin/pw/tests/pw_lock.sh
  stable/10/usr.sbin/pw/tests/pw_useradd.sh
     - copied, changed from r275656, head/usr.sbin/pw/tests/pw_useradd.sh
  stable/10/usr.sbin/pw/tests/pw_userdel.sh
     - copied unchanged from r275656, head/usr.sbin/pw/tests/pw_userdel.sh
  stable/10/usr.sbin/pw/tests/pw_usermod.sh
     - copied, changed from r275657, head/usr.sbin/pw/tests/pw_usermod.sh
  stable/10/usr.sbin/pw/tests/pw_usernext.sh
     - copied, changed from r278475, head/usr.sbin/pw/tests/pw_usernext.sh
Deleted:
  stable/10/usr.sbin/pw/tests/pw_delete.sh
  stable/10/usr.sbin/pw/tests/pw_modify.sh
Modified:
  stable/10/share/mk/atf.test.mk
  stable/10/usr.sbin/pw/Makefile
  stable/10/usr.sbin/pw/fileupd.c
  stable/10/usr.sbin/pw/grupd.c
  stable/10/usr.sbin/pw/pw.8
  stable/10/usr.sbin/pw/pw.c
  stable/10/usr.sbin/pw/pw.h
  stable/10/usr.sbin/pw/pw_conf.c
  stable/10/usr.sbin/pw/pw_group.c
  stable/10/usr.sbin/pw/pw_nis.c
  stable/10/usr.sbin/pw/pw_user.c
  stable/10/usr.sbin/pw/pwupd.c
  stable/10/usr.sbin/pw/pwupd.h
  stable/10/usr.sbin/pw/tests/Makefile
  stable/10/usr.sbin/pw/tests/helper_functions.shin
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/share/mk/atf.test.mk
==============================================================================
--- stable/10/share/mk/atf.test.mk	Fri Jul  3 14:13:16 2015	(r285091)
+++ stable/10/share/mk/atf.test.mk	Fri Jul  3 14:22:44 2015	(r285092)
@@ -104,7 +104,7 @@ CLEANFILES+= ${_T} ${_T}.tmp
 ATF_TESTS_SH_SED_${_T}?= # empty
 ATF_TESTS_SH_SRC_${_T}?= ${_T}.sh
 ${_T}: ${ATF_TESTS_SH_SRC_${_T}}
-	echo '#! /usr/libexec/atf-sh' > ${.TARGET}.tmp
+	echo '#! /usr/bin/env atf-sh' > ${.TARGET}.tmp
 .if empty(ATF_TESTS_SH_SED_${_T})
 	cat ${.ALLSRC:N*Makefile*} >>${.TARGET}.tmp
 .else

Modified: stable/10/usr.sbin/pw/Makefile
==============================================================================
--- stable/10/usr.sbin/pw/Makefile	Fri Jul  3 14:13:16 2015	(r285091)
+++ stable/10/usr.sbin/pw/Makefile	Fri Jul  3 14:22:44 2015	(r285092)
@@ -8,10 +8,10 @@ SRCS=	pw.c pw_conf.c pw_user.c pw_group.
 	grupd.c pwupd.c fileupd.c psdate.c \
 	bitmap.c cpdir.c rm_r.c
 
-WARNS?=	2
+WARNS?=	3
 
-DPADD=	${LIBCRYPT} ${LIBUTIL}
-LDADD=	-lcrypt -lutil
+DPADD=	${LIBCRYPT} ${LIBUTIL} ${LIBSBUF}
+LDADD=	-lcrypt -lutil -lsbuf
 
 .if ${MK_TESTS} != "no"
 SUBDIR+=	tests

Modified: stable/10/usr.sbin/pw/fileupd.c
==============================================================================
--- stable/10/usr.sbin/pw/fileupd.c	Fri Jul  3 14:13:16 2015	(r285091)
+++ stable/10/usr.sbin/pw/fileupd.c	Fri Jul  3 14:22:44 2015	(r285092)
@@ -29,32 +29,11 @@ static const char rcsid[] =
   "$FreeBSD$";
 #endif /* not lint */
 
-#include <stdio.h>
-#include <fcntl.h>
 #include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <errno.h>
-#include <unistd.h>
 
 #include "pwupd.h"
 
 int
-extendline(char **buf, int * buflen, int needed)
-{
-	if (needed > *buflen) {
-		char	*tmp = realloc(*buf, needed);
-		if (tmp == NULL)
-			return -1;
-		*buf = tmp;
-		*buflen = needed;
-	}
-	return *buflen;
-}
-
-int
 extendarray(char ***buf, int * buflen, int needed)
 {
 	if (needed > *buflen) {

Modified: stable/10/usr.sbin/pw/grupd.c
==============================================================================
--- stable/10/usr.sbin/pw/grupd.c	Fri Jul  3 14:13:16 2015	(r285091)
+++ stable/10/usr.sbin/pw/grupd.c	Fri Jul  3 14:22:44 2015	(r285092)
@@ -35,36 +35,18 @@ static const char rcsid[] =
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <unistd.h>
-#include <stdarg.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <sys/param.h>
 
 #include "pwupd.h"
 
-static char * grpath = _PATH_PWD;
-
-int
-setgrdir(const char * dir)
-{
-	if (dir == NULL)
-		return -1;
-	else
-		grpath = strdup(dir);
-	if (grpath == NULL)
-		return -1;
-
-	return 0;
-}
-
 char *
 getgrpath(const char * file)
 {
 	static char pathbuf[MAXPATHLEN];
 
-	snprintf(pathbuf, sizeof pathbuf, "%s/%s", grpath, file);
-	return pathbuf;
+	snprintf(pathbuf, sizeof pathbuf, "%s/%s", conf.etcpath, file);
+
+	return (pathbuf);
 }
 
 static int
@@ -80,7 +62,7 @@ gr_update(struct group * grp, char const
 	if (group != NULL)
 		old_gr = GETGRNAM(group);
 
-	if (gr_init(grpath, NULL))
+	if (gr_init(conf.etcpath, NULL))
 		err(1, "gr_init()");
 
 	if ((pfd = gr_lock()) == -1) {
@@ -120,9 +102,6 @@ chggrent(char const * login, struct grou
 int
 delgrent(struct group * grp)
 {
-	char group[MAXLOGNAME];
-
-	strlcpy(group, grp->gr_name, MAXLOGNAME);
 
-	return gr_update(NULL, group);
+	return (gr_update(NULL, grp->gr_name));
 }

Modified: stable/10/usr.sbin/pw/pw.8
==============================================================================
--- stable/10/usr.sbin/pw/pw.8	Fri Jul  3 14:13:16 2015	(r285091)
+++ stable/10/usr.sbin/pw/pw.8	Fri Jul  3 14:22:44 2015	(r285092)
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd October 29, 2012
+.Dd June 14, 2015
 .Dt PW 8
 .Os
 .Sh NAME
@@ -32,6 +32,7 @@
 .Nd create, remove, modify & display system users and groups
 .Sh SYNOPSIS
 .Nm
+.Op Fl R Ar rootdir
 .Op Fl V Ar etcdir
 .Ar useradd
 .Op name|uid
@@ -57,6 +58,7 @@
 .Op Fl P
 .Op Fl Y
 .Nm
+.Op Fl R Ar rootdir
 .Op Fl V Ar etcdir
 .Ar useradd
 .Op name|uid
@@ -76,6 +78,7 @@
 .Op Fl s Ar shell
 .Op Fl y Ar path
 .Nm
+.Op Fl R Ar rootdir
 .Op Fl V Ar etcdir
 .Ar userdel
 .Op name|uid
@@ -84,6 +87,7 @@
 .Op Fl r
 .Op Fl Y
 .Nm
+.Op Fl R Ar rootdir
 .Op Fl V Ar etcdir
 .Ar usermod
 .Op name|uid
@@ -109,6 +113,7 @@
 .Op Fl P
 .Op Fl Y
 .Nm
+.Op Fl R Ar rootdir
 .Op Fl V Ar etcdir
 .Ar usershow
 .Op name|uid
@@ -119,11 +124,13 @@
 .Op Fl 7
 .Op Fl a
 .Nm
+.Op Fl R Ar rootdir
 .Op Fl V Ar etcdir
 .Ar usernext
 .Op Fl C Ar config
 .Op Fl q
 .Nm
+.Op Fl R Ar rootdir
 .Op Fl V Ar etcdir
 .Ar groupadd
 .Op group|gid
@@ -138,6 +145,7 @@
 .Op Fl P
 .Op Fl Y
 .Nm
+.Op Fl R Ar rootdir
 .Op Fl V Ar etcdir
 .Ar groupdel
 .Op group|gid
@@ -145,6 +153,7 @@
 .Op Fl g Ar gid
 .Op Fl Y
 .Nm
+.Op Fl R Ar rootdir
 .Op Fl V Ar etcdir
 .Ar groupmod
 .Op group|gid
@@ -161,6 +170,7 @@
 .Op Fl P
 .Op Fl Y
 .Nm
+.Op Fl R Ar rootdir
 .Op Fl V Ar etcdir
 .Ar groupshow
 .Op group|gid
@@ -170,17 +180,20 @@
 .Op Fl P
 .Op Fl a
 .Nm
+.Op Fl R Ar rootdir
 .Op Fl V Ar etcdir
 .Ar groupnext
 .Op Fl C Ar config
 .Op Fl q
 .Nm
+.Op Fl R Ar rootdir
 .Op Fl V Ar etcdir
 .Ar lock
 .Op name|uid
 .Op Fl C Ar config
 .Op Fl q
 .Nm
+.Op Fl R Ar rootdir
 .Op Fl V Ar etcdir
 .Ar unlock
 .Op name|uid
@@ -246,6 +259,12 @@ options.
 .Pp
 The following flags are common to most or all modes of operation:
 .Bl -tag -width "-G grouplist"
+.It Fl R Ar rootdir
+Specifies an alternate root directory within which
+.Nm
+will operate.
+Any paths specified will be relative to
+.Va rootdir .
 .It Fl V Ar etcdir
 This flag sets an alternate location for the password, group and configuration files,
 and may be used to maintain a user/group database in an alternate location.
@@ -259,7 +278,7 @@ flag may be used to override this behavi
 As an exception to the general rule where options must follow the operation
 type, the
 .Fl V
-flag may be used on the command line before the operation keyword.
+flag must be used on the command line before the operation keyword.
 .It Fl C Ar config
 By default,
 .Nm

Modified: stable/10/usr.sbin/pw/pw.c
==============================================================================
--- stable/10/usr.sbin/pw/pw.c	Fri Jul  3 14:13:16 2015	(r285091)
+++ stable/10/usr.sbin/pw/pw.c	Fri Jul  3 14:22:44 2015	(r285092)
@@ -33,6 +33,7 @@ static const char rcsid[] =
 #include <fcntl.h>
 #include <locale.h>
 #include <paths.h>
+#include <stdbool.h>
 #include <sys/wait.h>
 #include "pw.h"
 
@@ -56,7 +57,7 @@ static const char *Combo2[] = {
 
 struct pwf PWF =
 {
-	0,
+	PWF_REGULAR,
 	setpwent,
 	endpwent,
 	getpwent,
@@ -71,7 +72,7 @@ struct pwf PWF =
 };
 struct pwf VPWF =
 {
-	1,
+	PWF_ALT,
 	vsetpwent,
 	vendpwent,
 	vgetpwent,
@@ -84,6 +85,8 @@ struct pwf VPWF =
 	vgetgrnam,
 };
 
+struct pwconf conf;
+
 static struct cargs arglist;
 
 static int      getindex(const char *words[], const char *word);
@@ -96,35 +99,45 @@ main(int argc, char *argv[])
 	int             ch;
 	int             mode = -1;
 	int             which = -1;
+	long		id = -1;
 	char		*config = NULL;
-	struct userconf *cnf;
+	struct stat	st;
+	const char	*errstr;
+	char		arg, *name;
+	bool		relocated, nis;
 
 	static const char *opts[W_NUM][M_NUM] =
 	{
 		{ /* user */
-			"V:C:qn:u:c:d:e:p:g:G:mM:k:s:oL:i:w:h:H:Db:NPy:Y",
-			"V:C:qn:u:rY",
-			"V:C:qn:u:c:d:e:p:g:G:mM:l:k:s:w:L:h:H:FNPY",
-			"V:C:qn:u:FPa7",
-			"V:C:q",
-			"V:C:q",
-			"V:C:q"
+			"R:V:C:qn:u:c:d:e:p:g:G:mM:k:s:oL:i:w:h:H:Db:NPy:Y",
+			"R:V:C:qn:u:rY",
+			"R:V:C:qn:u:c:d:e:p:g:G:mM:l:k:s:w:L:h:H:FNPY",
+			"R:V:C:qn:u:FPa7",
+			"R:V:C:q",
+			"R:V:C:q",
+			"R:V:C:q"
 		},
 		{ /* grp  */
-			"V:C:qn:g:h:H:M:opNPY",
-			"V:C:qn:g:Y",
-			"V:C:qn:d:g:l:h:H:FM:m:NPY",
-			"V:C:qn:g:FPa",
-			"V:C:q"
+			"R:V:C:qn:g:h:H:M:opNPY",
+			"R:V:C:qn:g:Y",
+			"R:V:C:qn:d:g:l:h:H:FM:m:NPY",
+			"R:V:C:qn:g:FPa",
+			"R:V:C:q"
 		 }
 	};
 
-	static int      (*funcs[W_NUM]) (struct userconf * _cnf, int _mode, struct cargs * _args) =
+	static int      (*funcs[W_NUM]) (int _mode, char *_name, long _id,
+	    struct cargs * _args) =
 	{			/* Request handlers */
 		pw_user,
 		pw_group
 	};
 
+	name = NULL;
+	relocated = nis = false;
+	memset(&conf, 0, sizeof(conf));
+	strlcpy(conf.etcpath, _PATH_PWD, sizeof(conf.etcpath));
+
 	LIST_INIT(&arglist);
 
 	(void)setlocale(LC_ALL, "");
@@ -140,14 +153,33 @@ main(int argc, char *argv[])
 			/*
 			 * Special case, allow pw -V<dir> <operation> [args] for scripts etc.
 			 */
-			if (argv[1][1] == 'V') {
+			arg = argv[1][1];
+			if (arg == 'V' || arg == 'R') {
+				if (relocated)
+					errx(EXIT_FAILURE, "Both '-R' and '-V' "
+					    "specified, only one accepted");
+				relocated = true;
 				optarg = &argv[1][2];
 				if (*optarg == '\0') {
+					if (stat(argv[2], &st) != 0)
+						errx(EX_OSFILE, \
+						    "no such directory `%s'",
+						    argv[2]);
+					if (!S_ISDIR(st.st_mode))
+						errx(EX_OSFILE, "`%s' not a "
+						    "directory", argv[2]);
 					optarg = argv[2];
 					++argv;
 					--argc;
 				}
-				addarg(&arglist, 'V', optarg);
+				memcpy(&PWF, &VPWF, sizeof PWF);
+				if (arg == 'R') {
+					strlcpy(conf.rootdir, optarg,
+					    sizeof(conf.rootdir));
+					PWF._altdir = PWF_ROOTDIR;
+				}
+				snprintf(conf.etcpath, sizeof(conf.etcpath),
+				    "%s%s", optarg, arg == 'R' ? "/etc" : "");
 			} else
 				break;
 		}
@@ -162,9 +194,15 @@ main(int argc, char *argv[])
 			mode = tmp % M_NUM;
 		} else if (strcmp(argv[1], "help") == 0 && argv[2] == NULL)
 			cmdhelp(mode, which);
-		else if (which != -1 && mode != -1)
-			addarg(&arglist, 'n', argv[1]);
-		else
+		else if (which != -1 && mode != -1) {
+			if (strspn(argv[1], "0123456789") == strlen(argv[1])) {
+				id = strtonum(argv[1], 0, LONG_MAX, &errstr);
+				if (errstr != NULL)
+					errx(EX_USAGE, "Bad id '%s': %s",
+					    argv[1], errstr);
+			} else
+				name = argv[1];
+		} else
 			errx(EX_USAGE, "unknown keyword `%s'", argv[1]);
 		++argv;
 		--argc;
@@ -183,17 +221,82 @@ main(int argc, char *argv[])
 	optarg = NULL;
 
 	while ((ch = getopt(argc, argv, opts[which][mode])) != -1) {
-		if (ch == '?')
+		switch (ch) {
+		case '?':
 			errx(EX_USAGE, "unknown switch");
-		else
+			break;
+		case '7':
+			conf.v7 = true;
+			break;
+		case 'C':
+			conf.config = optarg;
+			config = conf.config;
+			break;
+		case 'N':
+			conf.dryrun = true;
+			break;
+		case 'l':
+			if (strlen(optarg) >= MAXLOGNAME)
+				errx(EX_USAGE, "new name too long: %s", optarg);
+			conf.newname = optarg;
+			break;
+		case 'P':
+			conf.pretty = true;
+			break;
+		case 'Y':
+			nis = true;
+			break;
+		case 'g':
+			if (which == 0) { /* for user* */
+				addarg(&arglist, 'g', optarg);
+				break;
+			}
+			if (strspn(optarg, "0123456789") != strlen(optarg))
+				errx(EX_USAGE, "-g expects a number");
+			id = strtonum(optarg, 0, LONG_MAX, &errstr);
+			if (errstr != NULL)
+				errx(EX_USAGE, "Bad id '%s': %s", optarg,
+				    errstr);
+			break;
+		case 'u':
+			if (strspn(optarg, "0123456789,") != strlen(optarg))
+				errx(EX_USAGE, "-u expects a number");
+			if (strchr(optarg, ',') != NULL) {
+				addarg(&arglist, 'u', optarg);
+				break;
+			}
+			id = strtonum(optarg, 0, LONG_MAX, &errstr);
+			if (errstr != NULL)
+				errx(EX_USAGE, "Bad id '%s': %s", optarg,
+				    errstr);
+			break;
+		case 'n':
+			if (strspn(optarg, "0123456789") != strlen(optarg)) {
+				name = optarg;
+				break;
+			}
+			id = strtonum(optarg, 0, LONG_MAX, &errstr);
+			if (errstr != NULL)
+				errx(EX_USAGE, "Bad id '%s': %s", optarg,
+				    errstr);
+			break;
+		case 'o':
+			conf.checkduplicate = true;
+			break;
+		default:
 			addarg(&arglist, ch, optarg);
+			break;
+		}
 		optarg = NULL;
 	}
 
+	if (name != NULL && strlen(name) >= MAXLOGNAME)
+		errx(EX_USAGE, "name too long: %s", name);
+
 	/*
 	 * Must be root to attempt an update
 	 */
-	if (geteuid() != 0 && mode != M_PRINT && mode != M_NEXT && getarg(&arglist, 'N')==NULL)
+	if (geteuid() != 0 && mode != M_PRINT && mode != M_NEXT && !conf.dryrun)
 		errx(EX_NOPERM, "you must be root to run this program");
 
 	/*
@@ -207,33 +310,24 @@ main(int argc, char *argv[])
 	 * Set our base working path if not overridden
 	 */
 
-	config = getarg(&arglist, 'C') ? getarg(&arglist, 'C')->val : NULL;
-
-	if (getarg(&arglist, 'V') != NULL) {
-		char * etcpath = getarg(&arglist, 'V')->val;
-		if (*etcpath) {
-			if (config == NULL) {	/* Only override config location if -C not specified */
-				config = malloc(MAXPATHLEN);
-				snprintf(config, MAXPATHLEN, "%s/pw.conf", etcpath);
-			}
-			memcpy(&PWF, &VPWF, sizeof PWF);
-			setpwdir(etcpath);
-			setgrdir(etcpath);
-		}
+	if (config == NULL) {	/* Only override config location if -C not specified */
+		asprintf(&config, "%s/pw.conf", conf.etcpath);
+		if (config == NULL)
+			errx(EX_OSERR, "out of memory");
 	}
 
 	/*
 	 * Now, let's do the common initialisation
 	 */
-	cnf = read_userconfig(config);
+	conf.userconf = read_userconfig(config);
 
-	ch = funcs[which] (cnf, mode, &arglist);
+	ch = funcs[which] (mode, name, id, &arglist);
 
 	/*
 	 * If everything went ok, and we've been asked to update
 	 * the NIS maps, then do it now
 	 */
-	if (ch == EXIT_SUCCESS && getarg(&arglist, 'Y') != NULL) {
+	if (ch == EXIT_SUCCESS && nis) {
 		pid_t	pid;
 
 		fflush(NULL);
@@ -251,7 +345,7 @@ main(int argc, char *argv[])
 			if ((i = WEXITSTATUS(i)) != 0)
 				errx(ch, "make exited with status %d", i);
 			else
-				pw_log(cnf, mode, which, "NIS maps updated");
+				pw_log(conf.userconf, mode, which, "NIS maps updated");
 		}
 	}
 	return ch;
@@ -294,6 +388,7 @@ cmdhelp(int mode, int which)
 			{
 				"usage: pw useradd [name] [switches]\n"
 				"\t-V etcdir      alternate /etc location\n"
+				"\t-R rootir      alternate root directory\n"
 				"\t-C config      configuration file\n"
 				"\t-q             quiet operation\n"
 				"  Adding users:\n"
@@ -316,6 +411,7 @@ cmdhelp(int mode, int which)
 				"\t-N             no update\n"
 				"  Setting defaults:\n"
 				"\t-V etcdir      alternate /etc location\n"
+				"\t-R rootir      alternate root directory\n"
 			        "\t-D             set user defaults\n"
 				"\t-b dir         default home root dir\n"
 				"\t-e period      default expiry period\n"
@@ -332,12 +428,14 @@ cmdhelp(int mode, int which)
 				"\t-y path        set NIS passwd file path\n",
 				"usage: pw userdel [uid|name] [switches]\n"
 				"\t-V etcdir      alternate /etc location\n"
+				"\t-R rootir      alternate root directory\n"
 				"\t-n name        login name\n"
 				"\t-u uid         user id\n"
 				"\t-Y             update NIS maps\n"
 				"\t-r             remove home & contents\n",
 				"usage: pw usermod [uid|name] [switches]\n"
 				"\t-V etcdir      alternate /etc location\n"
+				"\t-R rootir      alternate root directory\n"
 				"\t-C config      configuration file\n"
 				"\t-q             quiet operation\n"
 				"\t-F             force add if no user\n"
@@ -361,6 +459,7 @@ cmdhelp(int mode, int which)
 				"\t-N             no update\n",
 				"usage: pw usershow [uid|name] [switches]\n"
 				"\t-V etcdir      alternate /etc location\n"
+				"\t-R rootir      alternate root directory\n"
 				"\t-n name        login name\n"
 				"\t-u uid         user id\n"
 				"\t-F             force print\n"
@@ -369,6 +468,7 @@ cmdhelp(int mode, int which)
 				"\t-7             print in v7 format\n",
 				"usage: pw usernext [switches]\n"
 				"\t-V etcdir      alternate /etc location\n"
+				"\t-R rootir      alternate root directory\n"
 				"\t-C config      configuration file\n"
 				"\t-q             quiet operation\n",
 				"usage pw: lock [switches]\n"
@@ -383,6 +483,7 @@ cmdhelp(int mode, int which)
 			{
 				"usage: pw groupadd [group|gid] [switches]\n"
 				"\t-V etcdir      alternate /etc location\n"
+				"\t-R rootir      alternate root directory\n"
 				"\t-C config      configuration file\n"
 				"\t-q             quiet operation\n"
 				"\t-n group       group name\n"
@@ -393,11 +494,13 @@ cmdhelp(int mode, int which)
 				"\t-N             no update\n",
 				"usage: pw groupdel [group|gid] [switches]\n"
 				"\t-V etcdir      alternate /etc location\n"
+				"\t-R rootir      alternate root directory\n"
 				"\t-n name        group name\n"
 				"\t-g gid         group id\n"
 				"\t-Y             update NIS maps\n",
 				"usage: pw groupmod [group|gid] [switches]\n"
 				"\t-V etcdir      alternate /etc location\n"
+				"\t-R rootir      alternate root directory\n"
 				"\t-C config      configuration file\n"
 				"\t-q             quiet operation\n"
 				"\t-F             force add if not exists\n"
@@ -411,6 +514,7 @@ cmdhelp(int mode, int which)
 				"\t-N             no update\n",
 				"usage: pw groupshow [group|gid] [switches]\n"
 				"\t-V etcdir      alternate /etc location\n"
+				"\t-R rootir      alternate root directory\n"
 				"\t-n name        group name\n"
 				"\t-g gid         group id\n"
 				"\t-F             force print\n"
@@ -418,6 +522,7 @@ cmdhelp(int mode, int which)
 				"\t-a             print all accounting groups\n",
 				"usage: pw groupnext [switches]\n"
 				"\t-V etcdir      alternate /etc location\n"
+				"\t-R rootir      alternate root directory\n"
 				"\t-C config      configuration file\n"
 				"\t-q             quiet operation\n"
 			}

Modified: stable/10/usr.sbin/pw/pw.h
==============================================================================
--- stable/10/usr.sbin/pw/pw.h	Fri Jul  3 14:13:16 2015	(r285091)
+++ stable/10/usr.sbin/pw/pw.h	Fri Jul  3 14:22:44 2015	(r285092)
@@ -72,30 +72,6 @@ struct carg
 
 LIST_HEAD(cargs, carg);
 
-struct userconf
-{
-	int	default_password;	/* Default password for new users? */
-	int	reuse_uids;		/* Reuse uids? */
-	int	reuse_gids;		/* Reuse gids? */
-	char	*nispasswd;		/* Path to NIS version of the passwd file */
-	char	*dotdir;		/* Where to obtain skeleton files */
-	char	*newmail;		/* Mail to send to new accounts */
-	char	*logfile;		/* Where to log changes */
-	char	*home;			/* Where to create home directory */
-	mode_t	homemode;		/* Home directory permissions */
-	char	*shelldir;		/* Where shells are located */
-	char	**shells;		/* List of shells */
-	char	*shell_default;		/* Default shell */
-	char	*default_group;		/* Default group number */
-	char	**groups;		/* Default (additional) groups */
-	char	*default_class;		/* Default user class */
-	uid_t	min_uid, max_uid;	/* Allowed range of uids */
-	gid_t	min_gid, max_gid;	/* Allowed range of gids */
-	int	expire_days;		/* Days to expiry */
-	int	password_days;		/* Days to password expiry */
-	int	numgroups;		/* (internal) size of default_group array */
-};
-
 #define	_DEF_DIRMODE	(S_IRWXU | S_IRWXG | S_IRWXO)
 #define _PATH_PW_CONF	"/etc/pw.conf"
 #define _UC_MAXLINE	1024
@@ -106,9 +82,9 @@ int write_userconfig(char const * file);
 struct carg *addarg(struct cargs * _args, int ch, char *argstr);
 struct carg *getarg(struct cargs * _args, int ch);
 
-int pw_user(struct userconf * cnf, int mode, struct cargs * _args);
-int pw_group(struct userconf * cnf, int mode, struct cargs * _args);
-char    *pw_checkname(u_char *name, int gecos);
+int pw_user(int mode, char *name, long id, struct cargs * _args);
+int pw_group(int mode, char *name, long id,  struct cargs * _args);
+char *pw_checkname(char *name, int gecos);
 
 int addnispwent(const char *path, struct passwd *pwd);
 int delnispwent(const char *path, const char *login);

Modified: stable/10/usr.sbin/pw/pw_conf.c
==============================================================================
--- stable/10/usr.sbin/pw/pw_conf.c	Fri Jul  3 14:13:16 2015	(r285091)
+++ stable/10/usr.sbin/pw/pw_conf.c	Fri Jul  3 14:22:44 2015	(r285092)
@@ -29,9 +29,12 @@ static const char rcsid[] =
   "$FreeBSD$";
 #endif /* not lint */
 
+#include <sys/types.h>
+#include <sys/sbuf.h>
 #include <string.h>
 #include <ctype.h>
 #include <fcntl.h>
+#include <err.h>
 
 #include "pw.h"
 
@@ -209,19 +212,16 @@ boolean_str(int val)
 char           *
 newstr(char const * p)
 {
-	char           *q = NULL;
+	char	*q;
 
-	if ((p = unquote(p)) != NULL) {
-		int             l = strlen(p) + 1;
+	if ((p = unquote(p)) == NULL)
+		return (NULL);
 
-		if ((q = malloc(l)) != NULL)
-			memcpy(q, p, l);
-	}
-	return q;
-}
-
-#define LNBUFSZ 1024
+	if ((q = strdup(p)) == NULL)
+		err(1, "strdup()");
 
+	return (q);
+}
 
 struct userconf *
 read_userconfig(char const * file)
@@ -234,131 +234,134 @@ read_userconfig(char const * file)
 	buf = NULL;
 	linecap = 0;
 
-	extendarray(&config.groups, &config.numgroups, 200);
-	memset(config.groups, 0, config.numgroups * sizeof(char *));
+	config.numgroups = 200;
+	config.groups = calloc(config.numgroups, sizeof(char *));
+	if (config.groups == NULL)
+		err(1, "calloc()");
 	if (file == NULL)
 		file = _PATH_PW_CONF;
 
-	if ((fp = fopen(file, "r")) != NULL) {
-		while ((linelen = getline(&buf, &linecap, fp)) > 0) {
-			if (*buf && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') {
-				static char const toks[] = " \t\r\n,=";
-				char           *q = strtok(NULL, toks);
-				int             i = 0;
-				mode_t          *modeset;
+	if ((fp = fopen(file, "r")) == NULL)
+		return (&config);
+
+	while ((linelen = getline(&buf, &linecap, fp)) > 0) {
+		if (*buf && (p = strtok(buf, " \t\r\n=")) != NULL && *p != '#') {
+			static char const toks[] = " \t\r\n,=";
+			char           *q = strtok(NULL, toks);
+			int             i = 0;
+			mode_t          *modeset;
 
-				while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0)
-					++i;
+			while (i < _UC_FIELDS && strcmp(p, kwds[i]) != 0)
+				++i;
 #if debugging
-				if (i == _UC_FIELDS)
-					printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : "");
-				else
-					printf("Got kwd[%s]=%s\n", p, q);
+			if (i == _UC_FIELDS)
+				printf("Got unknown kwd `%s' val=`%s'\n", p, q ? q : "");
+			else
+				printf("Got kwd[%s]=%s\n", p, q);
 #endif
-				switch (i) {
-				case _UC_DEFAULTPWD:
-					config.default_password = boolean_val(q, 1);
-					break;
-				case _UC_REUSEUID:
-					config.reuse_uids = boolean_val(q, 0);
-					break;
-				case _UC_REUSEGID:
-					config.reuse_gids = boolean_val(q, 0);
-					break;
-				case _UC_NISPASSWD:
-					config.nispasswd = (q == NULL || !boolean_val(q, 1))
-						? NULL : newstr(q);
-					break;
-				case _UC_DOTDIR:
-					config.dotdir = (q == NULL || !boolean_val(q, 1))
-						? NULL : newstr(q);
-					break;
+			switch (i) {
+			case _UC_DEFAULTPWD:
+				config.default_password = boolean_val(q, 1);
+				break;
+			case _UC_REUSEUID:
+				config.reuse_uids = boolean_val(q, 0);
+				break;
+			case _UC_REUSEGID:
+				config.reuse_gids = boolean_val(q, 0);
+				break;
+			case _UC_NISPASSWD:
+				config.nispasswd = (q == NULL || !boolean_val(q, 1))
+					? NULL : newstr(q);
+				break;
+			case _UC_DOTDIR:
+				config.dotdir = (q == NULL || !boolean_val(q, 1))
+					? NULL : newstr(q);
+				break;
 				case _UC_NEWMAIL:
-					config.newmail = (q == NULL || !boolean_val(q, 1))
-						? NULL : newstr(q);
-					break;
-				case _UC_LOGFILE:
-					config.logfile = (q == NULL || !boolean_val(q, 1))
-						? NULL : newstr(q);
-					break;
-				case _UC_HOMEROOT:
-					config.home = (q == NULL || !boolean_val(q, 1))
-						? "/home" : newstr(q);
-					break;
-				case _UC_HOMEMODE:
-					modeset = setmode(q);
-					config.homemode = (q == NULL || !boolean_val(q, 1))
-						? _DEF_DIRMODE : getmode(modeset, _DEF_DIRMODE);
-					free(modeset);
-					break;
-				case _UC_SHELLPATH:
-					config.shelldir = (q == NULL || !boolean_val(q, 1))
-						? "/bin" : newstr(q);
-					break;
-				case _UC_SHELLS:
-					for (i = 0; i < _UC_MAXSHELLS && q != NULL; i++, q = strtok(NULL, toks))
-						system_shells[i] = newstr(q);
-					if (i > 0)
-						while (i < _UC_MAXSHELLS)
-							system_shells[i++] = NULL;
-					break;
-				case _UC_DEFAULTSHELL:
-					config.shell_default = (q == NULL || !boolean_val(q, 1))
-						? (char *) bourne_shell : newstr(q);
-					break;
-				case _UC_DEFAULTGROUP:
-					q = unquote(q);
-					config.default_group = (q == NULL || !boolean_val(q, 1) || GETGRNAM(q) == NULL)
-						? NULL : newstr(q);
-					break;
-				case _UC_EXTRAGROUPS:
-					for (i = 0; q != NULL; q = strtok(NULL, toks)) {
-						if (extendarray(&config.groups, &config.numgroups, i + 2) != -1)
-							config.groups[i++] = newstr(q);
-					}
-					if (i > 0)
-						while (i < config.numgroups)
-							config.groups[i++] = NULL;
-					break;
-				case _UC_DEFAULTCLASS:
-					config.default_class = (q == NULL || !boolean_val(q, 1))
-						? NULL : newstr(q);
-					break;
-				case _UC_MINUID:
-					if ((q = unquote(q)) != NULL && isdigit(*q))
-						config.min_uid = (uid_t) atol(q);
-					break;
-				case _UC_MAXUID:
-					if ((q = unquote(q)) != NULL && isdigit(*q))
-						config.max_uid = (uid_t) atol(q);
-					break;
-				case _UC_MINGID:
-					if ((q = unquote(q)) != NULL && isdigit(*q))
-						config.min_gid = (gid_t) atol(q);
-					break;
-				case _UC_MAXGID:
-					if ((q = unquote(q)) != NULL && isdigit(*q))
-						config.max_gid = (gid_t) atol(q);
-					break;
-				case _UC_EXPIRE:
-					if ((q = unquote(q)) != NULL && isdigit(*q))
-						config.expire_days = atoi(q);
-					break;
-				case _UC_PASSWORD:
-					if ((q = unquote(q)) != NULL && isdigit(*q))
-						config.password_days = atoi(q);
-					break;
-				case _UC_FIELDS:
-				case _UC_NONE:
-					break;
+				config.newmail = (q == NULL || !boolean_val(q, 1))
+					? NULL : newstr(q);
+				break;
+			case _UC_LOGFILE:
+				config.logfile = (q == NULL || !boolean_val(q, 1))
+					? NULL : newstr(q);
+				break;
+			case _UC_HOMEROOT:
+				config.home = (q == NULL || !boolean_val(q, 1))
+					? "/home" : newstr(q);
+				break;
+			case _UC_HOMEMODE:
+				modeset = setmode(q);
+				config.homemode = (q == NULL || !boolean_val(q, 1))
+					? _DEF_DIRMODE : getmode(modeset, _DEF_DIRMODE);
+				free(modeset);
+				break;
+			case _UC_SHELLPATH:
+				config.shelldir = (q == NULL || !boolean_val(q, 1))
+					? "/bin" : newstr(q);
+				break;
+			case _UC_SHELLS:
+				for (i = 0; i < _UC_MAXSHELLS && q != NULL; i++, q = strtok(NULL, toks))
+					system_shells[i] = newstr(q);
+				if (i > 0)
+					while (i < _UC_MAXSHELLS)
+						system_shells[i++] = NULL;
+				break;
+			case _UC_DEFAULTSHELL:
+				config.shell_default = (q == NULL || !boolean_val(q, 1))
+					? (char *) bourne_shell : newstr(q);
+				break;
+			case _UC_DEFAULTGROUP:
+				q = unquote(q);
+				config.default_group = (q == NULL || !boolean_val(q, 1) || GETGRNAM(q) == NULL)
+					? NULL : newstr(q);
+				break;
+			case _UC_EXTRAGROUPS:
+				for (i = 0; q != NULL; q = strtok(NULL, toks)) {
+					if (extendarray(&config.groups, &config.numgroups, i + 2) != -1)
+						config.groups[i++] = newstr(q);
 				}
+				if (i > 0)
+					while (i < config.numgroups)
+						config.groups[i++] = NULL;
+				break;
+			case _UC_DEFAULTCLASS:
+				config.default_class = (q == NULL || !boolean_val(q, 1))
+					? NULL : newstr(q);
+				break;
+			case _UC_MINUID:
+				if ((q = unquote(q)) != NULL && isdigit(*q))
+					config.min_uid = (uid_t) atol(q);
+				break;
+			case _UC_MAXUID:
+				if ((q = unquote(q)) != NULL && isdigit(*q))
+					config.max_uid = (uid_t) atol(q);
+				break;
+			case _UC_MINGID:
+				if ((q = unquote(q)) != NULL && isdigit(*q))
+					config.min_gid = (gid_t) atol(q);
+				break;
+			case _UC_MAXGID:
+				if ((q = unquote(q)) != NULL && isdigit(*q))
+					config.max_gid = (gid_t) atol(q);
+				break;
+			case _UC_EXPIRE:
+				if ((q = unquote(q)) != NULL && isdigit(*q))
+					config.expire_days = atoi(q);
+				break;
+			case _UC_PASSWORD:
+				if ((q = unquote(q)) != NULL && isdigit(*q))
+					config.password_days = atoi(q);
+				break;
+			case _UC_FIELDS:
+			case _UC_NONE:
+				break;
 			}
 		}
-		if (linecap > 0)
-			free(buf);
-		fclose(fp);
 	}
-	return &config;
+	free(buf);
+	fclose(fp);
+
+	return (&config);
 }
 
 
@@ -366,138 +369,132 @@ int
 write_userconfig(char const * file)
 {
 	int             fd;
+	int             i, j;
+	struct sbuf	*buf;
+	FILE           *fp;
 
 	if (file == NULL)
 		file = _PATH_PW_CONF;
 
-	if ((fd = open(file, O_CREAT | O_RDWR | O_TRUNC | O_EXLOCK, 0644)) != -1) {
-		FILE           *fp;
+	if ((fd = open(file, O_CREAT|O_RDWR|O_TRUNC|O_EXLOCK, 0644)) == -1)
+		return (0);
 
-		if ((fp = fdopen(fd, "w")) == NULL)
-			close(fd);
-		else {
-			int             i, j, k;
-			int		len = LNBUFSZ;
-			char           *buf = malloc(len);
-
-			for (i = _UC_NONE; i < _UC_FIELDS; i++) {
-				int             quote = 1;
-				char const     *val = buf;
-
-				*buf = '\0';
-				switch (i) {
-				case _UC_DEFAULTPWD:
-					val = boolean_str(config.default_password);
-					break;
-				case _UC_REUSEUID:
-					val = boolean_str(config.reuse_uids);

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201507031422.t63EMjx6044022>