xref: /freebsd/usr.bin/logins/logins.c (revision e738085b)
10a5f38d4SDag-Erling Smørgrav /*-
21de7b4b8SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
31de7b4b8SPedro F. Giffuni  *
4e738085bSDag-Erling Smørgrav  * Copyright (c) 2004 Dag-Erling Smørgrav
50a5f38d4SDag-Erling Smørgrav  * All rights reserved.
60a5f38d4SDag-Erling Smørgrav  *
70a5f38d4SDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
80a5f38d4SDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
90a5f38d4SDag-Erling Smørgrav  * are met:
100a5f38d4SDag-Erling Smørgrav  * 1. Redistributions of source code must retain the above copyright
110a5f38d4SDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer
120a5f38d4SDag-Erling Smørgrav  *    in this position and unchanged.
130a5f38d4SDag-Erling Smørgrav  * 2. Redistributions in binary form must reproduce the above copyright
140a5f38d4SDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer in the
150a5f38d4SDag-Erling Smørgrav  *    documentation and/or other materials provided with the distribution.
160a5f38d4SDag-Erling Smørgrav  * 3. The name of the author may not be used to endorse or promote products
170a5f38d4SDag-Erling Smørgrav  *    derived from this software without specific prior written permission.
180a5f38d4SDag-Erling Smørgrav  *
190a5f38d4SDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
200a5f38d4SDag-Erling Smørgrav  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
210a5f38d4SDag-Erling Smørgrav  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
220a5f38d4SDag-Erling Smørgrav  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
230a5f38d4SDag-Erling Smørgrav  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
240a5f38d4SDag-Erling Smørgrav  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
250a5f38d4SDag-Erling Smørgrav  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
260a5f38d4SDag-Erling Smørgrav  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
270a5f38d4SDag-Erling Smørgrav  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
280a5f38d4SDag-Erling Smørgrav  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
290a5f38d4SDag-Erling Smørgrav  */
300a5f38d4SDag-Erling Smørgrav 
310a5f38d4SDag-Erling Smørgrav #include <sys/cdefs.h>
320a5f38d4SDag-Erling Smørgrav #include <err.h>
330a5f38d4SDag-Erling Smørgrav #include <grp.h>
340a5f38d4SDag-Erling Smørgrav #include <pwd.h>
350a5f38d4SDag-Erling Smørgrav #include <stdio.h>
360a5f38d4SDag-Erling Smørgrav #include <stdlib.h>
370a5f38d4SDag-Erling Smørgrav #include <string.h>
380a5f38d4SDag-Erling Smørgrav #include <time.h>
390a5f38d4SDag-Erling Smørgrav #include <unistd.h>
400a5f38d4SDag-Erling Smørgrav 
410a5f38d4SDag-Erling Smørgrav struct xpasswd {
420a5f38d4SDag-Erling Smørgrav 	char		*pw_name;
430a5f38d4SDag-Erling Smørgrav 	char		*pw_passwd;
440a5f38d4SDag-Erling Smørgrav 	uid_t		 pw_uid;
450a5f38d4SDag-Erling Smørgrav 	gid_t		 pw_gid;
460a5f38d4SDag-Erling Smørgrav 	time_t		 pw_change;
470a5f38d4SDag-Erling Smørgrav 	char		*pw_class;
480a5f38d4SDag-Erling Smørgrav 	char		*pw_gecos;
490a5f38d4SDag-Erling Smørgrav 	char		*pw_dir;
500a5f38d4SDag-Erling Smørgrav 	char		*pw_shell;
510a5f38d4SDag-Erling Smørgrav 	time_t		 pw_expire;
520a5f38d4SDag-Erling Smørgrav 	int		 pw_selected;
530a5f38d4SDag-Erling Smørgrav };
540a5f38d4SDag-Erling Smørgrav 
550a5f38d4SDag-Erling Smørgrav struct xgroup {
560a5f38d4SDag-Erling Smørgrav 	char		*gr_name;
570a5f38d4SDag-Erling Smørgrav 	char		*gr_passwd;
580a5f38d4SDag-Erling Smørgrav 	gid_t		 gr_gid;
590a5f38d4SDag-Erling Smørgrav 	char		*gr_mem;
600a5f38d4SDag-Erling Smørgrav };
610a5f38d4SDag-Erling Smørgrav 
620a5f38d4SDag-Erling Smørgrav static int		 everything = 1;
630a5f38d4SDag-Erling Smørgrav static int		 a_flag;
640a5f38d4SDag-Erling Smørgrav static int		 d_flag;
650a5f38d4SDag-Erling Smørgrav static const char	*g_args;
660a5f38d4SDag-Erling Smørgrav static const char	*l_args;
670a5f38d4SDag-Erling Smørgrav static int		 m_flag;
680a5f38d4SDag-Erling Smørgrav static int		 o_flag;
690a5f38d4SDag-Erling Smørgrav static int		 p_flag;
700a5f38d4SDag-Erling Smørgrav static int		 s_flag;
710a5f38d4SDag-Erling Smørgrav static int		 t_flag;
720a5f38d4SDag-Erling Smørgrav static int		 u_flag;
730a5f38d4SDag-Erling Smørgrav static int		 x_flag;
740a5f38d4SDag-Erling Smørgrav 
750a5f38d4SDag-Erling Smørgrav static int
member(const char * elem,const char * list)760a5f38d4SDag-Erling Smørgrav member(const char *elem, const char *list)
770a5f38d4SDag-Erling Smørgrav {
780a5f38d4SDag-Erling Smørgrav 	char *p;
790a5f38d4SDag-Erling Smørgrav 	int len;
800a5f38d4SDag-Erling Smørgrav 
810a5f38d4SDag-Erling Smørgrav 	p = strstr(list, elem);
820a5f38d4SDag-Erling Smørgrav 	len = strlen(elem);
830a5f38d4SDag-Erling Smørgrav 
840a5f38d4SDag-Erling Smørgrav 	return (p != NULL &&
850a5f38d4SDag-Erling Smørgrav 	    (p == list || p[-1] == ',') &&
860a5f38d4SDag-Erling Smørgrav 	    (p[len] == '\0' || p[len] == ','));
870a5f38d4SDag-Erling Smørgrav }
880a5f38d4SDag-Erling Smørgrav 
890a5f38d4SDag-Erling Smørgrav static void *
xmalloc(size_t size)900a5f38d4SDag-Erling Smørgrav xmalloc(size_t size)
910a5f38d4SDag-Erling Smørgrav {
920a5f38d4SDag-Erling Smørgrav 	void *newptr;
930a5f38d4SDag-Erling Smørgrav 
940a5f38d4SDag-Erling Smørgrav 	if ((newptr = malloc(size)) == NULL)
950a5f38d4SDag-Erling Smørgrav 		err(1, "malloc()");
960a5f38d4SDag-Erling Smørgrav 	return (newptr);
970a5f38d4SDag-Erling Smørgrav }
980a5f38d4SDag-Erling Smørgrav 
990a5f38d4SDag-Erling Smørgrav static void *
xrealloc(void * ptr,size_t size)1000a5f38d4SDag-Erling Smørgrav xrealloc(void *ptr, size_t size)
1010a5f38d4SDag-Erling Smørgrav {
1020a5f38d4SDag-Erling Smørgrav 	void *newptr;
1030a5f38d4SDag-Erling Smørgrav 
1040a5f38d4SDag-Erling Smørgrav 	if ((newptr = realloc(ptr, size)) == NULL)
1050a5f38d4SDag-Erling Smørgrav 		err(1, "realloc()");
1060a5f38d4SDag-Erling Smørgrav 	return (newptr);
1070a5f38d4SDag-Erling Smørgrav }
1080a5f38d4SDag-Erling Smørgrav 
1090a5f38d4SDag-Erling Smørgrav static char *
xstrdup(const char * str)1100a5f38d4SDag-Erling Smørgrav xstrdup(const char *str)
1110a5f38d4SDag-Erling Smørgrav {
1120a5f38d4SDag-Erling Smørgrav 	char *dupstr;
1130a5f38d4SDag-Erling Smørgrav 
1140a5f38d4SDag-Erling Smørgrav 	if ((dupstr = strdup(str)) == NULL)
1150a5f38d4SDag-Erling Smørgrav 		err(1, "strdup()");
1160a5f38d4SDag-Erling Smørgrav 	return (dupstr);
1170a5f38d4SDag-Erling Smørgrav }
1180a5f38d4SDag-Erling Smørgrav 
1190a5f38d4SDag-Erling Smørgrav static struct xgroup	*grps;
1200a5f38d4SDag-Erling Smørgrav static size_t		 grpsz;
1210a5f38d4SDag-Erling Smørgrav static size_t		 ngrps;
1220a5f38d4SDag-Erling Smørgrav 
1230a5f38d4SDag-Erling Smørgrav static void
get_groups(void)1240a5f38d4SDag-Erling Smørgrav get_groups(void)
1250a5f38d4SDag-Erling Smørgrav {
1260a5f38d4SDag-Erling Smørgrav 	struct group *grp;
1270a5f38d4SDag-Erling Smørgrav 	size_t len;
1280a5f38d4SDag-Erling Smørgrav 	int i;
1290a5f38d4SDag-Erling Smørgrav 
1300a5f38d4SDag-Erling Smørgrav 	setgrent();
1310a5f38d4SDag-Erling Smørgrav 	for (;;) {
1320a5f38d4SDag-Erling Smørgrav 		if (ngrps == grpsz) {
1330a5f38d4SDag-Erling Smørgrav 			grpsz += grpsz ? grpsz : 128;
1340a5f38d4SDag-Erling Smørgrav 			grps = xrealloc(grps, grpsz * sizeof *grps);
1350a5f38d4SDag-Erling Smørgrav 		}
1360a5f38d4SDag-Erling Smørgrav 		if ((grp = getgrent()) == NULL)
1370a5f38d4SDag-Erling Smørgrav 			break;
1380a5f38d4SDag-Erling Smørgrav 		grps[ngrps].gr_name = xstrdup(grp->gr_name);
1390a5f38d4SDag-Erling Smørgrav 		grps[ngrps].gr_passwd = xstrdup(grp->gr_passwd);
1400a5f38d4SDag-Erling Smørgrav 		grps[ngrps].gr_gid = grp->gr_gid;
1410a5f38d4SDag-Erling Smørgrav 		grps[ngrps].gr_mem = xstrdup("");
1420a5f38d4SDag-Erling Smørgrav 		for (i = 0, len = 1; grp->gr_mem[i] != NULL; ++i)
1430a5f38d4SDag-Erling Smørgrav 			len += strlen(grp->gr_mem[i]) + 1;
1440a5f38d4SDag-Erling Smørgrav 		grps[ngrps].gr_mem = xmalloc(len);
1450a5f38d4SDag-Erling Smørgrav 		for (i = 0, len = 0; grp->gr_mem[i] != NULL; ++i)
1460a5f38d4SDag-Erling Smørgrav 			len += sprintf(grps[ngrps].gr_mem + len,
1470a5f38d4SDag-Erling Smørgrav 			    i ? ",%s" : "%s", grp->gr_mem[i]);
1480a5f38d4SDag-Erling Smørgrav 		grps[ngrps].gr_mem[len] = '\0';
1490a5f38d4SDag-Erling Smørgrav 		ngrps++;
1500a5f38d4SDag-Erling Smørgrav 	}
1510a5f38d4SDag-Erling Smørgrav 	endgrent();
1520a5f38d4SDag-Erling Smørgrav }
1530a5f38d4SDag-Erling Smørgrav 
1540a5f38d4SDag-Erling Smørgrav static struct xgroup *
find_group_bygid(gid_t gid)1550a5f38d4SDag-Erling Smørgrav find_group_bygid(gid_t gid)
1560a5f38d4SDag-Erling Smørgrav {
1570a5f38d4SDag-Erling Smørgrav 	unsigned int i;
1580a5f38d4SDag-Erling Smørgrav 
1590a5f38d4SDag-Erling Smørgrav 	for (i = 0; i < ngrps; ++i)
1600a5f38d4SDag-Erling Smørgrav 		if (grps[i].gr_gid == gid)
1610a5f38d4SDag-Erling Smørgrav 			return (&grps[i]);
1620a5f38d4SDag-Erling Smørgrav 	return (NULL);
1630a5f38d4SDag-Erling Smørgrav }
1640a5f38d4SDag-Erling Smørgrav 
1650a5f38d4SDag-Erling Smørgrav #if 0
1660a5f38d4SDag-Erling Smørgrav static struct xgroup *
1670a5f38d4SDag-Erling Smørgrav find_group_byname(const char *name)
1680a5f38d4SDag-Erling Smørgrav {
1690a5f38d4SDag-Erling Smørgrav 	unsigned int i;
1700a5f38d4SDag-Erling Smørgrav 
1710a5f38d4SDag-Erling Smørgrav 	for (i = 0; i < ngrps; ++i)
1720a5f38d4SDag-Erling Smørgrav 		if (strcmp(grps[i].gr_name, name) == 0)
1730a5f38d4SDag-Erling Smørgrav 			return (&grps[i]);
1740a5f38d4SDag-Erling Smørgrav 	return (NULL);
1750a5f38d4SDag-Erling Smørgrav }
1760a5f38d4SDag-Erling Smørgrav #endif
1770a5f38d4SDag-Erling Smørgrav 
1780a5f38d4SDag-Erling Smørgrav static struct xpasswd	*pwds;
1790a5f38d4SDag-Erling Smørgrav static size_t		 pwdsz;
1800a5f38d4SDag-Erling Smørgrav static size_t		 npwds;
1810a5f38d4SDag-Erling Smørgrav 
1820a5f38d4SDag-Erling Smørgrav static int
pwd_cmp_byname(const void * ap,const void * bp)1830a5f38d4SDag-Erling Smørgrav pwd_cmp_byname(const void *ap, const void *bp)
1840a5f38d4SDag-Erling Smørgrav {
1850a5f38d4SDag-Erling Smørgrav 	const struct passwd *a = ap;
1860a5f38d4SDag-Erling Smørgrav 	const struct passwd *b = bp;
1870a5f38d4SDag-Erling Smørgrav 
1880a5f38d4SDag-Erling Smørgrav 	return (strcmp(a->pw_name, b->pw_name));
1890a5f38d4SDag-Erling Smørgrav }
1900a5f38d4SDag-Erling Smørgrav 
1910a5f38d4SDag-Erling Smørgrav static int
pwd_cmp_byuid(const void * ap,const void * bp)1920a5f38d4SDag-Erling Smørgrav pwd_cmp_byuid(const void *ap, const void *bp)
1930a5f38d4SDag-Erling Smørgrav {
1940a5f38d4SDag-Erling Smørgrav 	const struct passwd *a = ap;
1950a5f38d4SDag-Erling Smørgrav 	const struct passwd *b = bp;
1960a5f38d4SDag-Erling Smørgrav 
1970a5f38d4SDag-Erling Smørgrav 	return (a->pw_uid - b->pw_uid);
1980a5f38d4SDag-Erling Smørgrav }
1990a5f38d4SDag-Erling Smørgrav 
2000a5f38d4SDag-Erling Smørgrav static void
get_users(void)2010a5f38d4SDag-Erling Smørgrav get_users(void)
2020a5f38d4SDag-Erling Smørgrav {
2030a5f38d4SDag-Erling Smørgrav 	struct passwd *pwd;
2040a5f38d4SDag-Erling Smørgrav 
2050a5f38d4SDag-Erling Smørgrav 	setpwent();
2060a5f38d4SDag-Erling Smørgrav 	for (;;) {
2070a5f38d4SDag-Erling Smørgrav 		if (npwds == pwdsz) {
2080a5f38d4SDag-Erling Smørgrav 			pwdsz += pwdsz ? pwdsz : 128;
2090a5f38d4SDag-Erling Smørgrav 			pwds = xrealloc(pwds, pwdsz * sizeof *pwds);
2100a5f38d4SDag-Erling Smørgrav 		}
2110a5f38d4SDag-Erling Smørgrav 		if ((pwd = getpwent()) == NULL)
2120a5f38d4SDag-Erling Smørgrav 			break;
2130a5f38d4SDag-Erling Smørgrav 		pwds[npwds].pw_name = xstrdup(pwd->pw_name);
2140a5f38d4SDag-Erling Smørgrav 		pwds[npwds].pw_passwd = xstrdup(pwd->pw_passwd);
2150a5f38d4SDag-Erling Smørgrav 		pwds[npwds].pw_uid = pwd->pw_uid;
2160a5f38d4SDag-Erling Smørgrav 		pwds[npwds].pw_gid = pwd->pw_gid;
2170a5f38d4SDag-Erling Smørgrav 		pwds[npwds].pw_change = pwd->pw_change;
2180a5f38d4SDag-Erling Smørgrav 		pwds[npwds].pw_class = xstrdup(pwd->pw_class);
2190a5f38d4SDag-Erling Smørgrav 		pwds[npwds].pw_gecos = xstrdup(pwd->pw_gecos);
2200a5f38d4SDag-Erling Smørgrav 		pwds[npwds].pw_dir = xstrdup(pwd->pw_dir);
2210a5f38d4SDag-Erling Smørgrav 		pwds[npwds].pw_shell = xstrdup(pwd->pw_shell);
2220a5f38d4SDag-Erling Smørgrav 		pwds[npwds].pw_expire = pwd->pw_expire;
2230a5f38d4SDag-Erling Smørgrav 		pwds[npwds].pw_selected = 0;
2240a5f38d4SDag-Erling Smørgrav 		npwds++;
2250a5f38d4SDag-Erling Smørgrav 	}
2260a5f38d4SDag-Erling Smørgrav 	endpwent();
2270a5f38d4SDag-Erling Smørgrav }
2280a5f38d4SDag-Erling Smørgrav 
2290a5f38d4SDag-Erling Smørgrav static void
select_users(void)2300a5f38d4SDag-Erling Smørgrav select_users(void)
2310a5f38d4SDag-Erling Smørgrav {
2320a5f38d4SDag-Erling Smørgrav 	unsigned int i, j;
2330a5f38d4SDag-Erling Smørgrav 	struct xgroup *grp;
2340a5f38d4SDag-Erling Smørgrav 	struct xpasswd *pwd;
2350a5f38d4SDag-Erling Smørgrav 
2360a5f38d4SDag-Erling Smørgrav 	for (i = 0, pwd = pwds; i < npwds; ++i, ++pwd) {
2370a5f38d4SDag-Erling Smørgrav 		if (everything) {
2380a5f38d4SDag-Erling Smørgrav 			pwd->pw_selected = 1;
2390a5f38d4SDag-Erling Smørgrav 			continue;
2400a5f38d4SDag-Erling Smørgrav 		}
2410a5f38d4SDag-Erling Smørgrav 		if (d_flag)
2420a5f38d4SDag-Erling Smørgrav 			if ((i > 0 && pwd->pw_uid == pwd[-1].pw_uid) ||
2430a5f38d4SDag-Erling Smørgrav 			    (i < npwds - 1 && pwd->pw_uid == pwd[1].pw_uid)) {
2440a5f38d4SDag-Erling Smørgrav 				pwd->pw_selected = 1;
2450a5f38d4SDag-Erling Smørgrav 				continue;
2460a5f38d4SDag-Erling Smørgrav 			}
2470a5f38d4SDag-Erling Smørgrav 		if (g_args) {
2480a5f38d4SDag-Erling Smørgrav 			for (j = 0, grp = grps; j < ngrps; ++j, ++grp) {
2490a5f38d4SDag-Erling Smørgrav 				if (member(grp->gr_name, g_args) &&
2500a5f38d4SDag-Erling Smørgrav 				    member(pwd->pw_name, grp->gr_mem)) {
2510a5f38d4SDag-Erling Smørgrav 					pwd->pw_selected = 1;
2520a5f38d4SDag-Erling Smørgrav 					break;
2530a5f38d4SDag-Erling Smørgrav 				}
2540a5f38d4SDag-Erling Smørgrav 			}
2550a5f38d4SDag-Erling Smørgrav 			if (pwd->pw_selected)
2560a5f38d4SDag-Erling Smørgrav 				continue;
2570a5f38d4SDag-Erling Smørgrav 		}
2580a5f38d4SDag-Erling Smørgrav 		if (l_args)
2590a5f38d4SDag-Erling Smørgrav 			if (member(pwd->pw_name, l_args)) {
2600a5f38d4SDag-Erling Smørgrav 				pwd->pw_selected = 1;
2610a5f38d4SDag-Erling Smørgrav 				continue;
2620a5f38d4SDag-Erling Smørgrav 			}
2630a5f38d4SDag-Erling Smørgrav 		if (p_flag)
2640a5f38d4SDag-Erling Smørgrav 			if (pwd->pw_passwd[0] == '\0') {
2650a5f38d4SDag-Erling Smørgrav 				pwd->pw_selected = 1;
2660a5f38d4SDag-Erling Smørgrav 				continue;
2670a5f38d4SDag-Erling Smørgrav 			}
2680a5f38d4SDag-Erling Smørgrav 		if (s_flag)
2690a5f38d4SDag-Erling Smørgrav 			if (pwd->pw_uid < 1000 || pwd->pw_uid == 65534) {
2700a5f38d4SDag-Erling Smørgrav 				pwd->pw_selected = 1;
2710a5f38d4SDag-Erling Smørgrav 				continue;
2720a5f38d4SDag-Erling Smørgrav 			}
2730a5f38d4SDag-Erling Smørgrav 		if (u_flag)
2740a5f38d4SDag-Erling Smørgrav 			if (pwd->pw_uid >= 1000 && pwd->pw_uid != 65534) {
2750a5f38d4SDag-Erling Smørgrav 				pwd->pw_selected = 1;
2760a5f38d4SDag-Erling Smørgrav 				continue;
2770a5f38d4SDag-Erling Smørgrav 			}
2780a5f38d4SDag-Erling Smørgrav 	}
2790a5f38d4SDag-Erling Smørgrav }
2800a5f38d4SDag-Erling Smørgrav 
2810a5f38d4SDag-Erling Smørgrav static void
sort_users(void)2820a5f38d4SDag-Erling Smørgrav sort_users(void)
2830a5f38d4SDag-Erling Smørgrav {
2840a5f38d4SDag-Erling Smørgrav 	if (t_flag)
2850a5f38d4SDag-Erling Smørgrav 		mergesort(pwds, npwds, sizeof *pwds, pwd_cmp_byname);
2860a5f38d4SDag-Erling Smørgrav 	else
2870a5f38d4SDag-Erling Smørgrav 		mergesort(pwds, npwds, sizeof *pwds, pwd_cmp_byuid);
2880a5f38d4SDag-Erling Smørgrav }
2890a5f38d4SDag-Erling Smørgrav 
2900a5f38d4SDag-Erling Smørgrav static void
display_user(struct xpasswd * pwd)2910a5f38d4SDag-Erling Smørgrav display_user(struct xpasswd *pwd)
2920a5f38d4SDag-Erling Smørgrav {
2930a5f38d4SDag-Erling Smørgrav 	struct xgroup *grp;
2940a5f38d4SDag-Erling Smørgrav 	unsigned int i;
2950a5f38d4SDag-Erling Smørgrav 	char cbuf[16], ebuf[16];
2960a5f38d4SDag-Erling Smørgrav 	struct tm *tm;
2970a5f38d4SDag-Erling Smørgrav 
2980a5f38d4SDag-Erling Smørgrav 	grp = find_group_bygid(pwd->pw_gid);
2990a5f38d4SDag-Erling Smørgrav 	printf(o_flag ? "%s:%ld:%s:%ld:%s" : "%-15s %-7ld %-15s %-7ld %s\n",
3000a5f38d4SDag-Erling Smørgrav 	    pwd->pw_name, (long)pwd->pw_uid, grp ? grp->gr_name : "",
3010a5f38d4SDag-Erling Smørgrav 	    (long)pwd->pw_gid, pwd->pw_gecos);
3020a5f38d4SDag-Erling Smørgrav 	if (m_flag) {
3030a5f38d4SDag-Erling Smørgrav 		for (i = 0, grp = grps; i < ngrps; ++i, ++grp) {
3040a5f38d4SDag-Erling Smørgrav 			if (grp->gr_gid == pwd->pw_gid ||
3050a5f38d4SDag-Erling Smørgrav 			    !member(pwd->pw_name, grp->gr_mem))
3060a5f38d4SDag-Erling Smørgrav 				continue;
3070a5f38d4SDag-Erling Smørgrav 			printf(o_flag ? "%s:%s:%ld" : "%24s%-15s %-7ld\n",
3080a5f38d4SDag-Erling Smørgrav 			    "", grp->gr_name, (long)grp->gr_gid);
3090a5f38d4SDag-Erling Smørgrav 		}
3100a5f38d4SDag-Erling Smørgrav 	}
3110a5f38d4SDag-Erling Smørgrav 	if (x_flag) {
3120a5f38d4SDag-Erling Smørgrav 		printf(o_flag ? "%s:%s" : "%24s%s\n", "", pwd->pw_dir);
3130a5f38d4SDag-Erling Smørgrav 		printf(o_flag ? "%s:%s" : "%24s%s\n", "", pwd->pw_shell);
3140a5f38d4SDag-Erling Smørgrav 	}
3150a5f38d4SDag-Erling Smørgrav 	if (a_flag) {
3160a5f38d4SDag-Erling Smørgrav 		tm = gmtime(&pwd->pw_change);
3170a5f38d4SDag-Erling Smørgrav 		strftime(cbuf, sizeof(cbuf), pwd->pw_change ? "%F" : "0", tm);
3180a5f38d4SDag-Erling Smørgrav 		tm = gmtime(&pwd->pw_expire);
3190a5f38d4SDag-Erling Smørgrav 		strftime(ebuf, sizeof(ebuf), pwd->pw_expire ? "%F" : "0", tm);
3200a5f38d4SDag-Erling Smørgrav 		printf(o_flag ? "%s:%s:%s" : "%24s%s %s\n", "", cbuf, ebuf);
3210a5f38d4SDag-Erling Smørgrav 	}
3220a5f38d4SDag-Erling Smørgrav 	if (o_flag)
3230a5f38d4SDag-Erling Smørgrav 		printf("\n");
3240a5f38d4SDag-Erling Smørgrav }
3250a5f38d4SDag-Erling Smørgrav 
3260a5f38d4SDag-Erling Smørgrav static void
list_users(void)3270a5f38d4SDag-Erling Smørgrav list_users(void)
3280a5f38d4SDag-Erling Smørgrav {
3290a5f38d4SDag-Erling Smørgrav 	struct xpasswd *pwd;
3300a5f38d4SDag-Erling Smørgrav 	unsigned int i;
3310a5f38d4SDag-Erling Smørgrav 
3320a5f38d4SDag-Erling Smørgrav 	for (i = 0, pwd = pwds; i < npwds; ++i, ++pwd)
3330a5f38d4SDag-Erling Smørgrav 		if (pwd->pw_selected)
3340a5f38d4SDag-Erling Smørgrav 			display_user(pwd);
3350a5f38d4SDag-Erling Smørgrav }
3360a5f38d4SDag-Erling Smørgrav 
3370a5f38d4SDag-Erling Smørgrav static void
usage(void)3380a5f38d4SDag-Erling Smørgrav usage(void)
3390a5f38d4SDag-Erling Smørgrav {
3400a5f38d4SDag-Erling Smørgrav 	fprintf(stderr, "usage: logins [-admopstux] [-g group] [-l login]\n");
3410a5f38d4SDag-Erling Smørgrav 	exit(1);
3420a5f38d4SDag-Erling Smørgrav }
3430a5f38d4SDag-Erling Smørgrav 
3440a5f38d4SDag-Erling Smørgrav int
main(int argc,char * const argv[])3450a5f38d4SDag-Erling Smørgrav main(int argc, char * const argv[])
3460a5f38d4SDag-Erling Smørgrav {
3470a5f38d4SDag-Erling Smørgrav 	int o;
3480a5f38d4SDag-Erling Smørgrav 
3490a5f38d4SDag-Erling Smørgrav 	while ((o = getopt(argc, argv, "adg:l:mopstux")) != -1)
3500a5f38d4SDag-Erling Smørgrav 		switch (o) {
3510a5f38d4SDag-Erling Smørgrav 		case 'a':
3520a5f38d4SDag-Erling Smørgrav 			a_flag = 1;
3530a5f38d4SDag-Erling Smørgrav 			break;
3540a5f38d4SDag-Erling Smørgrav 		case 'd':
3550a5f38d4SDag-Erling Smørgrav 			everything = 0;
3560a5f38d4SDag-Erling Smørgrav 			d_flag = 1;
3570a5f38d4SDag-Erling Smørgrav 			break;
3580a5f38d4SDag-Erling Smørgrav 		case 'g':
3590a5f38d4SDag-Erling Smørgrav 			everything = 0;
3600a5f38d4SDag-Erling Smørgrav 			g_args = optarg;
3610a5f38d4SDag-Erling Smørgrav 			break;
3620a5f38d4SDag-Erling Smørgrav 		case 'l':
3630a5f38d4SDag-Erling Smørgrav 			everything = 0;
3640a5f38d4SDag-Erling Smørgrav 			l_args = optarg;
3650a5f38d4SDag-Erling Smørgrav 			break;
3660a5f38d4SDag-Erling Smørgrav 		case 'm':
3670a5f38d4SDag-Erling Smørgrav 			m_flag = 1;
3680a5f38d4SDag-Erling Smørgrav 			break;
3690a5f38d4SDag-Erling Smørgrav 		case 'o':
3700a5f38d4SDag-Erling Smørgrav 			o_flag = 1;
3710a5f38d4SDag-Erling Smørgrav 			break;
3720a5f38d4SDag-Erling Smørgrav 		case 'p':
3730a5f38d4SDag-Erling Smørgrav 			everything = 0;
3740a5f38d4SDag-Erling Smørgrav 			p_flag = 1;
3750a5f38d4SDag-Erling Smørgrav 			break;
3760a5f38d4SDag-Erling Smørgrav 		case 's':
3770a5f38d4SDag-Erling Smørgrav 			everything = 0;
3780a5f38d4SDag-Erling Smørgrav 			s_flag = 1;
3790a5f38d4SDag-Erling Smørgrav 			break;
3800a5f38d4SDag-Erling Smørgrav 		case 't':
3810a5f38d4SDag-Erling Smørgrav 			t_flag = 1;
3820a5f38d4SDag-Erling Smørgrav 			break;
3830a5f38d4SDag-Erling Smørgrav 		case 'u':
3840a5f38d4SDag-Erling Smørgrav 			everything = 0;
3850a5f38d4SDag-Erling Smørgrav 			u_flag = 1;
3860a5f38d4SDag-Erling Smørgrav 			break;
3870a5f38d4SDag-Erling Smørgrav 		case 'x':
3880a5f38d4SDag-Erling Smørgrav 			x_flag = 1;
3890a5f38d4SDag-Erling Smørgrav 			break;
3900a5f38d4SDag-Erling Smørgrav 		default:
3910a5f38d4SDag-Erling Smørgrav 			usage();
3920a5f38d4SDag-Erling Smørgrav 		}
3930a5f38d4SDag-Erling Smørgrav 
3940a5f38d4SDag-Erling Smørgrav 	argc -= optind;
3950a5f38d4SDag-Erling Smørgrav 	argv += optind;
3960a5f38d4SDag-Erling Smørgrav 
3970a5f38d4SDag-Erling Smørgrav 	if (argc > 0)
3980a5f38d4SDag-Erling Smørgrav 		usage();
3990a5f38d4SDag-Erling Smørgrav 
4000a5f38d4SDag-Erling Smørgrav 	get_groups();
4010a5f38d4SDag-Erling Smørgrav 	get_users();
4020a5f38d4SDag-Erling Smørgrav 	select_users();
4030a5f38d4SDag-Erling Smørgrav 	sort_users();
4040a5f38d4SDag-Erling Smørgrav 	list_users();
4050a5f38d4SDag-Erling Smørgrav 	exit(0);
4060a5f38d4SDag-Erling Smørgrav }
407