test: avoid false failure with setgid directories
[coreutils.git] / src / uptime.c
blob843b1019220e5486ead085462b21b5e2555017b1
1 /* GNU's uptime.
2 Copyright (C) 1992-2024 Free Software Foundation, Inc.
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.
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.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 /* Created by hacking who.c by Kaveh Ghazi ghazi@caip.rutgers.edu. */
19 #include <config.h>
21 #include <stdio.h>
22 #include <sys/types.h>
24 #include "system.h"
26 #include "long-options.h"
27 #include "quote.h"
28 #include "readutmp.h"
29 #include "fprintftime.h"
31 /* The official name of this program (e.g., no 'g' prefix). */
32 #define PROGRAM_NAME "uptime"
34 #define AUTHORS \
35 proper_name ("Joseph Arceneaux"), \
36 proper_name ("David MacKenzie"), \
37 proper_name ("Kaveh Ghazi")
39 static int
40 print_uptime (idx_t n, struct gl_utmp const *utmp_buf)
42 int status = EXIT_SUCCESS;
43 time_t boot_time = 0;
45 /* Loop through all the utmp entries we just read and count up the valid
46 ones, also in the process possibly gleaning boottime. */
47 idx_t entries = 0;
48 for (idx_t i = 0; i < n; i++)
50 struct gl_utmp const *this = &utmp_buf[i];
51 entries += IS_USER_PROCESS (this);
52 if (UT_TYPE_BOOT_TIME (this))
53 boot_time = this->ut_ts.tv_sec;
55 /* The gnulib module 'readutmp' is supposed to provide a BOOT_TIME entry
56 on all platforms. */
57 if (boot_time == 0)
59 error (0, errno, _("couldn't get boot time"));
60 status = EXIT_FAILURE;
63 time_t time_now = time (nullptr);
64 struct tm *tmn = time_now == (time_t) -1 ? nullptr : localtime (&time_now);
65 /* procps' version of uptime also prints the seconds field, but
66 previous versions of coreutils don't. */
67 if (tmn)
68 /* TRANSLATORS: This prints the current clock time. */
69 fprintftime (stdout, _(" %H:%M:%S "), tmn, 0, 0);
70 else
72 printf (_(" ??:???? "));
73 status = EXIT_FAILURE;
76 intmax_t uptime;
77 if (time_now == (time_t) -1 || boot_time == 0
78 || ckd_sub (&uptime, time_now, boot_time) || uptime < 0)
80 printf (_("up ???? days ??:??, "));
81 status = EXIT_FAILURE;
83 else
85 intmax_t updays = uptime / 86400;
86 int uphours = uptime % 86400 / 3600;
87 int upmins = uptime % 86400 % 3600 / 60;
88 if (0 < updays)
89 printf (ngettext ("up %jd day %2d:%02d, ",
90 "up %jd days %2d:%02d, ",
91 select_plural (updays)),
92 updays, uphours, upmins);
93 else
94 printf (_("up %2d:%02d, "), uphours, upmins);
97 printf (ngettext ("%td user", "%td users", select_plural (entries)),
98 entries);
100 double avg[3];
101 int loads = getloadavg (avg, 3);
103 if (loads == -1)
104 putchar ('\n');
105 else
107 if (loads > 0)
108 printf (_(", load average: %.2f"), avg[0]);
109 if (loads > 1)
110 printf (", %.2f", avg[1]);
111 if (loads > 2)
112 printf (", %.2f", avg[2]);
113 if (loads > 0)
114 putchar ('\n');
117 return status;
120 /* Display the system uptime and the number of users on the system,
121 according to utmp file FILENAME. Use read_utmp OPTIONS to read the
122 utmp file. */
124 static _Noreturn void
125 uptime (char const *filename, int options)
127 idx_t n_users;
128 struct gl_utmp *utmp_buf;
129 int read_utmp_status = (read_utmp (filename, &n_users, &utmp_buf, options) < 0
130 ? EXIT_FAILURE : EXIT_SUCCESS);
131 if (read_utmp_status != EXIT_SUCCESS)
133 error (0, errno, "%s", quotef (filename));
134 n_users = 0;
135 utmp_buf = nullptr;
138 int print_uptime_status = print_uptime (n_users, utmp_buf);
139 exit (MAX (read_utmp_status, print_uptime_status));
142 void
143 usage (int status)
145 if (status != EXIT_SUCCESS)
146 emit_try_help ();
147 else
149 printf (_("Usage: %s [OPTION]... [FILE]\n"), program_name);
150 printf (_("\
151 Print the current time, the length of time the system has been up,\n\
152 the number of users on the system, and the average number of jobs\n\
153 in the run queue over the last 1, 5 and 15 minutes."));
154 #ifdef __linux__
155 /* It would be better to introduce a configure test for this,
156 but such a test is hard to write. For the moment then, we
157 have a hack which depends on the preprocessor used at compile
158 time to tell us what the running kernel is. Ugh. */
159 printf (_(" \
160 Processes in\n\
161 an uninterruptible sleep state also contribute to the load average.\n"));
162 #else
163 printf (_("\n"));
164 #endif
165 printf (_("\
166 If FILE is not specified, use %s. %s as FILE is common.\n\
167 \n"),
168 UTMP_FILE, WTMP_FILE);
169 fputs (HELP_OPTION_DESCRIPTION, stdout);
170 fputs (VERSION_OPTION_DESCRIPTION, stdout);
171 emit_ancillary_info (PROGRAM_NAME);
173 exit (status);
177 main (int argc, char **argv)
179 initialize_main (&argc, &argv);
180 set_program_name (argv[0]);
181 setlocale (LC_ALL, "");
182 bindtextdomain (PACKAGE, LOCALEDIR);
183 textdomain (PACKAGE);
185 atexit (close_stdout);
187 parse_gnu_standard_options_only (argc, argv, PROGRAM_NAME, PACKAGE_NAME,
188 Version, true, usage, AUTHORS,
189 (char const *) nullptr);
191 switch (argc - optind)
193 case 0: /* uptime */
194 uptime (UTMP_FILE, READ_UTMP_CHECK_PIDS);
195 break;
197 case 1: /* uptime <utmp file> */
198 uptime (argv[optind], 0);
199 break;
201 default: /* lose */
202 error (0, 0, _("extra operand %s"), quote (argv[optind + 1]));
203 usage (EXIT_FAILURE);