dd: clarify meaning of multiplication factors; put xM in order
[platform/upstream/coreutils.git] / src / uptime.c
1 /* GNU's uptime.
2    Copyright (C) 1992-2002, 2004-2008 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 #include "fprintftime.h"
40
41 /* The official name of this program (e.g., no `g' prefix).  */
42 #define PROGRAM_NAME "uptime"
43
44 #define AUTHORS \
45   proper_name ("Joseph Arceneaux"), \
46   proper_name ("David MacKenzie"), \
47   proper_name ("Kaveh Ghazi")
48
49 int getloadavg ();
50
51 static void
52 print_uptime (size_t n, const STRUCT_UTMP *this)
53 {
54   size_t entries = 0;
55   time_t boot_time = 0;
56   time_t time_now;
57   time_t uptime = 0;
58   long int updays;
59   int uphours;
60   int upmins;
61   struct tm *tmn;
62   double avg[3];
63   int loads;
64 #ifdef HAVE_PROC_UPTIME
65   FILE *fp;
66
67   fp = fopen ("/proc/uptime", "r");
68   if (fp != NULL)
69     {
70       char buf[BUFSIZ];
71       char *b = fgets (buf, BUFSIZ, fp);
72       if (b == buf)
73         {
74           char *end_ptr;
75           double upsecs = c_strtod (buf, &end_ptr);
76           if (buf != end_ptr)
77             uptime = (0 <= upsecs && upsecs < TYPE_MAXIMUM (time_t)
78                       ? upsecs : -1);
79         }
80
81       fclose (fp);
82     }
83 #endif /* HAVE_PROC_UPTIME */
84
85 #if HAVE_SYSCTL && defined CTL_KERN && defined KERN_BOOTTIME
86   {
87     /* FreeBSD specific: fetch sysctl "kern.boottime".  */
88     static int request[2] = { CTL_KERN, KERN_BOOTTIME };
89     struct timeval result;
90     size_t result_len = sizeof result;
91
92     if (sysctl (request, 2, &result, &result_len, NULL, 0) >= 0)
93       boot_time = result.tv_sec;
94   }
95 #endif
96
97 #if HAVE_OS_H /* BeOS */
98   {
99     system_info si;
100
101     get_system_info (&si);
102     boot_time = si.boot_time / 1000000;
103   }
104 #endif
105
106 #if HAVE_UTMPX_H || HAVE_UTMP_H
107   /* Loop through all the utmp entries we just read and count up the valid
108      ones, also in the process possibly gleaning boottime. */
109   while (n--)
110     {
111       entries += IS_USER_PROCESS (this);
112       if (UT_TYPE_BOOT_TIME (this))
113         boot_time = UT_TIME_MEMBER (this);
114       ++this;
115     }
116 #endif
117   time_now = time (NULL);
118 #if defined HAVE_PROC_UPTIME
119   if (uptime == 0)
120 #endif
121     {
122       if (boot_time == 0)
123         error (EXIT_FAILURE, errno, _("couldn't get boot time"));
124       uptime = time_now - boot_time;
125     }
126   updays = uptime / 86400;
127   uphours = (uptime - (updays * 86400)) / 3600;
128   upmins = (uptime - (updays * 86400) - (uphours * 3600)) / 60;
129   tmn = localtime (&time_now);
130   /* procps' version of uptime also prints the seconds field, but
131      previous versions of coreutils don't. */
132   if (tmn)
133     fprintftime (stdout, _(" %H:%M%P  up "), tmn, 0, 0);
134   else
135     printf (_(" ??:????  up "));
136   if (uptime == (time_t) -1)
137     printf (_("???? days ??:??,  "));
138   else
139     {
140       if (0 < updays)
141         printf (ngettext ("%ld day", "%ld days", select_plural (updays)),
142                 updays);
143       printf (" %2d:%02d,  ", uphours, upmins);
144     }
145   printf (ngettext ("%lu user", "%lu users", entries),
146           (unsigned long int) entries);
147
148 #if defined HAVE_GETLOADAVG || defined C_GETLOADAVG
149   loads = getloadavg (avg, 3);
150 #else
151   loads = -1;
152 #endif
153
154   if (loads == -1)
155     putchar ('\n');
156   else
157     {
158       if (loads > 0)
159         printf (_(",  load average: %.2f"), avg[0]);
160       if (loads > 1)
161         printf (", %.2f", avg[1]);
162       if (loads > 2)
163         printf (", %.2f", avg[2]);
164       if (loads > 0)
165         putchar ('\n');
166     }
167 }
168
169 /* Display the system uptime and the number of users on the system,
170    according to utmp file FILENAME.  Use read_utmp OPTIONS to read the
171    utmp file.  */
172
173 static void
174 uptime (const char *filename, int options)
175 {
176   size_t n_users;
177   STRUCT_UTMP *utmp_buf;
178
179 #if HAVE_UTMPX_H || HAVE_UTMP_H
180   if (read_utmp (filename, &n_users, &utmp_buf, options) != 0)
181     error (EXIT_FAILURE, errno, "%s", filename);
182 #endif
183
184   print_uptime (n_users, utmp_buf);
185 }
186
187 void
188 usage (int status)
189 {
190   if (status != EXIT_SUCCESS)
191     fprintf (stderr, _("Try `%s --help' for more information.\n"),
192              program_name);
193   else
194     {
195       printf (_("Usage: %s [OPTION]... [FILE]\n"), program_name);
196       printf (_("\
197 Print the current time, the length of time the system has been up,\n\
198 the number of users on the system, and the average number of jobs\n\
199 in the run queue over the last 1, 5 and 15 minutes."));
200 #ifdef __linux__
201       /* It would be better to introduce a configure test for this,
202          but such a test is hard to write.  For the moment then, we
203          have a hack which depends on the preprocessor used at compile
204          time to tell us what the running kernel is.  Ugh.  */
205       printf(_("  \
206 Processes in\n\
207 an uninterruptible sleep state also contribute to the load average.\n"));
208 #else
209       printf(_("\n"));
210 #endif
211       printf (_("\
212 If FILE is not specified, use %s.  %s as FILE is common.\n\
213 \n"),
214               UTMP_FILE, WTMP_FILE);
215       fputs (HELP_OPTION_DESCRIPTION, stdout);
216       fputs (VERSION_OPTION_DESCRIPTION, stdout);
217       emit_bug_reporting_address ();
218     }
219   exit (status);
220 }
221
222 int
223 main (int argc, char **argv)
224 {
225   initialize_main (&argc, &argv);
226   set_program_name (argv[0]);
227   setlocale (LC_ALL, "");
228   bindtextdomain (PACKAGE, LOCALEDIR);
229   textdomain (PACKAGE);
230
231   atexit (close_stdout);
232
233   parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, VERSION,
234                       usage, AUTHORS, (char const *) NULL);
235   if (getopt_long (argc, argv, "", NULL, NULL) != -1)
236     usage (EXIT_FAILURE);
237
238   switch (argc - optind)
239     {
240     case 0:                     /* uptime */
241       uptime (UTMP_FILE, READ_UTMP_CHECK_PIDS);
242       break;
243
244     case 1:                     /* uptime <utmp file> */
245       uptime (argv[optind], 0);
246       break;
247
248     default:                    /* lose */
249       error (0, 0, _("extra operand %s"), quote (argv[optind + 1]));
250       usage (EXIT_FAILURE);
251     }
252
253   exit (EXIT_SUCCESS);
254 }