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 ***
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to