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