Line data Source code
1 : /* GNU's uptime.
2 : Copyright (C) 1992-2002, 2004-2007 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 : /* Created by hacking who.c by Kaveh Ghazi ghazi@caip.rutgers.edu. */
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 : #if HAVE_SYSCTL && HAVE_SYS_SYSCTL_H
27 : # include <sys/sysctl.h>
28 : #endif
29 :
30 : #if HAVE_OS_H
31 : # include <OS.h>
32 : #endif
33 :
34 : #include "c-strtod.h"
35 : #include "error.h"
36 : #include "long-options.h"
37 : #include "quote.h"
38 : #include "readutmp.h"
39 :
40 : /* The official name of this program (e.g., no `g' prefix). */
41 : #define PROGRAM_NAME "uptime"
42 :
43 : #define AUTHORS "Joseph Arceneaux", "David MacKenzie", "Kaveh Ghazi"
44 :
45 : int getloadavg ();
46 :
47 : /* The name this program was run with. */
48 : char *program_name;
49 :
50 : static void
51 10 : print_uptime (size_t n, const STRUCT_UTMP *this)
52 : {
53 10 : size_t entries = 0;
54 10 : time_t boot_time = 0;
55 : time_t time_now;
56 10 : time_t uptime = 0;
57 : long int updays;
58 : int uphours;
59 : int upmins;
60 : struct tm *tmn;
61 : double avg[3];
62 : int loads;
63 : #ifdef HAVE_PROC_UPTIME
64 : FILE *fp;
65 :
66 10 : fp = fopen ("/proc/uptime", "r");
67 10 : if (fp != NULL)
68 : {
69 : char buf[BUFSIZ];
70 10 : char *b = fgets (buf, BUFSIZ, fp);
71 10 : if (b == buf)
72 : {
73 : char *end_ptr;
74 10 : double upsecs = c_strtod (buf, &end_ptr);
75 10 : if (buf != end_ptr)
76 10 : uptime = (0 <= upsecs && upsecs < TYPE_MAXIMUM (time_t)
77 : ? upsecs : -1);
78 : }
79 :
80 10 : fclose (fp);
81 : }
82 : #endif /* HAVE_PROC_UPTIME */
83 :
84 : #if HAVE_SYSCTL && defined CTL_KERN && defined KERN_BOOTTIME
85 : {
86 : /* FreeBSD specific: fetch sysctl "kern.boottime". */
87 : static int request[2] = { CTL_KERN, KERN_BOOTTIME };
88 : struct timeval result;
89 : size_t result_len = sizeof result;
90 :
91 : if (sysctl (request, 2, &result, &result_len, NULL, 0) >= 0)
92 : boot_time = result.tv_sec;
93 : }
94 : #endif
95 :
96 : #if HAVE_OS_H /* BeOS */
97 : {
98 : system_info si;
99 :
100 : get_system_info (&si);
101 : boot_time = si.boot_time / 1000000;
102 : }
103 : #endif
104 :
105 : #if HAVE_UTMPX_H || HAVE_UTMP_H
106 : /* Loop through all the utmp entries we just read and count up the valid
107 : ones, also in the process possibly gleaning boottime. */
108 20 : while (n--)
109 : {
110 0 : entries += IS_USER_PROCESS (this);
111 0 : if (UT_TYPE_BOOT_TIME (this))
112 0 : boot_time = UT_TIME_MEMBER (this);
113 0 : ++this;
114 : }
115 : #endif
116 10 : time_now = time (NULL);
117 : #if defined HAVE_PROC_UPTIME
118 10 : if (uptime == 0)
119 : #endif
120 : {
121 0 : if (boot_time == 0)
122 0 : error (EXIT_FAILURE, errno, _("couldn't get boot time"));
123 0 : uptime = time_now - boot_time;
124 : }
125 10 : updays = uptime / 86400;
126 10 : uphours = (uptime - (updays * 86400)) / 3600;
127 10 : upmins = (uptime - (updays * 86400) - (uphours * 3600)) / 60;
128 10 : tmn = localtime (&time_now);
129 10 : if (tmn)
130 30 : printf (_(" %2d:%02d%s up "),
131 20 : ((tmn->tm_hour % 12) == 0 ? 12 : tmn->tm_hour % 12),
132 : /* FIXME: use strftime, not am, pm. Uli reports that
133 : the german translation is meaningless. */
134 10 : tmn->tm_min, (tmn->tm_hour < 12 ? _("am") : _("pm")));
135 : else
136 0 : printf (_(" ??:???? up "));
137 10 : if (uptime == (time_t) -1)
138 0 : printf (_("???? days ??:??, "));
139 : else
140 : {
141 10 : if (0 < updays)
142 10 : printf (ngettext ("%ld day", "%ld days", select_plural (updays)),
143 : updays);
144 10 : printf (" %2d:%02d, ", uphours, upmins);
145 : }
146 10 : printf (ngettext ("%lu user", "%lu users", entries),
147 : (unsigned long int) entries);
148 :
149 : #if defined HAVE_GETLOADAVG || defined C_GETLOADAVG
150 10 : loads = getloadavg (avg, 3);
151 : #else
152 : loads = -1;
153 : #endif
154 :
155 10 : if (loads == -1)
156 0 : putchar ('\n');
157 : else
158 : {
159 10 : if (loads > 0)
160 10 : printf (_(", load average: %.2f"), avg[0]);
161 10 : if (loads > 1)
162 10 : printf (", %.2f", avg[1]);
163 10 : if (loads > 2)
164 10 : printf (", %.2f", avg[2]);
165 10 : if (loads > 0)
166 10 : putchar ('\n');
167 : }
168 10 : }
169 :
170 : /* Display the system uptime and the number of users on the system,
171 : according to utmp file FILENAME. Use read_utmp OPTIONS to read the
172 : utmp file. */
173 :
174 : static void
175 10 : uptime (const char *filename, int options)
176 : {
177 : size_t n_users;
178 : STRUCT_UTMP *utmp_buf;
179 :
180 : #if HAVE_UTMPX_H || HAVE_UTMP_H
181 10 : if (read_utmp (filename, &n_users, &utmp_buf, options) != 0)
182 0 : error (EXIT_FAILURE, errno, "%s", filename);
183 : #endif
184 :
185 10 : print_uptime (n_users, utmp_buf);
186 10 : }
187 :
188 : void
189 26 : usage (int status)
190 : {
191 26 : if (status != EXIT_SUCCESS)
192 24 : fprintf (stderr, _("Try `%s --help' for more information.\n"),
193 : program_name);
194 : else
195 : {
196 2 : printf (_("Usage: %s [OPTION]... [ FILE ]\n"), program_name);
197 2 : printf (_("\
198 : Print the current time, the length of time the system has been up,\n\
199 : the number of users on the system, and the average number of jobs\n\
200 : in the run queue over the last 1, 5 and 15 minutes.\n\
201 : If FILE is not specified, use %s. %s as FILE is common.\n\
202 : \n\
203 : "),
204 : UTMP_FILE, WTMP_FILE);
205 2 : fputs (HELP_OPTION_DESCRIPTION, stdout);
206 2 : fputs (VERSION_OPTION_DESCRIPTION, stdout);
207 2 : emit_bug_reporting_address ();
208 : }
209 26 : exit (status);
210 : }
211 :
212 : int
213 37 : main (int argc, char **argv)
214 : {
215 : initialize_main (&argc, &argv);
216 37 : program_name = argv[0];
217 37 : setlocale (LC_ALL, "");
218 : bindtextdomain (PACKAGE, LOCALEDIR);
219 : textdomain (PACKAGE);
220 :
221 37 : atexit (close_stdout);
222 :
223 37 : parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, VERSION,
224 : usage, AUTHORS, (char const *) NULL);
225 34 : if (getopt_long (argc, argv, "", NULL, NULL) != -1)
226 5 : usage (EXIT_FAILURE);
227 :
228 29 : switch (argc - optind)
229 : {
230 2 : case 0: /* uptime */
231 2 : uptime (UTMP_FILE, READ_UTMP_CHECK_PIDS);
232 2 : break;
233 :
234 8 : case 1: /* uptime <utmp file> */
235 8 : uptime (argv[optind], 0);
236 8 : break;
237 :
238 19 : default: /* lose */
239 19 : error (0, 0, _("extra operand %s"), quote (argv[optind + 1]));
240 19 : usage (EXIT_FAILURE);
241 : }
242 :
243 10 : exit (EXIT_SUCCESS);
244 : }
|