procfetch  0.3.0
A command-line system information utility written in C++
fetch.h
Go to the documentation of this file.
1 
4 #pragma once
5 
6 #include "color.h"
7 #include "config.h"
8 #include <algorithm>
9 #include <cctype>
10 #include <cerrno>
11 #include <cstring>
12 #include <filesystem>
13 #include <fstream>
14 #include <functional>
15 #include <iostream>
16 #include <map>
17 #include <mutex>
18 #include <ostream>
19 #include <sstream>
20 #include <stdexcept>
21 #include <string.h>
22 #include <string>
23 #include <sys/errno.h>
24 #include <sys/wait.h>
25 #include <thread>
26 #include <unistd.h>
27 #include <vector>
28 
29 using namespace std;
30 
31 // fetch.cpp
32 
33 string getuser();
34 
35 string gethostname(string path);
36 
37 string getOS(string path);
38 
39 string getHardwarePlatform();
40 
41 string getHost(string path);
42 
43 string getKernel(string path);
44 
45 string getUpTime(string path);
46 
47 string getRAM(string path);
48 
49 string getSHELL(string path);
50 
51 string getDE();
52 
53 bool resCheck();
54 
55 string getRES(string path);
56 
57 string getTheme();
58 
59 string getIcons();
60 
61 string getCPU(string path);
62 
63 bool CpuTempCheck();
64 
65 int getCPUtemp(string path);
66 
67 vector<string> getGPU();
68 
69 string getPackages();
70 
71 void printBattery(string path);
72 
73 void print(string color, string distro_name);
74 
75 string getColor(string);
76 
80 class Path
81 {
82  private:
83  filesystem::path path;
84  filesystem::file_status status;
85 
86  Path(filesystem::path path, filesystem::file_status status)
87  {
88  this->path = path;
89  this->status = status;
90  }
91 
92  public:
97  static Path of(const string &path)
98  {
99  return Path(filesystem::path(path), filesystem::status(path));
100  }
101 
106  {
107  filesystem::path p = this->path.filename();
108  return Path(p, filesystem::status(p));
109  }
110 
115  {
116  return filesystem::is_regular_file(status);
117  }
118 
123  {
124  if (status.permissions() == filesystem::perms::unknown)
125  return false;
126  return (status.permissions() & filesystem::perms::others_exec) !=
127  filesystem::perms::none;
128  }
129 
133  bool isDirectory()
134  {
135  return filesystem::is_directory(status);
136  }
137 
141  string toString() const
142  {
143  return path.string();
144  }
145 
149  vector<Path> getDirectoryContents()
150  {
151  vector<Path> contents;
152  if (!this->isDirectory())
153  {
154  return contents;
155  }
156 
157  for (const auto &entry : filesystem::directory_iterator(path))
158  {
159  contents.push_back(Path::of(entry.path()));
160  }
161  return contents;
162  }
163 };
164 
176 class Command
177 {
178  public:
179  typedef std::function<void(Command)> func_type;
180 
181  private:
182  int exit_code;
183  string output;
184  string error_output;
185  int lines;
186  static std::vector<std::thread> ths;
187  static std::vector<std::runtime_error> exceptions;
188  static std::mutex mtx;
189 
190  Command()
191  {
192  output = string();
193  lines = 0;
194  }
195 
196  static void split(vector<char *> &v, string cmd)
197  {
198  istringstream ss{cmd};
199  for (string arg{}; getline(ss, arg, ' '); ) {
200  if (arg == "")
201  continue;
202 
203  auto s = strdup(arg.c_str());
204  if (s == NULL)
205  throw runtime_error("strdup failed");
206  v.push_back(s);
207  }
208  v.push_back((char *)0);
209  }
210 
211  public:
215  static void wait()
216  {
217  for (auto &t : ths)
218  {
219  if (t.joinable())
220  {
221  t.join();
222  }
223  }
224  }
225 
229  static vector<runtime_error> &getExceptions()
230  {
231  return exceptions;
232  }
233 
239  static void exec_async(const string &cmd, const func_type &func)
240  {
241  ths.push_back(std::thread([=]() {
242  try
243  {
244  auto result = exec(cmd);
245  func(result);
246  }
247  catch (const runtime_error &e)
248  {
249  std::lock_guard<std::mutex> lock(mtx);
250  exceptions.push_back(e);
251  }
252  }));
253  }
254 
261  static void exec_async(const Path &cmd, const string &arg,
262  const func_type &func)
263  {
264  exec_async(cmd.toString() + " " + arg, func);
265  }
266 
273  static Command exec(const string &cmd)
274  {
275  auto result = Command{};
276  int out_fd[2], err_fd[2];
277  pid_t pid;
278 
279  if (pipe(out_fd) == -1)
280  {
281  throw runtime_error("pipe failed");
282  }
283  if (pipe(err_fd) == -1)
284  {
285  throw runtime_error("pipe failed");
286  }
287 
288  if ((pid = fork()) < 0)
289  {
290  throw runtime_error("fork faliled");
291  }
292  else if (pid == 0)
293  { // child
294  if (close(out_fd[0]) == -1)
295  {
296  throw runtime_error("close failed");
297  }
298  if (close(err_fd[0]) == -1)
299  {
300  throw runtime_error("close failed");
301  }
302  if (dup2(out_fd[1], fileno(stdout)) == -1)
303  {
304  throw runtime_error("dup2 failed");
305  }
306  if (dup2(err_fd[1], fileno(stderr)) == -1)
307  {
308  throw runtime_error("dup2 failed");
309  }
310 
311  vector<char *>v{};
312  split(v, cmd);
313  auto argv = v.data();
314  execvp(argv[0], argv);
315 
316  // If execvp() returns, an error have occured.
317  // As the process terminates immediately, it does not free the dynamically allocated memory tied to the argv.
318  switch (errno)
319  {
320  case ENOENT:
321  exit(127);
322  case EACCES:
323  exit(126);
324  default:
325  throw runtime_error("execvp failed: " +
326  string(strerror(errno)) + ": " + argv[0]);
327  }
328  }
329 
330  // parent
331  if (close(out_fd[1]) == -1)
332  {
333  throw runtime_error("close failed");
334  }
335  if (close(err_fd[1]) == -1)
336  {
337  throw runtime_error("close failed");
338  }
339  FILE *out = fdopen(out_fd[0], "r");
340  if (out == NULL)
341  {
342  throw runtime_error("fdopen failed");
343  }
344  FILE *err = fdopen(err_fd[0], "r");
345  if (err == NULL)
346  {
347  throw runtime_error("fdopen failed");
348  }
349 
350  int c;
351  while ((c = fgetc(out)) != EOF)
352  {
353  if (c == '\n')
354  {
355  result.lines += 1;
356  }
357  result.output += c;
358  }
359 
360  while ((c = fgetc(err)) != EOF)
361  {
362  result.error_output += c;
363  }
364 
365  if (fclose(out) == EOF)
366  {
367  throw runtime_error("fclose failed: " + string(strerror(errno)));
368  }
369 
370  if (fclose(err) == EOF)
371  {
372  throw runtime_error("fclose failed: " + string(strerror(errno)));
373  }
374 
375  int status;
376  waitpid(pid, &status, 0);
377  if (WIFEXITED(status))
378  {
379  result.exit_code = WEXITSTATUS(status);
380  }
381  else if (WIFSIGNALED(status))
382  {
383  int sig = WTERMSIG(status);
384  throw runtime_error("abnormal termination, signal number = " +
385  to_string(sig));
386  }
387  else if (WIFSTOPPED(status))
388  {
389  int sig = WSTOPSIG(status);
390  throw runtime_error("child stopped, signal number = " +
391  to_string(sig));
392  }
393  else
394  {
395  throw runtime_error("must not be here");
396  }
397 
398  return result;
399  }
400 
404  string getOutput()
405  {
406  return output;
407  }
408 
412  string getErrorOutput()
413  {
414  return error_output;
415  }
416 
421  {
422  return lines;
423  }
424 
429  {
430  return exit_code;
431  }
432 };
433 
437 class Crayon
438 {
439  private:
440  string escape_codes;
441  inline static map<string, string> m = {
442  {"RED", RED}, {"GREEN", GREEN}, {"BLACK", BLACK},
443  {"YELLOW", YELLOW}, {"BLUE", BLUE}, {"MAGENTA", MAGENTA},
444  {"CYAN", CYAN}, {"WHITE", WHITE}, {"BBLACK", BBLACK},
445  {"BGRAY", BGRAY}, {"BRED", BRED}, {"BGREEN", BGREEN},
446  {"BYELLOW", BYELLOW}, {"BBLUE", BBLUE}, {"BMAGENTA", BMAGENTA},
447  {"BCYAN", BCYAN}, {"BWHITE", BWHITE},
448  };
449 
450  static string getColor(string s)
451  {
452  return m[s];
453  }
454 
455  public:
460  {
461  escape_codes = ""s;
462  }
467  {
468  escape_codes += BRIGHT;
469  return *this;
470  }
475  {
476  escape_codes += UNDERSCORE;
477  return *this;
478  }
483  Crayon color(string color)
484  {
485  escape_codes += getColor(color);
486  return *this;
487  }
490  {
491  escape_codes += RED;
492  return *this;
493  }
496  {
497  escape_codes += GREEN;
498  return *this;
499  }
502  {
503  escape_codes += YELLOW;
504  return *this;
505  }
510  string text(string s)
511  {
512  return escape_codes + s + RESET;
513  }
514 };
515 
516 class Context
517 {
518  public:
519  static string PACKAGE_DELIM;
520 };
521 
522 enum class Mode
523 {
524  NORMAL,
525  SHOW_VERSION,
526 };
527 
528 class Options
529 {
530  public:
531  Mode mode = Mode::NORMAL;
532  string color_name = "def"s;
533  string distro_name = "def"s;
534  bool show_battery = false;
535 
536  Options(){};
537  Options(int argc, char *argv[])
538  {
539  int opt;
540  while ((opt = getopt(argc, argv, "a:d:vb")) != -1)
541  {
542 
543  switch (opt)
544  {
545  case 'a':
546  color_name = string(optarg);
547  break;
548  case 'd':
549  distro_name = string(optarg);
550  break;
551  case 'b':
552  show_battery = true;
553  break;
554  case 'v':
555  mode = Mode::SHOW_VERSION;
556  break;
557  default:
558  exit(1);
559  }
560  }
561  }
562 };
Definition: fetch.h:177
static void exec_async(const string &cmd, const func_type &func)
Definition: fetch.h:239
int getOutputLines()
Definition: fetch.h:420
int getExitCode()
Definition: fetch.h:428
string getOutput()
Definition: fetch.h:404
static void exec_async(const Path &cmd, const string &arg, const func_type &func)
Definition: fetch.h:261
static Command exec(const string &cmd)
Definition: fetch.h:273
static void wait()
Definition: fetch.h:215
string getErrorOutput()
Definition: fetch.h:412
static vector< runtime_error > & getExceptions()
Definition: fetch.h:229
Definition: fetch.h:517
Definition: fetch.h:438
Crayon yellow()
Definition: fetch.h:501
string text(string s)
Definition: fetch.h:510
Crayon bright()
Definition: fetch.h:466
Crayon red()
Definition: fetch.h:489
Crayon green()
Definition: fetch.h:495
Crayon color(string color)
Definition: fetch.h:483
Crayon underscore()
Definition: fetch.h:474
Crayon()
Definition: fetch.h:459
Definition: fetch.h:529
Definition: fetch.h:81
static Path of(const string &path)
Definition: fetch.h:97
vector< Path > getDirectoryContents()
Definition: fetch.h:149
bool isDirectory()
Definition: fetch.h:133
Path getFilename()
Definition: fetch.h:105
string toString() const
Definition: fetch.h:141
bool isExecutable()
Definition: fetch.h:122
bool isRegularFile()
Definition: fetch.h:114
string gethostname(string path)
Definition: fetch.cpp:33
vector< string > getGPU()
Definition: fetch.cpp:348
void printBattery(string path)
Definition: fetch.cpp:532
string getHardwarePlatform()
Definition: fetch.cpp:77
bool resCheck()
Definition: fetch.cpp:257
string getDE()
Definition: fetch.cpp:239
string getRES(string path)
Definition: fetch.cpp:266
string getOS(string path)
Definition: fetch.cpp:46
string getuser()
Definition: fetch.cpp:18
void print(string color, string distro_name)
Definition: fetch.cpp:599
string getPackages()
Definition: fetch.cpp:372
string getUpTime(string path)
Definition: fetch.cpp:127
string getCPU(string path)
Definition: fetch.cpp:304
string getRAM(string path)
Definition: fetch.cpp:162
string getTheme()
Definition: fetch.cpp:279
bool CpuTempCheck()
Definition: fetch.cpp:327
string getKernel(string path)
Definition: fetch.cpp:114
string getHost(string path)
Definition: fetch.cpp:90
int getCPUtemp(string path)
Definition: fetch.cpp:336
string getIcons()
Definition: fetch.cpp:291
string getSHELL(string path)
Definition: fetch.cpp:216