xref: /freebsd/usr.sbin/pw/pw.c (revision 6a3133efbbbb034bdfe5b7cc57a280ec94ac8c3d)
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[] =
2997d92980SPeter Wemm   "$FreeBSD$";
301dcc6ec7SPhilippe Charnier #endif /* not lint */
311dcc6ec7SPhilippe Charnier 
321dcc6ec7SPhilippe Charnier #include <err.h>
335e91a8acSNate Williams #include <fcntl.h>
34e7161f36SAndrey A. Chernov #include <locale.h>
35bcbdb01eSBaptiste Daroussin #include <string.h>
36bcbdb01eSBaptiste Daroussin #include <sysexits.h>
37bcbdb01eSBaptiste Daroussin #include <unistd.h>
38bcbdb01eSBaptiste Daroussin 
395f12594aSDavid Nugent #include "pw.h"
40d6f907dcSJoerg Wunsch 
412399cd14SDavid Nugent const char     *Modes[] = {
422399cd14SDavid Nugent   "add", "del", "mod", "show", "next",
432399cd14SDavid Nugent   NULL};
44d6f907dcSJoerg Wunsch const char     *Which[] = {"user", "group", NULL};
4548aee7f3SJoerg Wunsch static const char *Combo1[] = {
4648aee7f3SJoerg Wunsch   "useradd", "userdel", "usermod", "usershow", "usernext",
472399cd14SDavid Nugent   "lock", "unlock",
4848aee7f3SJoerg Wunsch   "groupadd", "groupdel", "groupmod", "groupshow", "groupnext",
49d6f907dcSJoerg Wunsch   NULL};
5048aee7f3SJoerg Wunsch static const char *Combo2[] = {
5148aee7f3SJoerg Wunsch   "adduser", "deluser", "moduser", "showuser", "nextuser",
522399cd14SDavid Nugent   "lock", "unlock",
5348aee7f3SJoerg Wunsch   "addgroup", "delgroup", "modgroup", "showgroup", "nextgroup",
54d6f907dcSJoerg Wunsch   NULL};
55d6f907dcSJoerg Wunsch 
565f12594aSDavid Nugent struct pwf PWF =
575f12594aSDavid Nugent {
58ac72be28SBaptiste Daroussin 	PWF_REGULAR,
595f12594aSDavid Nugent 	setpwent,
605f12594aSDavid Nugent 	endpwent,
615f12594aSDavid Nugent 	getpwent,
625f12594aSDavid Nugent 	getpwuid,
635f12594aSDavid Nugent 	getpwnam,
645f12594aSDavid Nugent 	setgrent,
655f12594aSDavid Nugent 	endgrent,
665f12594aSDavid Nugent 	getgrent,
675f12594aSDavid Nugent 	getgrgid,
685f12594aSDavid Nugent 	getgrnam,
695f12594aSDavid Nugent 
705f12594aSDavid Nugent };
715f12594aSDavid Nugent struct pwf VPWF =
725f12594aSDavid Nugent {
73ac72be28SBaptiste Daroussin 	PWF_ALT,
745f12594aSDavid Nugent 	vsetpwent,
755f12594aSDavid Nugent 	vendpwent,
765f12594aSDavid Nugent 	vgetpwent,
775f12594aSDavid Nugent 	vgetpwuid,
785f12594aSDavid Nugent 	vgetpwnam,
795f12594aSDavid Nugent 	vsetgrent,
805f12594aSDavid Nugent 	vendgrent,
815f12594aSDavid Nugent 	vgetgrent,
825f12594aSDavid Nugent 	vgetgrgid,
835f12594aSDavid Nugent 	vgetgrnam,
845f12594aSDavid Nugent };
855f12594aSDavid Nugent 
86d2d022b9SBaptiste Daroussin static int (*cmdfunc[W_NUM][M_NUM])(int argc, char **argv, char *_name) = {
87d2d022b9SBaptiste Daroussin 	{ /* user */
88d2d022b9SBaptiste Daroussin 		pw_user_add,
89d2d022b9SBaptiste Daroussin 		pw_user_del,
90d2d022b9SBaptiste Daroussin 		pw_user_mod,
91d2d022b9SBaptiste Daroussin 		pw_user_show,
92d2d022b9SBaptiste Daroussin 		pw_user_next,
93d2d022b9SBaptiste Daroussin 		pw_user_lock,
94d2d022b9SBaptiste Daroussin 		pw_user_unlock,
95d2d022b9SBaptiste Daroussin 	},
96d2d022b9SBaptiste Daroussin 	{ /* group */
97d2d022b9SBaptiste Daroussin 		pw_group_add,
98d2d022b9SBaptiste Daroussin 		pw_group_del,
99d2d022b9SBaptiste Daroussin 		pw_group_mod,
100d2d022b9SBaptiste Daroussin 		pw_group_show,
101d2d022b9SBaptiste Daroussin 		pw_group_next,
102d2d022b9SBaptiste Daroussin 	}
103d2d022b9SBaptiste Daroussin };
1042cc63cd1SBaptiste Daroussin 
105d2d022b9SBaptiste Daroussin struct pwconf conf;
106d6f907dcSJoerg Wunsch 
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 {
113d2d022b9SBaptiste Daroussin 	int		mode = -1, which = -1, 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),
1632cc63cd1SBaptiste Daroussin 				    "%s%s", optarg, arg == 'R' ? "/etc" : "");
164e3921b27SDavid Nugent 			} else
1655f12594aSDavid Nugent 				break;
1665f12594aSDavid Nugent 		}
167c4e667b9SDavid Nugent 		else if (mode == -1 && (tmp = getindex(Modes, argv[1])) != -1)
168d6f907dcSJoerg Wunsch 			mode = tmp;
169c4e667b9SDavid Nugent 		else if (which == -1 && (tmp = getindex(Which, argv[1])) != -1)
170d6f907dcSJoerg Wunsch 			which = tmp;
171c4e667b9SDavid Nugent 		else if ((mode == -1 && which == -1) &&
172c4e667b9SDavid Nugent 			 ((tmp = getindex(Combo1, argv[1])) != -1 ||
173c4e667b9SDavid Nugent 			  (tmp = getindex(Combo2, argv[1])) != -1)) {
174d6f907dcSJoerg Wunsch 			which = tmp / M_NUM;
175d6f907dcSJoerg Wunsch 			mode = tmp % M_NUM;
176c4e667b9SDavid Nugent 		} else if (strcmp(argv[1], "help") == 0 && argv[2] == NULL)
177d6f907dcSJoerg Wunsch 			cmdhelp(mode, which);
178d2d022b9SBaptiste Daroussin 		else if (which != -1 && mode != -1)
179d2d022b9SBaptiste Daroussin 				arg1 = argv[1];
180d2d022b9SBaptiste Daroussin 		else
1811dcc6ec7SPhilippe Charnier 			errx(EX_USAGE, "unknown keyword `%s'", argv[1]);
182d6f907dcSJoerg Wunsch 		++argv;
183d6f907dcSJoerg Wunsch 		--argc;
184d6f907dcSJoerg Wunsch 	}
185d6f907dcSJoerg Wunsch 
186d6f907dcSJoerg Wunsch 	/*
187d6f907dcSJoerg Wunsch 	 * Bail out unless the user is specific!
188d6f907dcSJoerg Wunsch 	 */
189d6f907dcSJoerg Wunsch 	if (mode == -1 || which == -1)
190d6f907dcSJoerg Wunsch 		cmdhelp(mode, which);
191d6f907dcSJoerg Wunsch 
19265730d93SBaptiste Daroussin 	conf.rootfd = open(conf.rootdir, O_DIRECTORY|O_CLOEXEC);
19365730d93SBaptiste Daroussin 	if (conf.rootfd == -1)
19465730d93SBaptiste Daroussin 		errx(EXIT_FAILURE, "Unable to open '%s'", conf.rootdir);
195d6f907dcSJoerg Wunsch 
196d2d022b9SBaptiste Daroussin 	return (cmdfunc[which][mode](argc, argv, arg1));
197d6f907dcSJoerg Wunsch }
198d6f907dcSJoerg Wunsch 
1995e91a8acSNate Williams 
200d6f907dcSJoerg Wunsch static int
201d6f907dcSJoerg Wunsch getindex(const char *words[], const char *word)
202d6f907dcSJoerg Wunsch {
203d6f907dcSJoerg Wunsch 	int	i = 0;
204d6f907dcSJoerg Wunsch 
205d6f907dcSJoerg Wunsch 	while (words[i]) {
206d6f907dcSJoerg Wunsch 		if (strcmp(words[i], word) == 0)
207d2d022b9SBaptiste Daroussin 			return (i);
208d6f907dcSJoerg Wunsch 		i++;
209d6f907dcSJoerg Wunsch 	}
210d2d022b9SBaptiste Daroussin 	return (-1);
211d6f907dcSJoerg Wunsch }
212d6f907dcSJoerg Wunsch 
213d6f907dcSJoerg Wunsch 
214d6f907dcSJoerg Wunsch /*
215d6f907dcSJoerg Wunsch  * This is probably an overkill for a cmdline help system, but it reflects
216d6f907dcSJoerg Wunsch  * the complexity of the command line.
217d6f907dcSJoerg Wunsch  */
218d6f907dcSJoerg Wunsch 
219d6f907dcSJoerg Wunsch static void
220d6f907dcSJoerg Wunsch cmdhelp(int mode, int which)
221d6f907dcSJoerg Wunsch {
222d6f907dcSJoerg Wunsch 	if (which == -1)
2232399cd14SDavid Nugent 		fprintf(stderr, "usage:\n  pw [user|group|lock|unlock] [add|del|mod|show|next] [help|switches/values]\n");
224d6f907dcSJoerg Wunsch 	else if (mode == -1)
2252399cd14SDavid Nugent 		fprintf(stderr, "usage:\n  pw %s [add|del|mod|show|next] [help|switches/values]\n", Which[which]);
226d6f907dcSJoerg Wunsch 	else {
227d6f907dcSJoerg Wunsch 
228d6f907dcSJoerg Wunsch 		/*
229d6f907dcSJoerg Wunsch 		 * We need to give mode specific help
230d6f907dcSJoerg Wunsch 		 */
231d6f907dcSJoerg Wunsch 		static const char *help[W_NUM][M_NUM] =
232d6f907dcSJoerg Wunsch 		{
233d6f907dcSJoerg Wunsch 			{
2341dcc6ec7SPhilippe Charnier 				"usage: pw useradd [name] [switches]\n"
2355f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
236*6a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
237d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
238d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
239d6f907dcSJoerg Wunsch 				"  Adding users:\n"
240d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
241d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
242d6f907dcSJoerg Wunsch 				"\t-c comment     user name/comment\n"
243d6f907dcSJoerg Wunsch 				"\t-d directory   home directory\n"
244d6f907dcSJoerg Wunsch 				"\t-e date        account expiry date\n"
245d6f907dcSJoerg Wunsch 				"\t-p date        password expiry date\n"
246d6f907dcSJoerg Wunsch 				"\t-g grp         initial group\n"
247d6f907dcSJoerg Wunsch 				"\t-G grp1,grp2   additional groups\n"
248d6f907dcSJoerg Wunsch 				"\t-m [ -k dir ]  create and set up home\n"
2491dd634b0SLukas Ertl 				"\t-M mode        home directory permissions\n"
250d6f907dcSJoerg Wunsch 				"\t-s shell       name of login shell\n"
251d6f907dcSJoerg Wunsch 				"\t-o             duplicate uid ok\n"
252d6f907dcSJoerg Wunsch 				"\t-L class       user class\n"
253d6f907dcSJoerg Wunsch 				"\t-h fd          read password on fd\n"
25487d6b5caSIan Dowse 				"\t-H fd          read encrypted password on fd\n"
255f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
25648aee7f3SJoerg Wunsch 				"\t-N             no update\n"
257d6f907dcSJoerg Wunsch 				"  Setting defaults:\n"
2585f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
259*6a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
260d6f907dcSJoerg Wunsch 				"\t-D             set user defaults\n"
261d6f907dcSJoerg Wunsch 				"\t-b dir         default home root dir\n"
262d6f907dcSJoerg Wunsch 				"\t-e period      default expiry period\n"
263d6f907dcSJoerg Wunsch 				"\t-p period      default password change period\n"
264d6f907dcSJoerg Wunsch 				"\t-g group       default group\n"
265d6f907dcSJoerg Wunsch 				"\t-G grp1,grp2   additional groups\n"
266d6f907dcSJoerg Wunsch 				"\t-L class       default user class\n"
267d6f907dcSJoerg Wunsch 				"\t-k dir         default home skeleton\n"
26885204142SLukas Ertl 				"\t-M mode        home directory permissions\n"
269d6f907dcSJoerg Wunsch 				"\t-u min,max     set min,max uids\n"
270d6f907dcSJoerg Wunsch 				"\t-i min,max     set min,max gids\n"
271d6f907dcSJoerg Wunsch 				"\t-w method      set default password method\n"
272f1d684faSDavid Nugent 				"\t-s shell       default shell\n"
273f1d684faSDavid Nugent 				"\t-y path        set NIS passwd file path\n",
2741dcc6ec7SPhilippe Charnier 				"usage: pw userdel [uid|name] [switches]\n"
2755f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
276*6a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
277d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
278d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
279f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
280d2d022b9SBaptiste Daroussin 				"\t-y path        set NIS passwd file path\n"
281d6f907dcSJoerg Wunsch 				"\t-r             remove home & contents\n",
2821dcc6ec7SPhilippe Charnier 				"usage: pw usermod [uid|name] [switches]\n"
2835f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
284*6a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
285d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
286d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
287d6f907dcSJoerg Wunsch 				"\t-F             force add if no user\n"
288d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
289d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
290d6f907dcSJoerg Wunsch 				"\t-c comment     user name/comment\n"
291d6f907dcSJoerg Wunsch 				"\t-d directory   home directory\n"
292d6f907dcSJoerg Wunsch 				"\t-e date        account expiry date\n"
293d6f907dcSJoerg Wunsch 				"\t-p date        password expiry date\n"
294d6f907dcSJoerg Wunsch 				"\t-g grp         initial group\n"
295d6f907dcSJoerg Wunsch 				"\t-G grp1,grp2   additional groups\n"
296d6f907dcSJoerg Wunsch 				"\t-l name        new login name\n"
297d6f907dcSJoerg Wunsch 				"\t-L class       user class\n"
298d6f907dcSJoerg Wunsch 				"\t-m [ -k dir ]  create and set up home\n"
2991dd634b0SLukas Ertl 				"\t-M mode        home directory permissions\n"
300d6f907dcSJoerg Wunsch 				"\t-s shell       name of login shell\n"
30148aee7f3SJoerg Wunsch 				"\t-w method      set new password using method\n"
30248aee7f3SJoerg Wunsch 				"\t-h fd          read password on fd\n"
30387d6b5caSIan Dowse 				"\t-H fd          read encrypted password on fd\n"
304f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
305d2d022b9SBaptiste Daroussin 				"\t-y path        set NIS passwd file path\n"
30648aee7f3SJoerg Wunsch 				"\t-N             no update\n",
3071dcc6ec7SPhilippe Charnier 				"usage: pw usershow [uid|name] [switches]\n"
3085f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
309*6a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
310d6f907dcSJoerg Wunsch 				"\t-n name        login name\n"
311d6f907dcSJoerg Wunsch 				"\t-u uid         user id\n"
312d6f907dcSJoerg Wunsch 				"\t-F             force print\n"
31348aee7f3SJoerg Wunsch 				"\t-P             prettier format\n"
314f3522722SDavid Nugent 				"\t-a             print all users\n"
315f3522722SDavid Nugent 				"\t-7             print in v7 format\n",
3161dcc6ec7SPhilippe Charnier 				"usage: pw usernext [switches]\n"
3175f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
318*6a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
3193bfc59e8SBaptiste Daroussin 				"\t-C config      configuration file\n"
3203bfc59e8SBaptiste Daroussin 				"\t-q             quiet operation\n",
321ed6fd55aSDima Dorfman 				"usage pw: lock [switches]\n"
322ed6fd55aSDima Dorfman 				"\t-V etcdir      alternate /etc locations\n"
323ed6fd55aSDima Dorfman 				"\t-C config      configuration file\n"
324ed6fd55aSDima Dorfman 				"\t-q             quiet operation\n",
325ed6fd55aSDima Dorfman 				"usage pw: unlock [switches]\n"
326ed6fd55aSDima Dorfman 				"\t-V etcdir      alternate /etc locations\n"
327ed6fd55aSDima Dorfman 				"\t-C config      configuration file\n"
328ed6fd55aSDima Dorfman 				"\t-q             quiet operation\n"
329d6f907dcSJoerg Wunsch 			},
330d6f907dcSJoerg Wunsch 			{
3311dcc6ec7SPhilippe Charnier 				"usage: pw groupadd [group|gid] [switches]\n"
3325f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
333*6a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
334d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
335d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
336d6f907dcSJoerg Wunsch 				"\t-n group       group name\n"
337d6f907dcSJoerg Wunsch 				"\t-g gid         group id\n"
33848aee7f3SJoerg Wunsch 				"\t-M usr1,usr2   add users as group members\n"
33948aee7f3SJoerg Wunsch 				"\t-o             duplicate gid ok\n"
340f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
34148aee7f3SJoerg Wunsch 				"\t-N             no update\n",
3421dcc6ec7SPhilippe Charnier 				"usage: pw groupdel [group|gid] [switches]\n"
3435f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
344*6a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
345d6f907dcSJoerg Wunsch 				"\t-n name        group name\n"
346f1d684faSDavid Nugent 				"\t-g gid         group id\n"
347f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n",
3481dcc6ec7SPhilippe Charnier 				"usage: pw groupmod [group|gid] [switches]\n"
3495f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
350*6a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
351d6f907dcSJoerg Wunsch 				"\t-C config      configuration file\n"
352d6f907dcSJoerg Wunsch 				"\t-q             quiet operation\n"
353d6f907dcSJoerg Wunsch 				"\t-F             force add if not exists\n"
354d6f907dcSJoerg Wunsch 				"\t-n name        group name\n"
355d6f907dcSJoerg Wunsch 				"\t-g gid         group id\n"
35648aee7f3SJoerg Wunsch 				"\t-M usr1,usr2   replaces users as group members\n"
35748aee7f3SJoerg Wunsch 				"\t-m usr1,usr2   add users as group members\n"
358bc991a6dSSean Farley 				"\t-d usr1,usr2   delete users as group members\n"
35948aee7f3SJoerg Wunsch 				"\t-l name        new group name\n"
360f1d684faSDavid Nugent 				"\t-Y             update NIS maps\n"
36148aee7f3SJoerg Wunsch 				"\t-N             no update\n",
3621dcc6ec7SPhilippe Charnier 				"usage: pw groupshow [group|gid] [switches]\n"
3635f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
364*6a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
365d6f907dcSJoerg Wunsch 				"\t-n name        group name\n"
366d6f907dcSJoerg Wunsch 				"\t-g gid         group id\n"
367d6f907dcSJoerg Wunsch 				"\t-F             force print\n"
36848aee7f3SJoerg Wunsch 				"\t-P             prettier format\n"
36948aee7f3SJoerg Wunsch 				"\t-a             print all accounting groups\n",
3701dcc6ec7SPhilippe Charnier 				"usage: pw groupnext [switches]\n"
3715f12594aSDavid Nugent 				"\t-V etcdir      alternate /etc location\n"
372*6a3133efSWarren Block 				"\t-R rootdir     alternate root directory\n"
37348aee7f3SJoerg Wunsch 				"\t-C config      configuration file\n"
3743bfc59e8SBaptiste Daroussin 				"\t-q             quiet operation\n"
375d6f907dcSJoerg Wunsch 			}
376d6f907dcSJoerg Wunsch 		};
377d6f907dcSJoerg Wunsch 
378cab0fb4eSKris Kennaway 		fprintf(stderr, "%s", help[which][mode]);
379d6f907dcSJoerg Wunsch 	}
38048aee7f3SJoerg Wunsch 	exit(EXIT_FAILURE);
381d6f907dcSJoerg Wunsch }
382