summaryrefslogtreecommitdiffstats
path: root/usr.bin/logins
diff options
context:
space:
mode:
authordes <des@FreeBSD.org>2004-03-06 21:57:29 +0000
committerdes <des@FreeBSD.org>2004-03-06 21:57:29 +0000
commit247bd59f13fc0777833da0ad618a144295b02e94 (patch)
tree304e0954e0c76195af5e139e035723c6e914ede8 /usr.bin/logins
parente82ea43f3939a4c4cdb2d93371a876038560f5b8 (diff)
downloadFreeBSD-src-247bd59f13fc0777833da0ad618a144295b02e94.zip
FreeBSD-src-247bd59f13fc0777833da0ad618a144295b02e94.tar.gz
Add a logins(1) utility similar to that found in SVr4 derivatives. This
particular implementation is based on the Solaris logins(1) man page.
Diffstat (limited to 'usr.bin/logins')
-rw-r--r--usr.bin/logins/Makefile6
-rw-r--r--usr.bin/logins/logins.1105
-rw-r--r--usr.bin/logins/logins.c408
3 files changed, 519 insertions, 0 deletions
diff --git a/usr.bin/logins/Makefile b/usr.bin/logins/Makefile
new file mode 100644
index 0000000..42840fb
--- /dev/null
+++ b/usr.bin/logins/Makefile
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+PROG= logins
+WARNS?= 6
+
+.include <bsd.prog.mk>
diff --git a/usr.bin/logins/logins.1 b/usr.bin/logins/logins.1
new file mode 100644
index 0000000..c6680b6
--- /dev/null
+++ b/usr.bin/logins/logins.1
@@ -0,0 +1,105 @@
+.\"-
+.\" Copyright (c) 2004 Dag-Erling Coïdan Smørgrav
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd March 6, 2004
+.Dt LOGINS 1
+.Os
+.Sh NAME
+.Nm logins
+.Nd display account information
+.Sh SYNOPSIS
+.Nm
+.Op Fl admopstux
+.Op Fl g Ar groups
+.Op Fl l Ar logins
+.Sh DESCRIPTION
+The
+.Nm
+utility displays information about user and system accounts.
+.Pp
+The following options are available:
+.Bl -tag -width Fl
+.It Fl a
+Display information about the password change and account expiration
+times for each account.
+.It Fl d
+Select accounts with duplicate UIDs.
+.It Fl g Ar groups
+Select accounts that are members of the specified groups.
+If multiple group names are specified, they must be separated with
+commas.
+.It Fl l Ar logins
+Select accounts matching the specified login names.
+If multiple names are specified, they must be separated with commas.
+.It Fl m
+Show information about secondary groups.
+.It Fl o
+Display the information for each account on a single line of
+colon-separated fields.
+.It Fl p
+Select accounts with no password.
+.It Fl s
+Select system accounts.
+This is currently defined as accounts with UIDs below 1000, plus the
+.Dq nobody
+account (UID 65534).
+.It Fl t
+Sort selected accounts by name rather than by UID.
+.It Fl u
+Select user accounts.
+These are currently defined as accounts with UIDs above 1000, except
+the
+.Dq nobody
+account (UID 65534).
+.It Fl x
+Display information about each account's home directory and shell.
+.El
+.Pp
+If multiple selection options are specified, all accounts matching any
+of the selection criteria will be displayed.
+.Pp
+If no selection options are specified, all acounts will be displayed.
+.Sh SEE ALSO
+.Xr getgrent 3 ,
+.Xr getpwent 3 ,
+.Xr group 5 ,
+.Xr passwd 5 ,
+.Xr pw 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Fx 4.10 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+utility was written by
+.An Dag-Erling Sm\(/orgrav Aq des@FreeBSD.org
+based on similar utilities in other operating systems.
diff --git a/usr.bin/logins/logins.c b/usr.bin/logins/logins.c
new file mode 100644
index 0000000..abf342e
--- /dev/null
+++ b/usr.bin/logins/logins.c
@@ -0,0 +1,408 @@
+/*-
+ * Copyright (c) 2004 Dag-Erling Coïdan Smørgrav
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+struct xpasswd {
+ char *pw_name;
+ char *pw_passwd;
+ uid_t pw_uid;
+ gid_t pw_gid;
+ time_t pw_change;
+ char *pw_class;
+ char *pw_gecos;
+ char *pw_dir;
+ char *pw_shell;
+ time_t pw_expire;
+ int pw_selected;
+};
+
+struct xgroup {
+ char *gr_name;
+ char *gr_passwd;
+ gid_t gr_gid;
+ char *gr_mem;
+};
+
+static int everything = 1;
+static int a_flag;
+static int d_flag;
+static const char *g_args;
+static const char *l_args;
+static int m_flag;
+static int o_flag;
+static int p_flag;
+static int s_flag;
+static int t_flag;
+static int u_flag;
+static int x_flag;
+
+static int
+member(const char *elem, const char *list)
+{
+ char *p;
+ int len;
+
+ p = strstr(list, elem);
+ len = strlen(elem);
+
+ return (p != NULL &&
+ (p == list || p[-1] == ',') &&
+ (p[len] == '\0' || p[len] == ','));
+}
+
+static void *
+xmalloc(size_t size)
+{
+ void *newptr;
+
+ if ((newptr = malloc(size)) == NULL)
+ err(1, "malloc()");
+ return (newptr);
+}
+
+static void *
+xrealloc(void *ptr, size_t size)
+{
+ void *newptr;
+
+ if ((newptr = realloc(ptr, size)) == NULL)
+ err(1, "realloc()");
+ return (newptr);
+}
+
+static char *
+xstrdup(const char *str)
+{
+ char *dupstr;
+
+ if ((dupstr = strdup(str)) == NULL)
+ err(1, "strdup()");
+ return (dupstr);
+}
+
+static struct xgroup *grps;
+static size_t grpsz;
+static size_t ngrps;
+
+static void
+get_groups(void)
+{
+ struct group *grp;
+ size_t len;
+ int i;
+
+ setgrent();
+ for (;;) {
+ if (ngrps == grpsz) {
+ grpsz += grpsz ? grpsz : 128;
+ grps = xrealloc(grps, grpsz * sizeof *grps);
+ }
+ if ((grp = getgrent()) == NULL)
+ break;
+ grps[ngrps].gr_name = xstrdup(grp->gr_name);
+ grps[ngrps].gr_passwd = xstrdup(grp->gr_passwd);
+ grps[ngrps].gr_gid = grp->gr_gid;
+ grps[ngrps].gr_mem = xstrdup("");
+ for (i = 0, len = 1; grp->gr_mem[i] != NULL; ++i)
+ len += strlen(grp->gr_mem[i]) + 1;
+ grps[ngrps].gr_mem = xmalloc(len);
+ for (i = 0, len = 0; grp->gr_mem[i] != NULL; ++i)
+ len += sprintf(grps[ngrps].gr_mem + len,
+ i ? ",%s" : "%s", grp->gr_mem[i]);
+ grps[ngrps].gr_mem[len] = '\0';
+ ngrps++;
+ }
+ endgrent();
+}
+
+static struct xgroup *
+find_group_bygid(gid_t gid)
+{
+ unsigned int i;
+
+ for (i = 0; i < ngrps; ++i)
+ if (grps[i].gr_gid == gid)
+ return (&grps[i]);
+ return (NULL);
+}
+
+#if 0
+static struct xgroup *
+find_group_byname(const char *name)
+{
+ unsigned int i;
+
+ for (i = 0; i < ngrps; ++i)
+ if (strcmp(grps[i].gr_name, name) == 0)
+ return (&grps[i]);
+ return (NULL);
+}
+#endif
+
+static struct xpasswd *pwds;
+static size_t pwdsz;
+static size_t npwds;
+
+static int
+pwd_cmp_byname(const void *ap, const void *bp)
+{
+ const struct passwd *a = ap;
+ const struct passwd *b = bp;
+
+ return (strcmp(a->pw_name, b->pw_name));
+}
+
+static int
+pwd_cmp_byuid(const void *ap, const void *bp)
+{
+ const struct passwd *a = ap;
+ const struct passwd *b = bp;
+
+ return (a->pw_uid - b->pw_uid);
+}
+
+static void
+get_users(void)
+{
+ struct passwd *pwd;
+
+ setpwent();
+ for (;;) {
+ if (npwds == pwdsz) {
+ pwdsz += pwdsz ? pwdsz : 128;
+ pwds = xrealloc(pwds, pwdsz * sizeof *pwds);
+ }
+ if ((pwd = getpwent()) == NULL)
+ break;
+ pwds[npwds].pw_name = xstrdup(pwd->pw_name);
+ pwds[npwds].pw_passwd = xstrdup(pwd->pw_passwd);
+ pwds[npwds].pw_uid = pwd->pw_uid;
+ pwds[npwds].pw_gid = pwd->pw_gid;
+ pwds[npwds].pw_change = pwd->pw_change;
+ pwds[npwds].pw_class = xstrdup(pwd->pw_class);
+ pwds[npwds].pw_gecos = xstrdup(pwd->pw_gecos);
+ pwds[npwds].pw_dir = xstrdup(pwd->pw_dir);
+ pwds[npwds].pw_shell = xstrdup(pwd->pw_shell);
+ pwds[npwds].pw_expire = pwd->pw_expire;
+ pwds[npwds].pw_selected = 0;
+ npwds++;
+ }
+ endpwent();
+}
+
+static void
+select_users(void)
+{
+ unsigned int i, j;
+ struct xgroup *grp;
+ struct xpasswd *pwd;
+
+ for (i = 0, pwd = pwds; i < npwds; ++i, ++pwd) {
+ if (everything) {
+ pwd->pw_selected = 1;
+ continue;
+ }
+ if (d_flag)
+ if ((i > 0 && pwd->pw_uid == pwd[-1].pw_uid) ||
+ (i < npwds - 1 && pwd->pw_uid == pwd[1].pw_uid)) {
+ pwd->pw_selected = 1;
+ continue;
+ }
+ if (g_args) {
+ for (j = 0, grp = grps; j < ngrps; ++j, ++grp) {
+ if (member(grp->gr_name, g_args) &&
+ member(pwd->pw_name, grp->gr_mem)) {
+ pwd->pw_selected = 1;
+ break;
+ }
+ }
+ if (pwd->pw_selected)
+ continue;
+ }
+ if (l_args)
+ if (member(pwd->pw_name, l_args)) {
+ pwd->pw_selected = 1;
+ continue;
+ }
+ if (p_flag)
+ if (pwd->pw_passwd[0] == '\0') {
+ pwd->pw_selected = 1;
+ continue;
+ }
+ if (s_flag)
+ if (pwd->pw_uid < 1000 || pwd->pw_uid == 65534) {
+ pwd->pw_selected = 1;
+ continue;
+ }
+ if (u_flag)
+ if (pwd->pw_uid >= 1000 && pwd->pw_uid != 65534) {
+ pwd->pw_selected = 1;
+ continue;
+ }
+ }
+}
+
+static void
+sort_users(void)
+{
+ if (t_flag)
+ mergesort(pwds, npwds, sizeof *pwds, pwd_cmp_byname);
+ else
+ mergesort(pwds, npwds, sizeof *pwds, pwd_cmp_byuid);
+}
+
+static void
+display_user(struct xpasswd *pwd)
+{
+ struct xgroup *grp;
+ unsigned int i;
+ char cbuf[16], ebuf[16];
+ struct tm *tm;
+
+ grp = find_group_bygid(pwd->pw_gid);
+ printf(o_flag ? "%s:%ld:%s:%ld:%s" : "%-15s %-7ld %-15s %-7ld %s\n",
+ pwd->pw_name, (long)pwd->pw_uid, grp ? grp->gr_name : "",
+ (long)pwd->pw_gid, pwd->pw_gecos);
+ if (m_flag) {
+ for (i = 0, grp = grps; i < ngrps; ++i, ++grp) {
+ if (grp->gr_gid == pwd->pw_gid ||
+ !member(pwd->pw_name, grp->gr_mem))
+ continue;
+ printf(o_flag ? "%s:%s:%ld" : "%24s%-15s %-7ld\n",
+ "", grp->gr_name, (long)grp->gr_gid);
+ }
+ }
+ if (x_flag) {
+ printf(o_flag ? "%s:%s" : "%24s%s\n", "", pwd->pw_dir);
+ printf(o_flag ? "%s:%s" : "%24s%s\n", "", pwd->pw_shell);
+ }
+ if (a_flag) {
+ tm = gmtime(&pwd->pw_change);
+ strftime(cbuf, sizeof(cbuf), pwd->pw_change ? "%F" : "0", tm);
+ tm = gmtime(&pwd->pw_expire);
+ strftime(ebuf, sizeof(ebuf), pwd->pw_expire ? "%F" : "0", tm);
+ printf(o_flag ? "%s:%s:%s" : "%24s%s %s\n", "", cbuf, ebuf);
+ }
+ if (o_flag)
+ printf("\n");
+}
+
+static void
+list_users(void)
+{
+ struct xpasswd *pwd;
+ unsigned int i;
+
+ for (i = 0, pwd = pwds; i < npwds; ++i, ++pwd)
+ if (pwd->pw_selected)
+ display_user(pwd);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: logins [-admopstux] [-g group] [-l login]\n");
+ exit(1);
+}
+
+int
+main(int argc, char * const argv[])
+{
+ int o;
+
+ while ((o = getopt(argc, argv, "adg:l:mopstux")) != -1)
+ switch (o) {
+ case 'a':
+ a_flag = 1;
+ break;
+ case 'd':
+ everything = 0;
+ d_flag = 1;
+ break;
+ case 'g':
+ everything = 0;
+ g_args = optarg;
+ break;
+ case 'l':
+ everything = 0;
+ l_args = optarg;
+ break;
+ case 'm':
+ m_flag = 1;
+ break;
+ case 'o':
+ o_flag = 1;
+ break;
+ case 'p':
+ everything = 0;
+ p_flag = 1;
+ break;
+ case 's':
+ everything = 0;
+ s_flag = 1;
+ break;
+ case 't':
+ t_flag = 1;
+ break;
+ case 'u':
+ everything = 0;
+ u_flag = 1;
+ break;
+ case 'x':
+ x_flag = 1;
+ break;
+ default:
+ usage();
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 0)
+ usage();
+
+ get_groups();
+ get_users();
+ select_users();
+ sort_users();
+ list_users();
+ exit(0);
+}
OpenPOWER on IntegriCloud