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