summaryrefslogtreecommitdiffstats
path: root/SysArchMeter.c
blob: b371acc7c0405a29f2fb74c5b388e9bf28d5e20f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/*
htop - SysArchMeter.c
(C) 2021 htop dev team
Released under the GNU GPLv2, see the COPYING file
in the source distribution for its full text.
*/
#include "config.h"  // IWYU pragma: keep

#include "SysArchMeter.h"

#include <stdio.h>
#include <sys/utsname.h>

#include "XUtils.h"


static const int SysArchMeter_attributes[] = {HOSTNAME};

static void parseOSRelease(char* buffer, size_t bufferLen) {
   FILE* stream = fopen("/etc/os-release", "r");
   if (!stream) {
      stream = fopen("/usr/lib/os-release", "r");
      if (!stream) {
         xSnprintf(buffer, bufferLen, "Unknown Distro");
         return;
      }
   }

   char name[64] = {'\0'};
   char version[64] = {'\0'};
   char lineBuffer[256];
   while (fgets(lineBuffer, sizeof(lineBuffer), stream)) {
      if (String_startsWith(lineBuffer, "PRETTY_NAME=\"")) {
         const char* start = lineBuffer + strlen("PRETTY_NAME=\"");
         const char* stop = strrchr(lineBuffer, '"');
         if (!stop || stop <= start)
            continue;
         String_safeStrncpy(buffer, start, MINIMUM(bufferLen, (size_t)(stop - start + 1)));
         fclose(stream);
         return;
      }
      if (String_startsWith(lineBuffer, "NAME=\"")) {
         const char* start = lineBuffer + strlen("NAME=\"");
         const char* stop = strrchr(lineBuffer, '"');
         if (!stop || stop <= start)
            continue;
         String_safeStrncpy(name, start, MINIMUM(sizeof(name), (size_t)(stop - start + 1)));
         continue;
      }
      if (String_startsWith(lineBuffer, "VERSION=\"")) {
         const char* start = lineBuffer + strlen("VERSION=\"");
         const char* stop = strrchr(lineBuffer, '"');
         if (!stop || stop <= start)
            continue;
         String_safeStrncpy(version, start, MINIMUM(sizeof(version), (size_t)(stop - start + 1)));
         continue;
      }
   }
   fclose(stream);

   snprintf(buffer, bufferLen, "%s%s%s", name[0] ? name : "", name[0] && version[0] ? " " : "", version);
}

static void SysArchMeter_updateValues(ATTR_UNUSED Meter* this, char* buffer, size_t size) {
   static struct utsname uname_info;

   static char savedString[
      /* uname structure fields - manpages recommend sizeof */
      sizeof(uname_info.sysname) +
      sizeof(uname_info.release) +
      sizeof(uname_info.machine) +
      16/*markup*/ +
      128/*distro*/] = {'\0'};
   static bool loaded_data = false;

   if (!loaded_data) {
      int uname_result = uname(&uname_info);

      char distro[128];
      parseOSRelease(distro, sizeof(distro));

      if (uname_result == 0) {
         size_t written = xSnprintf(savedString, sizeof(savedString), "%s %s [%s]", uname_info.sysname, uname_info.release, uname_info.machine);
         if (!String_contains_i(savedString, distro) && sizeof(savedString) > written)
            snprintf(savedString + written, sizeof(savedString) - written, " @ %s", distro);
      } else {
         snprintf(savedString, sizeof(savedString), "%s", distro);
      }

      loaded_data = true;
   }

   String_safeStrncpy(buffer, savedString, size);
}

const MeterClass SysArchMeter_class = {
   .super = {
      .extends = Class(Meter),
      .delete = Meter_delete
   },
   .updateValues = SysArchMeter_updateValues,
   .defaultMode = TEXT_METERMODE,
   .maxItems = 0,
   .total = 100.0,
   .attributes = SysArchMeter_attributes,
   .name = "System",
   .uiName = "System",
   .caption = "System: ",
};

© 2014-2024 Faster IT GmbH | imprint | privacy policy