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