xref: /freebsd/usr.sbin/pw/pw.c (revision e3921b2795b59e386edaf3f2498f05facd87e054)
1d6f907dcSJoerg Wunsch /*-
2ad7cf975SJoerg Wunsch  * Copyright (C) 1996
3ad7cf975SJoerg Wunsch  *	David L. Nugent.  All rights reserved.
4d6f907dcSJoerg Wunsch  *
5d6f907dcSJoerg Wunsch  * Redistribution and use in source and binary forms, with or without
6d6f907dcSJoerg Wunsch  * modification, are permitted provided that the following conditions
7d6f907dcSJoerg Wunsch  * are met:
8d6f907dcSJoerg Wunsch  * 1. Redistributions of source code must retain the above copyright
9ad7cf975SJoerg Wunsch  *    notice, this list of conditions and the following disclaimer.
10d6f907dcSJoerg Wunsch  * 2. Redistributions in binary form must reproduce the above copyright
11d6f907dcSJoerg Wunsch  *    notice, this list of conditions and the following disclaimer in the
12d6f907dcSJoerg Wunsch  *    documentation and/or other materials provided with the distribution.
13d6f907dcSJoerg Wunsch  *
14ad7cf975SJoerg Wunsch  * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND
15d6f907dcSJoerg Wunsch  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16d6f907dcSJoerg Wunsch  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17ad7cf975SJoerg Wunsch  * ARE DISCLAIMED.  IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE
18d6f907dcSJoerg Wunsch  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19d6f907dcSJoerg Wunsch  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20d6f907dcSJoerg Wunsch  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21d6f907dcSJoerg Wunsch  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22d6f907dcSJoerg Wunsch  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23d6f907dcSJoerg Wunsch  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24d6f907dcSJoerg Wunsch  * SUCH DAMAGE.
25d6f907dcSJoerg Wunsch  */
26d6f907dcSJoerg Wunsch 
271dcc6ec7SPhilippe Charnier #ifndef lint
281dcc6ec7SPhilippe Charnier static const char rcsid[] =
29e3921b27SDavid Nugent 	"$Id: pw.c,v 1.12 1999/02/23 07:15:10 davidn Exp $";
301dcc6ec7SPhilippe Charnier #endif /* not lint */
311dcc6ec7SPhilippe Charnier 
321dcc6ec7SPhilippe Charnier #include <err.h>
335e91a8acSNate Williams #include <fcntl.h>
34f1d684faSDavid Nugent #include <paths.h>
35f1d684faSDavid Nugent #include <sys/wait.h>
365f12594aSDavid Nugent #include "pw.h"
37d6f907dcSJoerg Wunsch 
3848aee7f3SJoerg Wunsch const char     *Modes[] = {"add", "del", "mod", "show", "next", NULL};
39d6f907dcSJoerg Wunsch const char     *Which[] = {"user", "group", NULL};
4048aee7f3SJoerg Wunsch static const char *Combo1[] = {
4148aee7f3SJoerg Wunsch   "useradd", "userdel", "usermod", "usershow", "usernext",
4248aee7f3SJoerg Wunsch   "groupadd", "groupdel", "groupmod", "groupshow", "groupnext",
43d6f907dcSJoerg Wunsch   NULL};
4448aee7f3SJoerg Wunsch static const char *Combo2[] = {
4548aee7f3SJoerg Wunsch   "adduser", "deluser", "moduser", "showuser", "nextuser",
4648aee7f3SJoerg Wunsch   "addgroup", "delgroup", "modgroup", "showgroup", "nextgroup",
47d6f907dcSJoerg Wunsch NULL};
48d6f907dcSJoerg Wunsch 
495f12594aSDavid Nugent struct pwf PWF =
505f12594aSDavid Nugent {
515f12594aSDavid Nugent 	0,
525f12594aSDavid Nugent 	setpwent,
535f12594aSDavid Nugent 	endpwent,
545f12594aSDavid Nugent 	getpwent,
555f12594aSDavid Nugent 	getpwuid,
565f12594aSDavid Nugent 	getpwnam,
575f12594aSDavid Nugent 	pwdb,
585f12594aSDavid Nugent 	setgrent,
595f12594aSDavid Nugent 	endgrent,
605f12594aSDavid Nugent 	getgrent,
615f12594aSDavid Nugent 	getgrgid,
625f12594aSDavid Nugent 	getgrnam,
635f12594aSDavid Nugent 	grdb
645f12594aSDavid Nugent 
655f12594aSDavid Nugent };
665f12594aSDavid Nugent struct pwf VPWF =
675f12594aSDavid Nugent {
685f12594aSDavid Nugent 	1,
695f12594aSDavid Nugent 	vsetpwent,
705f12594aSDavid Nugent 	vendpwent,
715f12594aSDavid Nugent 	vgetpwent,
725f12594aSDavid Nugent 	vgetpwuid,
735f12594aSDavid Nugent 	vgetpwnam,
745f12594aSDavid Nugent 	vpwdb,
755f12594aSDavid Nugent 	vsetgrent,
765f12594aSDavid Nugent 	vendgrent,
775f12594aSDavid Nugent 	vgetgrent,
785f12594aSDavid Nugent 	vgetgrgid,
795f12594aSDavid Nugent 	vgetgrnam,
805f12594aSDavid Nugent 	vgrdb
815f12594aSDavid Nugent };
825f12594aSDavid Nugent 
83d6f907dcSJoerg Wunsch static struct cargs arglist;
84d6f907dcSJoerg Wunsch 
85d6f907dcSJoerg Wunsch static int      getindex(const char *words[], const char *word);
86d6f907dcSJoerg Wunsch static void     cmdhelp(int mode, int which);
87d6f907dcSJoerg Wunsch 
88d6f907dcSJoerg Wunsch 
89d6f907dcSJoerg Wunsch int
90d6f907dcSJoerg Wunsch main(int argc, char *argv[])
91d6f907dcSJoerg Wunsch {
92d6f907dcSJoerg Wunsch 	int             ch;
93d6f907dcSJoerg Wunsch 	int             mode = -1;
94d6f907dcSJoerg Wunsch 	int             which = -1;
955f12594aSDavid Nugent 	char		*config = NULL;
96d6f907dcSJoerg Wunsch 	struct userconf *cnf;
97d6f907dcSJoerg Wunsch 
98d6f907dcSJoerg Wunsch 	static const char *opts[W_NUM][M_NUM] =
99d6f907dcSJoerg Wunsch 	{
10048aee7f3SJoerg Wunsch 		{ /* user */
101e3921b27SDavid Nugent 			"V:C:qn:u:c:d:e:p:g:G:mk:s:oL:i:w:h:Db:NPy:Y",
102e3921b27SDavid Nugent 			"V:C:qn:u:rY",
103e3921b27SDavid Nugent 			"V:C:qn:u:c:d:e:p:g:G:ml:k:s:w:L:h:FNPY",
104e3921b27SDavid Nugent 			"V:C:qn:u:FPa",
105e3921b27SDavid Nugent 			"V:C:q"
10648aee7f3SJoerg Wunsch 		},
10748aee7f3SJoerg Wunsch 		{ /* grp  */
108e3921b27SDavid Nugent 			"V:C:qn:g:h:M:pNPY",
109e3921b27SDavid Nugent 			"V:C:qn:g:Y",
110e3921b27SDavid Nugent 			"V:C:qn:g:l:h:FM:m:NPY",
111e3921b27SDavid Nugent 			"V:C:qn:g:FPa",
112e3921b27SDavid Nugent 			"V:C:q"
11348aee7f3SJoerg Wunsch 		 }
114d6f907dcSJoerg Wunsch 	};
115d6f907dcSJoerg Wunsch 
116d6f907dcSJoerg Wunsch 	static int      (*funcs[W_NUM]) (struct userconf * _cnf, int _mode, struct cargs * _args) =
117d6f907dcSJoerg Wunsch 	{			/* Request handlers */
118d6f907dcSJoerg Wunsch 		pw_user,
119d6f907dcSJoerg Wunsch 		pw_group
120d6f907dcSJoerg Wunsch 	};
121d6f907dcSJoerg Wunsch 
122d6f907dcSJoerg Wunsch 	umask(0);		/* We wish to handle this manually */
123d6f907dcSJoerg Wunsch 	LIST_INIT(&arglist);
124d6f907dcSJoerg Wunsch 
125d6f907dcSJoerg Wunsch 	/*
126d6f907dcSJoerg Wunsch 	 * Break off the first couple of words to determine what exactly
127d6f907dcSJoerg Wunsch 	 * we're being asked to do
128d6f907dcSJoerg Wunsch 	 */
1295f12594aSDavid Nugent 	while (argc > 1) {
130d6f907dcSJoerg Wunsch 		int             tmp;
131d6f907dcSJoerg Wunsch 
1325f12594aSDavid Nugent 		if (*argv[1] == '-') {
1335f12594aSDavid Nugent 			/*
1345f12594aSDavid Nugent 			 * Special case, allow pw -V<dir> <operation> [args] for scripts etc.
1355f12594aSDavid Nugent 			 */
1365f12594aSDavid Nugent 			if (argv[1][1] == 'V') {
1375f12594aSDavid Nugent 				optarg = &argv[1][2];
1385f12594aSDavid Nugent 				if (*optarg == '\0') {
1395f12594aSDavid Nugent 					optarg = argv[2];
1405f12594aSDavid Nugent 					++argv;
1415f12594aSDavid Nugent 					--argc;
1425f12594aSDavid Nugent 				}
1435f12594aSDavid Nugent 				addarg(&arglist, 'V', optarg);
144e3921b27SDavid Nugent 			} else
1455f12594aSDavid Nugent 				break;
1465f12594aSDavid Nugent 		}
1475f12594aSDavid Nugent 		else if ((tmp = getindex(Modes, argv[1])) != -1)
148d6f907dcSJoerg Wunsch 			mode = tmp;
149d6f907dcSJoerg Wunsch 		else if ((tmp = getindex(Which, argv[1])) != -1)
150d6f907dcSJoerg Wunsch 			which = tmp;
151d6f907dcSJoerg Wunsch 		else if ((tmp = getindex(Combo1, argv[1])) != -1 || (tmp = getindex(Combo2, argv[1])) != -1) {
152d6f907dcSJoerg Wunsch 			which = tmp / M_NUM;
153d6f907dcSJoerg Wunsch 			mode = tmp % M_NUM;
154d6f907dcSJoerg Wunsch 		} else if (strcmp(argv[1], "help") == 0)
155d6f907dcSJoerg Wunsch 			cmdhelp(mode, which);
156d6f907dcSJoerg Wunsch 		else if (which != -1 && mode != -1 && arglist.lh_first == NULL)
157d6f907dcSJoerg Wunsch 			addarg(&arglist, 'n', argv[1]);
158d6f907dcSJoerg Wunsch 		else
1591dcc6ec7SPhilippe Charnier 			errx(EX_USAGE, "unknown keyword `%s'", argv[1]);
160d6f907dcSJoerg Wunsch 		++argv;
161d6f907dcSJoerg Wunsch 		--argc;
162d6f907dcSJoerg Wunsch 	}
163d6f907dcSJoerg Wunsch 
164d6f907dcSJoerg Wunsch 	/*
165d6f907dcSJoerg Wunsch 	 * Bail out unless the user is specific!
166d6f907dcSJoerg Wunsch 	 */
167d6f907dcSJoerg Wunsch 	if (mode == -1 || which == -1)
168d6f907dcSJoerg Wunsch 		cmdhelp(mode, which);
169d6f907dcSJoerg Wunsch 
170d6f907dcSJoerg Wunsch 	/*
171d6f907dcSJoerg Wunsch 	 * We know which mode we're in and what we're about to do, so now
172d6f907dcSJoerg Wunsch 	 * let's dispatch the remaining command line args in a genric way.
173d6f907dcSJoerg Wunsch 	 */
174d6f907dcSJoerg Wunsch 	optarg = NULL;
175d6f907dcSJoerg Wunsch 
176d6f907dcSJoerg Wunsch 	while ((ch = getopt(argc, argv, opts[which][mode])) != -1) {
177d6f907dcSJoerg Wunsch 		if (ch == '?')
1781dcc6ec7SPhilippe Charnier 			errx(EX_USAGE, NULL);
179d6f907dcSJoerg Wunsch 		else
180d6f907dcSJoerg Wunsch 			addarg(&arglist, ch, optarg);
181d6f907dcSJoerg Wunsch 		optarg = NULL;
182d6f907dcSJoerg Wunsch 	}
183d6f907dcSJoerg Wunsch 
184d6f907dcSJoerg Wunsch 	/*
18548aee7f3SJoerg Wunsch 	 * Must be root to attempt an update
18648aee7f3SJoerg Wunsch 	 */
187fa7e83d4SDavid Nugent 	if (geteuid() != 0 && mode != M_PRINT && mode != M_NEXT && getarg(&arglist, 'N')==NULL)
1881dcc6ec7SPhilippe Charnier 		errx(EX_NOPERM, "you must be root to run this program");
18948aee7f3SJoerg Wunsch 
19048aee7f3SJoerg Wunsch 	/*
191d6f907dcSJoerg Wunsch 	 * We should immediately look for the -q 'quiet' switch so that we
192d6f907dcSJoerg Wunsch 	 * don't bother with extraneous errors
193d6f907dcSJoerg Wunsch 	 */
194d6f907dcSJoerg Wunsch 	if (getarg(&arglist, 'q') != NULL)
195d6f907dcSJoerg Wunsch 		freopen("/dev/null", "w", stderr);
196d6f907dcSJoerg Wunsch 
197d6f907dcSJoerg Wunsch 	/*
1985f12594aSDavid Nugent 	 * Set our base working path if not overridden
1995f12594aSDavid Nugent 	 */
2005f12594aSDavid Nugent 
2015f12594aSDavid Nugent 	config = getarg(&arglist, 'C') ? getarg(&arglist, 'C')->val : NULL;
2025f12594aSDavid Nugent 
2035f12594aSDavid Nugent 	if (getarg(&arglist, 'V') != NULL) {
2045f12594aSDavid Nugent 		char * etcpath = getarg(&arglist, 'V')->val;
2055f12594aSDavid Nugent 		if (*etcpath) {
2065f12594aSDavid Nugent 			if (config == NULL) {	/* Only override config location if -C not specified */
2075f12594aSDavid Nugent 				config = malloc(MAXPATHLEN);
2085f12594aSDavid Nugent 				snprintf(config, MAXPATHLEN, "%s/pw.conf", etcpath);
2095f12594aSDavid Nugent 			}
2105f12594aSDavid Nugent 			memcpy(&PWF, &VPWF, sizeof PWF);
2115f12594aSDavid Nugent 			setpwdir(etcpath);
2125f12594aSDavid Nugent 			setgrdir(etcpath);
2135f12594aSDavid Nugent 		}
2145f12594aSDavid Nugent 	}
2155f12594aSDavid Nugent 
2165f12594aSDavid Nugent 	/*
217d6f907dcSJoerg Wunsch 	 * Now, let's do the common initialisation
218d6f907dcSJoerg Wunsch 	 */
2195f12594aSDavid Nugent 	cnf = read_userconfig(config);
2205e91a8acSNate Williams 
221f1d684faSDavid Nugent 	ch = funcs[which] (cnf, mode, &arglist);
222f1d684faSDavid Nugent 
223f1d684faSDavid Nugent 	/*
224f1d684faSDavid Nugent 	 * If everything went ok, and we've been asked to update
225f1d684faSDavid Nugent 	 * the NIS maps, then do it now
226f1d684faSDavid Nugent 	 */
227f1d684faSDavid Nugent 	if (ch == EXIT_SUCCESS && getarg(&arglist, 'Y') != NULL) {
228f1d684faSDavid Nugent 		pid_t	pid;
229f1d684faSDavid Nugent 
230f1d684faSDavid Nugent 		fflush(NULL);
231f1d684faSDavid Nugent 		if (chdir(_PATH_YP) == -1)
2321dcc6ec7SPhilippe Charnier 			warn("chdir(" _PATH_YP ")");
233f1d684faSDavid Nugent 		else if ((pid = fork()) == -1)
2341dcc6ec7SPhilippe Charnier 			warn("fork()");
235f1d684faSDavid Nugent 		else if (pid == 0) {
236f1d684faSDavid Nugent 			/* Is make anywhere else? */
237f1d684faSDavid Nugent 			execlp("/usr/bin/make", "make", NULL);
238f1d684faSDavid Nugent 			_exit(1);
239f1d684faSDavid Nugent 		} else {
240f1d684faSDavid Nugent 			int   i;
241f1d684faSDavid Nugent 			waitpid(pid, &i, 0);
242f1d684faSDavid Nugent 			if ((i = WEXITSTATUS(i)) != 0)
2431dcc6ec7SPhilippe Charnier 				errx(ch, "make exited with status %d", i);
244f1d684faSDavid Nugent 			else
245f1d684faSDavid Nugent 				pw_log(cnf, mode, which, "NIS maps updated");
246f1d684faSDavid Nugent 		}
247f1d684faSDavid Nugent 	}
248f1d684faSDavid Nugent 	return ch;
249d6f907dcSJoerg Wunsch }
250d6f907dcSJoerg Wunsch 
2515e91a8acSNate Williams 
252d6f907dcSJoerg Wunsch static int
253d6f907dcSJoerg Wunsch getindex(const char *words[], const char *word)
254d6f907dcSJoerg Wunsch {
255d6f907dcSJoerg Wunsch 	int             i = 0;
256d6f907dcSJoerg Wunsch 
257d6f907dcSJoerg Wunsch 	while (words[i]) {
258d6f907dcSJoerg Wunsch 		if (strcmp(words[i], word) == 0)
259d6f907dcSJoerg Wunsch 			return i;
260d6f907dcSJoerg Wunsch 		i++;
261d6f907dcSJoerg Wunsch 	}
262d6f907dcSJoerg Wunsch 	return -1;
263d6f907dcSJoerg Wunsch }
264d6f907dcSJoerg Wunsch 
265d6f907dcSJoerg Wunsch 
266d6f907dcSJoerg Wunsch /*
267d6f907dcSJoerg Wunsch  * This is probably an overkill for a cmdline help system, but it reflects
268d6f907dcSJoerg Wunsch  * the complexity of the command line.
269d6f907dcSJoerg Wunsch  */
270d6f907dcSJoerg Wunsch 
271d6f907dcSJoerg Wunsch static void
272d6f907dcSJoerg Wunsch cmdhelp(int mode, int which)
273d6f907dcSJoerg Wunsch {
274d6f907dcSJoerg Wunsch 	if (which == -1)
2751dcc6ec7SPhilippe Charnier 		fprintf(stderr, "usage: pw [user|group] [add|del|mod|show|next] [ help | switches/values ]\n");
276d6f907dcSJoerg Wunsch 	else if (mode == -1)
2771dcc6ec7SPhilippe Charnier 		fprintf(stderr, "usage: pw %s [add|del|mod|show|next] [ help | switches/values ]\n", Which[which]);
278d6f907dcSJoerg Wunsch 	else {
279d6f907dcSJoerg Wunsch 
280d6f907dcSJoerg Wunsch 		/*
281d6f907dcSJoerg Wunsch 		 * We need to give mode specific help
282d6f907dcSJoerg Wunsch 		 */
283d6f907dcSJoerg Wunsch 		static const char *help[W_NUM][M_NUM] =
284d6f907dcSJoerg Wunsch 		{
285d6f907dcSJoerg Wunsch 			{
2861dcc6ec7SPhilippe Charnier 				"usage: pw useradd [name] [switches]\n"
2875f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
288d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
289d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
290d6f907dcSJoerg Wunsch 				"  Adding users:\n"
291d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
292d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
293d6f907dcSJoerg Wunsch 				"\t-c comment     user name/comment\n"
294d6f907dcSJoerg Wunsch 				"\t-d directory   home directory\n"
295d6f907dcSJoerg Wunsch 				"\t-e date        account expiry date\n"
296d6f907dcSJoerg Wunsch 				"\t-p date        password expiry date\n"
297d6f907dcSJoerg Wunsch 				"\t-g grp         initial group\n"
298d6f907dcSJoerg Wunsch 				"\t-G grp1,grp2   additional groups\n"
299d6f907dcSJoerg Wunsch 				"\t-m [ -k dir ]  create and set up home\n"
300d6f907dcSJoerg Wunsch 				"\t-s shell       name of login shell\n"
301d6f907dcSJoerg Wunsch 				"\t-o             duplicate uid ok\n"
302d6f907dcSJoerg Wunsch 				"\t-L class       user class\n"
303d6f907dcSJoerg Wunsch 				"\t-h fd          read password on fd\n"
304f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
30548aee7f3SJoerg Wunsch 				"\t-N             no update\n"
306d6f907dcSJoerg Wunsch 				"  Setting defaults:\n"
3075f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
308d6f907dcSJoerg Wunsch 			        "\t-D             set user defaults\n"
309d6f907dcSJoerg Wunsch 				"\t-b dir         default home root dir\n"
310d6f907dcSJoerg Wunsch 				"\t-e period      default expiry period\n"
311d6f907dcSJoerg Wunsch 				"\t-p period      default password change period\n"
312d6f907dcSJoerg Wunsch 				"\t-g group       default group\n"
313d6f907dcSJoerg Wunsch 				"\t-G grp1,grp2   additional groups\n"
314d6f907dcSJoerg Wunsch 				"\t-L class       default user class\n"
315d6f907dcSJoerg Wunsch 				"\t-k dir         default home skeleton\n"
316d6f907dcSJoerg Wunsch 				"\t-u min,max     set min,max uids\n"
317d6f907dcSJoerg Wunsch 				"\t-i min,max     set min,max gids\n"
318d6f907dcSJoerg Wunsch 				"\t-w method      set default password method\n"
319f1d684faSDavid Nugent 				"\t-s shell       default shell\n"
320f1d684faSDavid Nugent 				"\t-y path        set NIS passwd file path\n",
3211dcc6ec7SPhilippe Charnier 				"usage: pw userdel [uid|name] [switches]\n"
3225f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
323d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
324d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
325f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
326d6f907dcSJoerg Wunsch 				"\t-r             remove home & contents\n",
3271dcc6ec7SPhilippe Charnier 				"usage: pw usermod [uid|name] [switches]\n"
3285f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
329d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
330d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
331d6f907dcSJoerg Wunsch 				"\t-F             force add if no user\n"
332d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
333d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
334d6f907dcSJoerg Wunsch 				"\t-c comment     user name/comment\n"
335d6f907dcSJoerg Wunsch 				"\t-d directory   home directory\n"
336d6f907dcSJoerg Wunsch 				"\t-e date        account expiry date\n"
337d6f907dcSJoerg Wunsch 				"\t-p date        password expiry date\n"
338d6f907dcSJoerg Wunsch 				"\t-g grp         initial group\n"
339d6f907dcSJoerg Wunsch 				"\t-G grp1,grp2   additional groups\n"
340d6f907dcSJoerg Wunsch 				"\t-l name        new login name\n"
341d6f907dcSJoerg Wunsch 				"\t-L class       user class\n"
342d6f907dcSJoerg Wunsch 				"\t-m [ -k dir ]  create and set up home\n"
343d6f907dcSJoerg Wunsch 				"\t-s shell       name of login shell\n"
34448aee7f3SJoerg Wunsch 				"\t-w method      set new password using method\n"
34548aee7f3SJoerg Wunsch 				"\t-h fd          read password on fd\n"
346f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
34748aee7f3SJoerg Wunsch 				"\t-N             no update\n",
3481dcc6ec7SPhilippe Charnier 				"usage: pw usershow [uid|name] [switches]\n"
3495f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
350d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
351d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
352d6f907dcSJoerg Wunsch 				"\t-F             force print\n"
35348aee7f3SJoerg Wunsch 				"\t-P             prettier format\n"
35448aee7f3SJoerg Wunsch 				"\t-a             print all users\n",
3551dcc6ec7SPhilippe Charnier 				"usage: pw usernext [switches]\n"
3565f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
35748aee7f3SJoerg Wunsch 				"\t-C config      configuration file\n"
358d6f907dcSJoerg Wunsch 			},
359d6f907dcSJoerg Wunsch 			{
3601dcc6ec7SPhilippe Charnier 				"usage: pw groupadd [group|gid] [switches]\n"
3615f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
362d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
363d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
364d6f907dcSJoerg Wunsch 				"\t-n group       group name\n"
365d6f907dcSJoerg Wunsch 				"\t-g gid         group id\n"
36648aee7f3SJoerg Wunsch 				"\t-M usr1,usr2   add users as group members\n"
36748aee7f3SJoerg Wunsch 				"\t-o             duplicate gid ok\n"
368f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
36948aee7f3SJoerg Wunsch 				"\t-N             no update\n",
3701dcc6ec7SPhilippe Charnier 				"usage: pw groupdel [group|gid] [switches]\n"
3715f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
372d6f907dcSJoerg Wunsch 				"\t-n name        group name\n"
373f1d684faSDavid Nugent 				"\t-g gid         group id\n"
374f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n",
3751dcc6ec7SPhilippe Charnier 				"usage: pw groupmod [group|gid] [switches]\n"
3765f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
377d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
378d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
379d6f907dcSJoerg Wunsch 				"\t-F             force add if not exists\n"
380d6f907dcSJoerg Wunsch 				"\t-n name        group name\n"
381d6f907dcSJoerg Wunsch 				"\t-g gid         group id\n"
38248aee7f3SJoerg Wunsch 				"\t-M usr1,usr2   replaces users as group members\n"
38348aee7f3SJoerg Wunsch 				"\t-m usr1,usr2   add users as group members\n"
38448aee7f3SJoerg Wunsch 				"\t-l name        new group name\n"
385f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
38648aee7f3SJoerg Wunsch 				"\t-N             no update\n",
3871dcc6ec7SPhilippe Charnier 				"usage: pw groupshow [group|gid] [switches]\n"
3885f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
389d6f907dcSJoerg Wunsch 				"\t-n name        group name\n"
390d6f907dcSJoerg Wunsch 				"\t-g gid         group id\n"
391d6f907dcSJoerg Wunsch 				"\t-F             force print\n"
39248aee7f3SJoerg Wunsch 				"\t-P             prettier format\n"
39348aee7f3SJoerg Wunsch 				"\t-a             print all accounting groups\n",
3941dcc6ec7SPhilippe Charnier 				"usage: pw groupnext [switches]\n"
3955f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
39648aee7f3SJoerg Wunsch 				"\t-C config      configuration file\n"
397d6f907dcSJoerg Wunsch 			}
398d6f907dcSJoerg Wunsch 		};
399d6f907dcSJoerg Wunsch 
4001dcc6ec7SPhilippe Charnier 		fprintf(stderr, help[which][mode]);
401d6f907dcSJoerg Wunsch 	}
40248aee7f3SJoerg Wunsch 	exit(EXIT_FAILURE);
403d6f907dcSJoerg Wunsch }
404d6f907dcSJoerg Wunsch 
405d6f907dcSJoerg Wunsch struct carg    *
406d6f907dcSJoerg Wunsch getarg(struct cargs * _args, int ch)
407d6f907dcSJoerg Wunsch {
408d6f907dcSJoerg Wunsch 	struct carg    *c = _args->lh_first;
409d6f907dcSJoerg Wunsch 
410d6f907dcSJoerg Wunsch 	while (c != NULL && c->ch != ch)
411d6f907dcSJoerg Wunsch 		c = c->list.le_next;
412d6f907dcSJoerg Wunsch 	return c;
413d6f907dcSJoerg Wunsch }
414d6f907dcSJoerg Wunsch 
415d6f907dcSJoerg Wunsch struct carg    *
416d6f907dcSJoerg Wunsch addarg(struct cargs * _args, int ch, char *argstr)
417d6f907dcSJoerg Wunsch {
418d6f907dcSJoerg Wunsch 	struct carg    *ca = malloc(sizeof(struct carg));
419d6f907dcSJoerg Wunsch 
420d6f907dcSJoerg Wunsch 	if (ca == NULL)
4211dcc6ec7SPhilippe Charnier 		errx(EX_OSERR, "out of memory");
422d6f907dcSJoerg Wunsch 	ca->ch = ch;
423d6f907dcSJoerg Wunsch 	ca->val = argstr;
424d6f907dcSJoerg Wunsch 	LIST_INSERT_HEAD(_args, ca, list);
425d6f907dcSJoerg Wunsch 	return ca;
426d6f907dcSJoerg Wunsch }
427