xref: /freebsd/usr.sbin/pw/pw.c (revision c86119328e6b2cfeb4f9319f6b154524d88caaf4)
1d6f907dcSJoerg Wunsch /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
4ad7cf975SJoerg Wunsch  * Copyright (C) 1996
5ad7cf975SJoerg Wunsch  *	David L. Nugent.  All rights reserved.
6d6f907dcSJoerg Wunsch  *
7d6f907dcSJoerg Wunsch  * Redistribution and use in source and binary forms, with or without
8d6f907dcSJoerg Wunsch  * modification, are permitted provided that the following conditions
9d6f907dcSJoerg Wunsch  * are met:
10d6f907dcSJoerg Wunsch  * 1. Redistributions of source code must retain the above copyright
11ad7cf975SJoerg Wunsch  *    notice, this list of conditions and the following disclaimer.
12d6f907dcSJoerg Wunsch  * 2. Redistributions in binary form must reproduce the above copyright
13d6f907dcSJoerg Wunsch  *    notice, this list of conditions and the following disclaimer in the
14d6f907dcSJoerg Wunsch  *    documentation and/or other materials provided with the distribution.
15d6f907dcSJoerg Wunsch  *
16ad7cf975SJoerg Wunsch  * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND
17d6f907dcSJoerg Wunsch  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18d6f907dcSJoerg Wunsch  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19ad7cf975SJoerg Wunsch  * ARE DISCLAIMED.  IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE
20d6f907dcSJoerg Wunsch  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21d6f907dcSJoerg Wunsch  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22d6f907dcSJoerg Wunsch  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23d6f907dcSJoerg Wunsch  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24d6f907dcSJoerg Wunsch  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25d6f907dcSJoerg Wunsch  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26d6f907dcSJoerg Wunsch  * SUCH DAMAGE.
27d6f907dcSJoerg Wunsch  */
28d6f907dcSJoerg Wunsch 
291dcc6ec7SPhilippe Charnier #include <err.h>
305e91a8acSNate Williams #include <fcntl.h>
31e7161f36SAndrey A. Chernov #include <locale.h>
32bcbdb01eSBaptiste Daroussin #include <string.h>
33bcbdb01eSBaptiste Daroussin #include <sysexits.h>
34bcbdb01eSBaptiste Daroussin #include <unistd.h>
35bcbdb01eSBaptiste Daroussin 
365f12594aSDavid Nugent #include "pw.h"
37d6f907dcSJoerg Wunsch 
382399cd14SDavid Nugent const char     *Modes[] = {
392399cd14SDavid Nugent   "add", "del", "mod", "show", "next",
402399cd14SDavid Nugent   NULL};
41d6f907dcSJoerg Wunsch const char     *Which[] = {"user", "group", NULL};
4248aee7f3SJoerg Wunsch static const char *Combo1[] = {
4348aee7f3SJoerg Wunsch   "useradd", "userdel", "usermod", "usershow", "usernext",
442399cd14SDavid Nugent   "lock", "unlock",
4548aee7f3SJoerg Wunsch   "groupadd", "groupdel", "groupmod", "groupshow", "groupnext",
46d6f907dcSJoerg Wunsch   NULL};
4748aee7f3SJoerg Wunsch static const char *Combo2[] = {
4848aee7f3SJoerg Wunsch   "adduser", "deluser", "moduser", "showuser", "nextuser",
492399cd14SDavid Nugent   "lock", "unlock",
5048aee7f3SJoerg Wunsch   "addgroup", "delgroup", "modgroup", "showgroup", "nextgroup",
51d6f907dcSJoerg Wunsch   NULL};
52d6f907dcSJoerg Wunsch 
535f12594aSDavid Nugent struct pwf PWF =
545f12594aSDavid Nugent {
55ac72be28SBaptiste Daroussin 	PWF_REGULAR,
565f12594aSDavid Nugent 	setpwent,
575f12594aSDavid Nugent 	endpwent,
585f12594aSDavid Nugent 	getpwent,
595f12594aSDavid Nugent 	getpwuid,
605f12594aSDavid Nugent 	getpwnam,
615f12594aSDavid Nugent 	setgrent,
625f12594aSDavid Nugent 	endgrent,
635f12594aSDavid Nugent 	getgrent,
645f12594aSDavid Nugent 	getgrgid,
655f12594aSDavid Nugent 	getgrnam,
665f12594aSDavid Nugent 
675f12594aSDavid Nugent };
685f12594aSDavid Nugent struct pwf VPWF =
695f12594aSDavid Nugent {
70ac72be28SBaptiste Daroussin 	PWF_ALT,
715f12594aSDavid Nugent 	vsetpwent,
725f12594aSDavid Nugent 	vendpwent,
735f12594aSDavid Nugent 	vgetpwent,
745f12594aSDavid Nugent 	vgetpwuid,
755f12594aSDavid Nugent 	vgetpwnam,
765f12594aSDavid Nugent 	vsetgrent,
775f12594aSDavid Nugent 	vendgrent,
785f12594aSDavid Nugent 	vgetgrent,
795f12594aSDavid Nugent 	vgetgrgid,
805f12594aSDavid Nugent 	vgetgrnam,
815f12594aSDavid Nugent };
825f12594aSDavid Nugent 
83d2d022b9SBaptiste Daroussin static int (*cmdfunc[W_NUM][M_NUM])(int argc, char **argv, char *_name) = {
84d2d022b9SBaptiste Daroussin 	{ /* user */
85d2d022b9SBaptiste Daroussin 		pw_user_add,
86d2d022b9SBaptiste Daroussin 		pw_user_del,
87d2d022b9SBaptiste Daroussin 		pw_user_mod,
88d2d022b9SBaptiste Daroussin 		pw_user_show,
89d2d022b9SBaptiste Daroussin 		pw_user_next,
90d2d022b9SBaptiste Daroussin 		pw_user_lock,
91d2d022b9SBaptiste Daroussin 		pw_user_unlock,
92d2d022b9SBaptiste Daroussin 	},
93d2d022b9SBaptiste Daroussin 	{ /* group */
94d2d022b9SBaptiste Daroussin 		pw_group_add,
95d2d022b9SBaptiste Daroussin 		pw_group_del,
96d2d022b9SBaptiste Daroussin 		pw_group_mod,
97d2d022b9SBaptiste Daroussin 		pw_group_show,
98d2d022b9SBaptiste Daroussin 		pw_group_next,
99d2d022b9SBaptiste Daroussin 	}
100d2d022b9SBaptiste Daroussin };
1012cc63cd1SBaptiste Daroussin 
102d2d022b9SBaptiste Daroussin struct pwconf conf;
103d6f907dcSJoerg Wunsch 
104*c8611932SDag-Erling Smørgrav static int	mode = -1;
105*c8611932SDag-Erling Smørgrav static int	which = -1;
106*c8611932SDag-Erling Smørgrav 
107d6f907dcSJoerg Wunsch static int	getindex(const char *words[], const char *word);
108d6f907dcSJoerg Wunsch static void	cmdhelp(int mode, int which);
109d6f907dcSJoerg Wunsch 
110d6f907dcSJoerg Wunsch int
111d6f907dcSJoerg Wunsch main(int argc, char *argv[])
112d6f907dcSJoerg Wunsch {
113*c8611932SDag-Erling Smørgrav 	int		tmp;
11490edef4fSBaptiste Daroussin 	struct stat	st;
115d2d022b9SBaptiste Daroussin 	char		arg, *arg1;
11682a3c75aSBaptiste Daroussin 	bool		relocated, nis;
117d6f907dcSJoerg Wunsch 
118d2d022b9SBaptiste Daroussin 	arg1 = NULL;
11982a3c75aSBaptiste Daroussin 	relocated = nis = false;
120bbe09b2eSBaptiste Daroussin 	memset(&conf, 0, sizeof(conf));
12165730d93SBaptiste Daroussin 	strlcpy(conf.rootdir, "/", sizeof(conf.rootdir));
1222cc63cd1SBaptiste Daroussin 	strlcpy(conf.etcpath, _PATH_PWD, sizeof(conf.etcpath));
12311621f96SBaptiste Daroussin 	conf.fd = -1;
124a70fbf7eSBaptiste Daroussin 	conf.checkduplicate = true;
1252cc63cd1SBaptiste Daroussin 
126d2d022b9SBaptiste Daroussin 	setlocale(LC_ALL, "");
127e7161f36SAndrey A. Chernov 
128d6f907dcSJoerg Wunsch 	/*
129d6f907dcSJoerg Wunsch 	 * Break off the first couple of words to determine what exactly
130d6f907dcSJoerg Wunsch 	 * we're being asked to do
131d6f907dcSJoerg Wunsch 	 */
1325f12594aSDavid Nugent 	while (argc > 1) {
1335f12594aSDavid Nugent 		if (*argv[1] == '-') {
1345f12594aSDavid Nugent 			/*
1355f12594aSDavid Nugent 			 * Special case, allow pw -V<dir> <operation> [args] for scripts etc.
1365f12594aSDavid Nugent 			 */
137ac72be28SBaptiste Daroussin 			arg = argv[1][1];
138ac72be28SBaptiste Daroussin 			if (arg == 'V' || arg == 'R') {
1392cc63cd1SBaptiste Daroussin 				if (relocated)
1402cc63cd1SBaptiste Daroussin 					errx(EXIT_FAILURE, "Both '-R' and '-V' "
1412cc63cd1SBaptiste Daroussin 					    "specified, only one accepted");
1422cc63cd1SBaptiste Daroussin 				relocated = true;
1435f12594aSDavid Nugent 				optarg = &argv[1][2];
1445f12594aSDavid Nugent 				if (*optarg == '\0') {
14590edef4fSBaptiste Daroussin 					if (stat(argv[2], &st) != 0)
14690edef4fSBaptiste Daroussin 						errx(EX_OSFILE, \
14790edef4fSBaptiste Daroussin 						    "no such directory `%s'",
14890edef4fSBaptiste Daroussin 						    argv[2]);
14990edef4fSBaptiste Daroussin 					if (!S_ISDIR(st.st_mode))
15090edef4fSBaptiste Daroussin 						errx(EX_OSFILE, "`%s' not a "
15190edef4fSBaptiste Daroussin 						    "directory", argv[2]);
1525f12594aSDavid Nugent 					optarg = argv[2];
1535f12594aSDavid Nugent 					++argv;
1545f12594aSDavid Nugent 					--argc;
1555f12594aSDavid Nugent 				}
1562cc63cd1SBaptiste Daroussin 				memcpy(&PWF, &VPWF, sizeof PWF);
1572cc63cd1SBaptiste Daroussin 				if (arg == 'R') {
1582cc63cd1SBaptiste Daroussin 					strlcpy(conf.rootdir, optarg,
1592cc63cd1SBaptiste Daroussin 					    sizeof(conf.rootdir));
1602cc63cd1SBaptiste Daroussin 					PWF._altdir = PWF_ROOTDIR;
1612cc63cd1SBaptiste Daroussin 				}
1622cc63cd1SBaptiste Daroussin 				snprintf(conf.etcpath, sizeof(conf.etcpath),
1634835c3b1SYuri Pankov 				    "%s%s", optarg, arg == 'R' ?
1644835c3b1SYuri Pankov 				    _PATH_PWD : "");
165e3921b27SDavid Nugent 			} else
1665f12594aSDavid Nugent 				break;
1675f12594aSDavid Nugent 		}
168c4e667b9SDavid Nugent 		else if (mode == -1 && (tmp = getindex(Modes, argv[1])) != -1)
169d6f907dcSJoerg Wunsch 			mode = tmp;
170c4e667b9SDavid Nugent 		else if (which == -1 && (tmp = getindex(Which, argv[1])) != -1)
171d6f907dcSJoerg Wunsch 			which = tmp;
172c4e667b9SDavid Nugent 		else if ((mode == -1 && which == -1) &&
173c4e667b9SDavid Nugent 			 ((tmp = getindex(Combo1, argv[1])) != -1 ||
174c4e667b9SDavid Nugent 			  (tmp = getindex(Combo2, argv[1])) != -1)) {
175d6f907dcSJoerg Wunsch 			which = tmp / M_NUM;
176d6f907dcSJoerg Wunsch 			mode = tmp % M_NUM;
177c4e667b9SDavid Nugent 		} else if (strcmp(argv[1], "help") == 0 && argv[2] == NULL)
178d6f907dcSJoerg Wunsch 			cmdhelp(mode, which);
179d2d022b9SBaptiste Daroussin 		else if (which != -1 && mode != -1)
180d2d022b9SBaptiste Daroussin 				arg1 = argv[1];
181d2d022b9SBaptiste Daroussin 		else
1821dcc6ec7SPhilippe Charnier 			errx(EX_USAGE, "unknown keyword `%s'", argv[1]);
183d6f907dcSJoerg Wunsch 		++argv;
184d6f907dcSJoerg Wunsch 		--argc;
185d6f907dcSJoerg Wunsch 	}
186d6f907dcSJoerg Wunsch 
187d6f907dcSJoerg Wunsch 	/*
188d6f907dcSJoerg Wunsch 	 * Bail out unless the user is specific!
189d6f907dcSJoerg Wunsch 	 */
190d6f907dcSJoerg Wunsch 	if (mode == -1 || which == -1)
191d6f907dcSJoerg Wunsch 		cmdhelp(mode, which);
192d6f907dcSJoerg Wunsch 
19365730d93SBaptiste Daroussin 	conf.rootfd = open(conf.rootdir, O_DIRECTORY|O_CLOEXEC);
19465730d93SBaptiste Daroussin 	if (conf.rootfd == -1)
19565730d93SBaptiste Daroussin 		errx(EXIT_FAILURE, "Unable to open '%s'", conf.rootdir);
196d6f907dcSJoerg Wunsch 
197d2d022b9SBaptiste Daroussin 	return (cmdfunc[which][mode](argc, argv, arg1));
198d6f907dcSJoerg Wunsch }
199d6f907dcSJoerg Wunsch 
2005e91a8acSNate Williams 
201d6f907dcSJoerg Wunsch static int
202d6f907dcSJoerg Wunsch getindex(const char *words[], const char *word)
203d6f907dcSJoerg Wunsch {
204d6f907dcSJoerg Wunsch 	int	i = 0;
205d6f907dcSJoerg Wunsch 
206d6f907dcSJoerg Wunsch 	while (words[i]) {
207d6f907dcSJoerg Wunsch 		if (strcmp(words[i], word) == 0)
208d2d022b9SBaptiste Daroussin 			return (i);
209d6f907dcSJoerg Wunsch 		i++;
210d6f907dcSJoerg Wunsch 	}
211d2d022b9SBaptiste Daroussin 	return (-1);
212d6f907dcSJoerg Wunsch }
213d6f907dcSJoerg Wunsch 
214d6f907dcSJoerg Wunsch 
215d6f907dcSJoerg Wunsch /*
216d6f907dcSJoerg Wunsch  * This is probably an overkill for a cmdline help system, but it reflects
217d6f907dcSJoerg Wunsch  * the complexity of the command line.
218d6f907dcSJoerg Wunsch  */
219d6f907dcSJoerg Wunsch 
220d6f907dcSJoerg Wunsch static void
221d6f907dcSJoerg Wunsch cmdhelp(int mode, int which)
222d6f907dcSJoerg Wunsch {
223d6f907dcSJoerg Wunsch 	if (which == -1)
2242399cd14SDavid Nugent 		fprintf(stderr, "usage:\n  pw [user|group|lock|unlock] [add|del|mod|show|next] [help|switches/values]\n");
225d6f907dcSJoerg Wunsch 	else if (mode == -1)
2262399cd14SDavid Nugent 		fprintf(stderr, "usage:\n  pw %s [add|del|mod|show|next] [help|switches/values]\n", Which[which]);
227d6f907dcSJoerg Wunsch 	else {
228d6f907dcSJoerg Wunsch 
229d6f907dcSJoerg Wunsch 		/*
230d6f907dcSJoerg Wunsch 		 * We need to give mode specific help
231d6f907dcSJoerg Wunsch 		 */
232d6f907dcSJoerg Wunsch 		static const char *help[W_NUM][M_NUM] =
233d6f907dcSJoerg Wunsch 		{
234d6f907dcSJoerg Wunsch 			{
2351dcc6ec7SPhilippe Charnier 				"usage: pw useradd [name] [switches]\n"
2365f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
2376a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
238d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
239d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
240d6f907dcSJoerg Wunsch 				"  Adding users:\n"
241d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
242d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
243d6f907dcSJoerg Wunsch 				"\t-c comment     user name/comment\n"
244d6f907dcSJoerg Wunsch 				"\t-d directory   home directory\n"
245d6f907dcSJoerg Wunsch 				"\t-e date        account expiry date\n"
246d6f907dcSJoerg Wunsch 				"\t-p date        password expiry date\n"
247d6f907dcSJoerg Wunsch 				"\t-g grp         initial group\n"
248d6f907dcSJoerg Wunsch 				"\t-G grp1,grp2   additional groups\n"
249d6f907dcSJoerg Wunsch 				"\t-m [ -k dir ]  create and set up home\n"
2501dd634b0SLukas Ertl 				"\t-M mode        home directory permissions\n"
251d6f907dcSJoerg Wunsch 				"\t-s shell       name of login shell\n"
252d6f907dcSJoerg Wunsch 				"\t-o             duplicate uid ok\n"
253d6f907dcSJoerg Wunsch 				"\t-L class       user class\n"
254d6f907dcSJoerg Wunsch 				"\t-h fd          read password on fd\n"
25587d6b5caSIan Dowse 				"\t-H fd          read encrypted password on fd\n"
256f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
25748aee7f3SJoerg Wunsch 				"\t-N             no update\n"
258d6f907dcSJoerg Wunsch 				"  Setting defaults:\n"
2595f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
2606a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
261d6f907dcSJoerg Wunsch 				"\t-D             set user defaults\n"
262d6f907dcSJoerg Wunsch 				"\t-b dir         default home root dir\n"
263d6f907dcSJoerg Wunsch 				"\t-e period      default expiry period\n"
264d6f907dcSJoerg Wunsch 				"\t-p period      default password change period\n"
265d6f907dcSJoerg Wunsch 				"\t-g group       default group\n"
266d6f907dcSJoerg Wunsch 				"\t-G grp1,grp2   additional groups\n"
267d6f907dcSJoerg Wunsch 				"\t-L class       default user class\n"
268d6f907dcSJoerg Wunsch 				"\t-k dir         default home skeleton\n"
26985204142SLukas Ertl 				"\t-M mode        home directory permissions\n"
270d6f907dcSJoerg Wunsch 				"\t-u min,max     set min,max uids\n"
271d6f907dcSJoerg Wunsch 				"\t-i min,max     set min,max gids\n"
272d6f907dcSJoerg Wunsch 				"\t-w method      set default password method\n"
273f1d684faSDavid Nugent 				"\t-s shell       default shell\n"
274f1d684faSDavid Nugent 				"\t-y path        set NIS passwd file path\n",
2751dcc6ec7SPhilippe Charnier 				"usage: pw userdel [uid|name] [switches]\n"
2765f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
2776a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
278d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
279d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
280f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
281d2d022b9SBaptiste Daroussin 				"\t-y path        set NIS passwd file path\n"
282d6f907dcSJoerg Wunsch 				"\t-r             remove home & contents\n",
2831dcc6ec7SPhilippe Charnier 				"usage: pw usermod [uid|name] [switches]\n"
2845f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
2856a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
286d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
287d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
288d6f907dcSJoerg Wunsch 				"\t-F             force add if no user\n"
289d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
290d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
291d6f907dcSJoerg Wunsch 				"\t-c comment     user name/comment\n"
292d6f907dcSJoerg Wunsch 				"\t-d directory   home directory\n"
293d6f907dcSJoerg Wunsch 				"\t-e date        account expiry date\n"
294d6f907dcSJoerg Wunsch 				"\t-p date        password expiry date\n"
295d6f907dcSJoerg Wunsch 				"\t-g grp         initial group\n"
296d6f907dcSJoerg Wunsch 				"\t-G grp1,grp2   additional groups\n"
297d6f907dcSJoerg Wunsch 				"\t-l name        new login name\n"
298d6f907dcSJoerg Wunsch 				"\t-L class       user class\n"
299d6f907dcSJoerg Wunsch 				"\t-m [ -k dir ]  create and set up home\n"
3001dd634b0SLukas Ertl 				"\t-M mode        home directory permissions\n"
301d6f907dcSJoerg Wunsch 				"\t-s shell       name of login shell\n"
30248aee7f3SJoerg Wunsch 				"\t-w method      set new password using method\n"
30348aee7f3SJoerg Wunsch 				"\t-h fd          read password on fd\n"
30487d6b5caSIan Dowse 				"\t-H fd          read encrypted password on fd\n"
305f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
306d2d022b9SBaptiste Daroussin 				"\t-y path        set NIS passwd file path\n"
30748aee7f3SJoerg Wunsch 				"\t-N             no update\n",
3081dcc6ec7SPhilippe Charnier 				"usage: pw usershow [uid|name] [switches]\n"
3095f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
3106a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
311d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
312d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
313d6f907dcSJoerg Wunsch 				"\t-F             force print\n"
31448aee7f3SJoerg Wunsch 				"\t-P             prettier format\n"
315f3522722SDavid Nugent 				"\t-a             print all users\n"
316f3522722SDavid Nugent 				"\t-7             print in v7 format\n",
3171dcc6ec7SPhilippe Charnier 				"usage: pw usernext [switches]\n"
3185f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
3196a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
3203bfc59e8SBaptiste Daroussin 				"\t-C config      configuration file\n"
3213bfc59e8SBaptiste Daroussin 				"\t-q             quiet operation\n",
322ed6fd55aSDima Dorfman 				"usage pw: lock [switches]\n"
323ed6fd55aSDima Dorfman 				"\t-V etcdir      alternate /etc locations\n"
324ed6fd55aSDima Dorfman 				"\t-C config      configuration file\n"
325ed6fd55aSDima Dorfman 				"\t-q             quiet operation\n",
326ed6fd55aSDima Dorfman 				"usage pw: unlock [switches]\n"
327ed6fd55aSDima Dorfman 				"\t-V etcdir      alternate /etc locations\n"
328ed6fd55aSDima Dorfman 				"\t-C config      configuration file\n"
329ed6fd55aSDima Dorfman 				"\t-q             quiet operation\n"
330d6f907dcSJoerg Wunsch 			},
331d6f907dcSJoerg Wunsch 			{
3321dcc6ec7SPhilippe Charnier 				"usage: pw groupadd [group|gid] [switches]\n"
3335f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
3346a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
335d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
336d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
337d6f907dcSJoerg Wunsch 				"\t-n group       group name\n"
338d6f907dcSJoerg Wunsch 				"\t-g gid         group id\n"
33948aee7f3SJoerg Wunsch 				"\t-M usr1,usr2   add users as group members\n"
34048aee7f3SJoerg Wunsch 				"\t-o             duplicate gid ok\n"
341f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
34248aee7f3SJoerg Wunsch 				"\t-N             no update\n",
3431dcc6ec7SPhilippe Charnier 				"usage: pw groupdel [group|gid] [switches]\n"
3445f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
3456a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
346d6f907dcSJoerg Wunsch 				"\t-n name        group name\n"
347f1d684faSDavid Nugent 				"\t-g gid         group id\n"
348f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n",
3491dcc6ec7SPhilippe Charnier 				"usage: pw groupmod [group|gid] [switches]\n"
3505f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
3516a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
352d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
353d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
354d6f907dcSJoerg Wunsch 				"\t-F             force add if not exists\n"
355d6f907dcSJoerg Wunsch 				"\t-n name        group name\n"
356d6f907dcSJoerg Wunsch 				"\t-g gid         group id\n"
35748aee7f3SJoerg Wunsch 				"\t-M usr1,usr2   replaces users as group members\n"
35848aee7f3SJoerg Wunsch 				"\t-m usr1,usr2   add users as group members\n"
359bc991a6dSSean Farley 				"\t-d usr1,usr2   delete users as group members\n"
36048aee7f3SJoerg Wunsch 				"\t-l name        new group name\n"
361f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
36248aee7f3SJoerg Wunsch 				"\t-N             no update\n",
3631dcc6ec7SPhilippe Charnier 				"usage: pw groupshow [group|gid] [switches]\n"
3645f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
3656a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
366d6f907dcSJoerg Wunsch 				"\t-n name        group name\n"
367d6f907dcSJoerg Wunsch 				"\t-g gid         group id\n"
368d6f907dcSJoerg Wunsch 				"\t-F             force print\n"
36948aee7f3SJoerg Wunsch 				"\t-P             prettier format\n"
37048aee7f3SJoerg Wunsch 				"\t-a             print all accounting groups\n",
3711dcc6ec7SPhilippe Charnier 				"usage: pw groupnext [switches]\n"
3725f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
3736a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
37448aee7f3SJoerg Wunsch 				"\t-C config      configuration file\n"
3753bfc59e8SBaptiste Daroussin 				"\t-q             quiet operation\n"
376d6f907dcSJoerg Wunsch 			}
377d6f907dcSJoerg Wunsch 		};
378d6f907dcSJoerg Wunsch 
379cab0fb4eSKris Kennaway 		fprintf(stderr, "%s", help[which][mode]);
380d6f907dcSJoerg Wunsch 	}
381*c8611932SDag-Erling Smørgrav 	exit(EX_USAGE);
382*c8611932SDag-Erling Smørgrav }
383*c8611932SDag-Erling Smørgrav 
384*c8611932SDag-Erling Smørgrav void
385*c8611932SDag-Erling Smørgrav usage(void)
386*c8611932SDag-Erling Smørgrav {
387*c8611932SDag-Erling Smørgrav 	cmdhelp(mode, which);
388d6f907dcSJoerg Wunsch }
389