2 * Copyright (c) 2004 Dag-Erling Coïdan Smørgrav
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer
10 * in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
64 static int everything = 1;
67 static const char *g_args;
68 static const char *l_args;
78 member(const char *elem, const char *list)
83 p = strstr(list, elem);
87 (p == list || p[-1] == ',') &&
88 (p[len] == '\0' || p[len] == ','));
96 if ((newptr = malloc(size)) == NULL)
102 xrealloc(void *ptr, size_t size)
106 if ((newptr = realloc(ptr, size)) == NULL)
112 xstrdup(const char *str)
116 if ((dupstr = strdup(str)) == NULL)
121 static struct xgroup *grps;
134 if (ngrps == grpsz) {
135 grpsz += grpsz ? grpsz : 128;
136 grps = xrealloc(grps, grpsz * sizeof *grps);
138 if ((grp = getgrent()) == NULL)
140 grps[ngrps].gr_name = xstrdup(grp->gr_name);
141 grps[ngrps].gr_passwd = xstrdup(grp->gr_passwd);
142 grps[ngrps].gr_gid = grp->gr_gid;
143 grps[ngrps].gr_mem = xstrdup("");
144 for (i = 0, len = 1; grp->gr_mem[i] != NULL; ++i)
145 len += strlen(grp->gr_mem[i]) + 1;
146 grps[ngrps].gr_mem = xmalloc(len);
147 for (i = 0, len = 0; grp->gr_mem[i] != NULL; ++i)
148 len += sprintf(grps[ngrps].gr_mem + len,
149 i ? ",%s" : "%s", grp->gr_mem[i]);
150 grps[ngrps].gr_mem[len] = '\0';
156 static struct xgroup *
157 find_group_bygid(gid_t gid)
161 for (i = 0; i < ngrps; ++i)
162 if (grps[i].gr_gid == gid)
168 static struct xgroup *
169 find_group_byname(const char *name)
173 for (i = 0; i < ngrps; ++i)
174 if (strcmp(grps[i].gr_name, name) == 0)
180 static struct xpasswd *pwds;
185 pwd_cmp_byname(const void *ap, const void *bp)
187 const struct passwd *a = ap;
188 const struct passwd *b = bp;
190 return (strcmp(a->pw_name, b->pw_name));
194 pwd_cmp_byuid(const void *ap, const void *bp)
196 const struct passwd *a = ap;
197 const struct passwd *b = bp;
199 return (a->pw_uid - b->pw_uid);
209 if (npwds == pwdsz) {
210 pwdsz += pwdsz ? pwdsz : 128;
211 pwds = xrealloc(pwds, pwdsz * sizeof *pwds);
213 if ((pwd = getpwent()) == NULL)
215 pwds[npwds].pw_name = xstrdup(pwd->pw_name);
216 pwds[npwds].pw_passwd = xstrdup(pwd->pw_passwd);
217 pwds[npwds].pw_uid = pwd->pw_uid;
218 pwds[npwds].pw_gid = pwd->pw_gid;
219 pwds[npwds].pw_change = pwd->pw_change;
220 pwds[npwds].pw_class = xstrdup(pwd->pw_class);
221 pwds[npwds].pw_gecos = xstrdup(pwd->pw_gecos);
222 pwds[npwds].pw_dir = xstrdup(pwd->pw_dir);
223 pwds[npwds].pw_shell = xstrdup(pwd->pw_shell);
224 pwds[npwds].pw_expire = pwd->pw_expire;
225 pwds[npwds].pw_selected = 0;
238 for (i = 0, pwd = pwds; i < npwds; ++i, ++pwd) {
240 pwd->pw_selected = 1;
244 if ((i > 0 && pwd->pw_uid == pwd[-1].pw_uid) ||
245 (i < npwds - 1 && pwd->pw_uid == pwd[1].pw_uid)) {
246 pwd->pw_selected = 1;
250 for (j = 0, grp = grps; j < ngrps; ++j, ++grp) {
251 if (member(grp->gr_name, g_args) &&
252 member(pwd->pw_name, grp->gr_mem)) {
253 pwd->pw_selected = 1;
257 if (pwd->pw_selected)
261 if (member(pwd->pw_name, l_args)) {
262 pwd->pw_selected = 1;
266 if (pwd->pw_passwd[0] == '\0') {
267 pwd->pw_selected = 1;
271 if (pwd->pw_uid < 1000 || pwd->pw_uid == 65534) {
272 pwd->pw_selected = 1;
276 if (pwd->pw_uid >= 1000 && pwd->pw_uid != 65534) {
277 pwd->pw_selected = 1;
287 mergesort(pwds, npwds, sizeof *pwds, pwd_cmp_byname);
289 mergesort(pwds, npwds, sizeof *pwds, pwd_cmp_byuid);
293 display_user(struct xpasswd *pwd)
297 char cbuf[16], ebuf[16];
300 grp = find_group_bygid(pwd->pw_gid);
301 printf(o_flag ? "%s:%ld:%s:%ld:%s" : "%-15s %-7ld %-15s %-7ld %s\n",
302 pwd->pw_name, (long)pwd->pw_uid, grp ? grp->gr_name : "",
303 (long)pwd->pw_gid, pwd->pw_gecos);
305 for (i = 0, grp = grps; i < ngrps; ++i, ++grp) {
306 if (grp->gr_gid == pwd->pw_gid ||
307 !member(pwd->pw_name, grp->gr_mem))
309 printf(o_flag ? "%s:%s:%ld" : "%24s%-15s %-7ld\n",
310 "", grp->gr_name, (long)grp->gr_gid);
314 printf(o_flag ? "%s:%s" : "%24s%s\n", "", pwd->pw_dir);
315 printf(o_flag ? "%s:%s" : "%24s%s\n", "", pwd->pw_shell);
318 tm = gmtime(&pwd->pw_change);
319 strftime(cbuf, sizeof(cbuf), pwd->pw_change ? "%F" : "0", tm);
320 tm = gmtime(&pwd->pw_expire);
321 strftime(ebuf, sizeof(ebuf), pwd->pw_expire ? "%F" : "0", tm);
322 printf(o_flag ? "%s:%s:%s" : "%24s%s %s\n", "", cbuf, ebuf);
334 for (i = 0, pwd = pwds; i < npwds; ++i, ++pwd)
335 if (pwd->pw_selected)
342 fprintf(stderr, "usage: logins [-admopstux] [-g group] [-l login]\n");
347 main(int argc, char * const argv[])
351 while ((o = getopt(argc, argv, "adg:l:mopstux")) != -1)