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