1/* GNU's users.
2   Copyright (C) 1992-2005, 2007-2010 Free Software Foundation, Inc.
3
4   This program is free software: you can redistribute it and/or modify
5   it under the terms of the GNU General Public License as published by
6   the Free Software Foundation, either version 3 of the License, or
7   (at your option) any later version.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13
14   You should have received a copy of the GNU General Public License
15   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17/* Written by jla; revised by djm */
18
19#include <config.h>
20#include <getopt.h>
21#include <stdio.h>
22
23#include <sys/types.h>
24#include "system.h"
25
26#include "error.h"
27#include "long-options.h"
28#include "quote.h"
29#include "readutmp.h"
30
31/* The official name of this program (e.g., no `g' prefix).  */
32#define PROGRAM_NAME "users"
33
34#define AUTHORS \
35  proper_name ("Joseph Arceneaux"), \
36  proper_name ("David MacKenzie")
37
38static int
39userid_compare (const void *v_a, const void *v_b)
40{
41  char **a = (char **) v_a;
42  char **b = (char **) v_b;
43  return strcmp (*a, *b);
44}
45
46static void
47list_entries_users (size_t n, const STRUCT_UTMP *this)
48{
49  char **u = xnmalloc (n, sizeof *u);
50  size_t i;
51  size_t n_entries = 0;
52
53  while (n--)
54    {
55      if (IS_USER_PROCESS (this))
56        {
57          char *trimmed_name;
58
59          trimmed_name = extract_trimmed_name (this);
60
61          u[n_entries] = trimmed_name;
62          ++n_entries;
63        }
64      this++;
65    }
66
67  qsort (u, n_entries, sizeof (u[0]), userid_compare);
68
69  for (i = 0; i < n_entries; i++)
70    {
71      char c = (i < n_entries - 1 ? ' ' : '\n');
72      fputs (u[i], stdout);
73      putchar (c);
74    }
75
76  for (i = 0; i < n_entries; i++)
77    free (u[i]);
78  free (u);
79}
80
81/* Display a list of users on the system, according to utmp file FILENAME.
82   Use read_utmp OPTIONS to read FILENAME.  */
83
84static void
85users (const char *filename, int options)
86{
87  size_t n_users;
88  STRUCT_UTMP *utmp_buf;
89
90  if (read_utmp (filename, &n_users, &utmp_buf, options) != 0)
91    error (EXIT_FAILURE, errno, "%s", filename);
92
93  list_entries_users (n_users, utmp_buf);
94
95  free (utmp_buf);
96}
97
98void
99usage (int status)
100{
101  if (status != EXIT_SUCCESS)
102    fprintf (stderr, _("Try `%s --help' for more information.\n"),
103             program_name);
104  else
105    {
106      printf (_("Usage: %s [OPTION]... [FILE]\n"), program_name);
107      printf (_("\
108Output who is currently logged in according to FILE.\n\
109If FILE is not specified, use %s.  %s as FILE is common.\n\
110\n\
111"),
112              UTMP_FILE, WTMP_FILE);
113      fputs (HELP_OPTION_DESCRIPTION, stdout);
114      fputs (VERSION_OPTION_DESCRIPTION, stdout);
115      emit_ancillary_info ();
116    }
117  exit (status);
118}
119
120int
121main (int argc, char **argv)
122{
123  initialize_main (&argc, &argv);
124  set_program_name (argv[0]);
125  setlocale (LC_ALL, "");
126  bindtextdomain (PACKAGE, LOCALEDIR);
127  textdomain (PACKAGE);
128
129  atexit (close_stdout);
130
131  parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, Version,
132                      usage, AUTHORS, (char const *) NULL);
133  if (getopt_long (argc, argv, "", NULL, NULL) != -1)
134    usage (EXIT_FAILURE);
135
136  switch (argc - optind)
137    {
138    case 0:			/* users */
139      users (UTMP_FILE, READ_UTMP_CHECK_PIDS);
140      break;
141
142    case 1:			/* users <utmp file> */
143      users (argv[optind], 0);
144      break;
145
146    default:			/* lose */
147      error (0, 0, _("extra operand %s"), quote (argv[optind + 1]));
148      usage (EXIT_FAILURE);
149    }
150
151  exit (EXIT_SUCCESS);
152}
153