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