aboutsummaryrefslogtreecommitdiffstats
path: root/CommandLine.c
diff options
context:
space:
mode:
Diffstat (limited to 'CommandLine.c')
-rw-r--r--CommandLine.c400
1 files changed, 400 insertions, 0 deletions
diff --git a/CommandLine.c b/CommandLine.c
new file mode 100644
index 0000000..f0d2255
--- /dev/null
+++ b/CommandLine.c
@@ -0,0 +1,400 @@
+/*
+htop - CommandLine.c
+(C) 2004-2011 Hisham H. Muhammad
+(C) 2020-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 "CommandLine.h"
+
+#include <assert.h>
+#include <getopt.h>
+#include <locale.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "Action.h"
+#include "CRT.h"
+#include "DynamicColumn.h"
+#include "DynamicMeter.h"
+#include "Hashtable.h"
+#include "Header.h"
+#include "IncSet.h"
+#include "MainPanel.h"
+#include "MetersPanel.h"
+#include "Panel.h"
+#include "Platform.h"
+#include "Process.h"
+#include "ProcessList.h"
+#include "ProvideCurses.h"
+#include "ScreenManager.h"
+#include "Settings.h"
+#include "UsersTable.h"
+#include "XUtils.h"
+
+
+static void printVersionFlag(const char* name) {
+ printf("%s " VERSION "\n", name);
+}
+
+static void printHelpFlag(const char* name) {
+ printf("%s " VERSION "\n"
+ COPYRIGHT "\n"
+ "Released under the GNU GPLv2.\n\n"
+ "-C --no-color Use a monochrome color scheme\n"
+ "-d --delay=DELAY Set the delay between updates, in tenths of seconds\n"
+ "-F --filter=FILTER Show only the commands matching the given filter\n"
+ "-h --help Print this help screen\n"
+ "-H --highlight-changes[=DELAY] Highlight new and old processes\n"
+ "-M --no-mouse Disable the mouse\n"
+ "-p --pid=PID[,PID,PID...] Show only the given PIDs\n"
+ " --readonly Disable all system and process changing features\n"
+ "-s --sort-key=COLUMN Sort by COLUMN in list view (try --sort-key=help for a list)\n"
+ "-t --tree Show the tree view (can be combined with -s)\n"
+ "-u --user[=USERNAME] Show only processes for a given user (or $USER)\n"
+ "-U --no-unicode Do not use unicode but plain ASCII\n"
+ "-V --version Print version info\n", name);
+ Platform_longOptionsUsage(name);
+ printf("\n"
+ "Long options may be passed with a single dash.\n\n"
+ "Press F1 inside %s for online help.\n"
+ "See 'man %s' for more information.\n", name, name);
+}
+
+// ----------------------------------------
+
+typedef struct CommandLineSettings_ {
+ Hashtable* pidMatchList;
+ char* commFilter;
+ uid_t userId;
+ int sortKey;
+ int delay;
+ bool useColors;
+ bool enableMouse;
+ bool treeView;
+ bool allowUnicode;
+ bool highlightChanges;
+ int highlightDelaySecs;
+ bool readonly;
+} CommandLineSettings;
+
+static CommandLineSettings parseArguments(const char* program, int argc, char** argv) {
+
+ CommandLineSettings flags = {
+ .pidMatchList = NULL,
+ .commFilter = NULL,
+ .userId = (uid_t)-1, // -1 is guaranteed to be an invalid uid_t (see setreuid(2))
+ .sortKey = 0,
+ .delay = -1,
+ .useColors = true,
+ .enableMouse = true,
+ .treeView = false,
+ .allowUnicode = true,
+ .highlightChanges = false,
+ .highlightDelaySecs = -1,
+ .readonly = false,
+ };
+
+ const struct option long_opts[] =
+ {
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'V'},
+ {"delay", required_argument, 0, 'd'},
+ {"sort-key", required_argument, 0, 's'},
+ {"user", optional_argument, 0, 'u'},
+ {"no-color", no_argument, 0, 'C'},
+ {"no-colour", no_argument, 0, 'C'},
+ {"no-mouse", no_argument, 0, 'M'},
+ {"no-unicode", no_argument, 0, 'U'},
+ {"tree", no_argument, 0, 't'},
+ {"pid", required_argument, 0, 'p'},
+ {"filter", required_argument, 0, 'F'},
+ {"highlight-changes", optional_argument, 0, 'H'},
+ {"readonly", no_argument, 0, 128},
+ PLATFORM_LONG_OPTIONS
+ {0, 0, 0, 0}
+ };
+
+ int opt, opti = 0;
+ /* Parse arguments */
+ while ((opt = getopt_long(argc, argv, "hVMCs:td:u::Up:F:H::", long_opts, &opti))) {
+ if (opt == EOF)
+ break;
+ switch (opt) {
+ case 'h':
+ printHelpFlag(program);
+ exit(0);
+ case 'V':
+ printVersionFlag(program);
+ exit(0);
+ case 's':
+ assert(optarg); /* please clang analyzer, cause optarg can be NULL in the 'u' case */
+ if (String_eq(optarg, "help")) {
+ for (int j = 1; j < LAST_PROCESSFIELD; j++) {
+ const char* name = Process_fields[j].name;
+ const char* description = Process_fields[j].description;
+ if (name) printf("%19s %s\n", name, description);
+ }
+ exit(0);
+ }
+ flags.sortKey = 0;
+ for (int j = 1; j < LAST_PROCESSFIELD; j++) {
+ if (Process_fields[j].name == NULL)
+ continue;
+ if (String_eq(optarg, Process_fields[j].name)) {
+ flags.sortKey = j;
+ break;
+ }
+ }
+ if (flags.sortKey == 0) {
+ fprintf(stderr, "Error: invalid column \"%s\".\n", optarg);
+ exit(1);
+ }
+ break;
+ case 'd':
+ if (sscanf(optarg, "%16d", &(flags.delay)) == 1) {
+ if (flags.delay < 1) flags.delay = 1;
+ if (flags.delay > 100) flags.delay = 100;
+ } else {
+ fprintf(stderr, "Error: invalid delay value \"%s\".\n", optarg);
+ exit(1);
+ }
+ break;
+ case 'u':
+ {
+ const char *username = optarg;
+ if (!username && optind < argc && argv[optind] != NULL &&
+ (argv[optind][0] != '\0' && argv[optind][0] != '-')) {
+ username = argv[optind++];
+ }
+
+ if (!username) {
+ flags.userId = geteuid();
+ } else if (!Action_setUserOnly(username, &(flags.userId))) {
+ fprintf(stderr, "Error: invalid user \"%s\".\n", username);
+ exit(1);
+ }
+ break;
+ }
+ case 'C':
+ flags.useColors = false;
+ break;
+ case 'M':
+#ifdef HAVE_GETMOUSE
+ flags.enableMouse = false;
+#endif
+ break;
+ case 'U':
+ flags.allowUnicode = false;
+ break;
+ case 't':
+ flags.treeView = true;
+ break;
+ case 'p': {
+ assert(optarg); /* please clang analyzer, cause optarg can be NULL in the 'u' case */
+ char* argCopy = xStrdup(optarg);
+ char* saveptr;
+ const char* pid = strtok_r(argCopy, ",", &saveptr);
+
+ if (!flags.pidMatchList) {
+ flags.pidMatchList = Hashtable_new(8, false);
+ }
+
+ while(pid) {
+ unsigned int num_pid = atoi(pid);
+ // deepcode ignore CastIntegerToAddress: we just want a non-NUll pointer here
+ Hashtable_put(flags.pidMatchList, num_pid, (void *) 1);
+ pid = strtok_r(NULL, ",", &saveptr);
+ }
+ free(argCopy);
+
+ break;
+ }
+ case 'F': {
+ assert(optarg);
+ free_and_xStrdup(&flags.commFilter, optarg);
+ break;
+ }
+ case 'H': {
+ const char *delay = optarg;
+ if (!delay && optind < argc && argv[optind] != NULL &&
+ (argv[optind][0] != '\0' && argv[optind][0] != '-')) {
+ delay = argv[optind++];
+ }
+ if (delay) {
+ if (sscanf(delay, "%16d", &(flags.highlightDelaySecs)) == 1) {
+ if (flags.highlightDelaySecs < 1)
+ flags.highlightDelaySecs = 1;
+ } else {
+ fprintf(stderr, "Error: invalid highlight delay value \"%s\".\n", delay);
+ exit(1);
+ }
+ }
+ flags.highlightChanges = true;
+ break;
+ }
+ case 128:
+ flags.readonly = true;
+ break;
+
+ default:
+ if (Platform_getLongOption(opt, argc, argv) == false)
+ exit(1);
+ break;
+ }
+ }
+ return flags;
+}
+
+static void CommandLine_delay(ProcessList* pl, unsigned long millisec) {
+ struct timespec req = {
+ .tv_sec = 0,
+ .tv_nsec = millisec * 1000000L
+ };
+ while (nanosleep(&req, &req) == -1)
+ continue;
+ Platform_gettime_realtime(&pl->realtime, &pl->realtimeMs);
+}
+
+static void setCommFilter(State* state, char** commFilter) {
+ ProcessList* pl = state->pl;
+ IncSet* inc = state->mainPanel->inc;
+
+ IncSet_setFilter(inc, *commFilter);
+ pl->incFilter = IncSet_filter(inc);
+
+ free(*commFilter);
+ *commFilter = NULL;
+}
+
+int CommandLine_run(const char* name, int argc, char** argv) {
+
+ /* initialize locale */
+ const char* lc_ctype;
+ if ((lc_ctype = getenv("LC_CTYPE")) || (lc_ctype = getenv("LC_ALL")))
+ setlocale(LC_CTYPE, lc_ctype);
+ else
+ setlocale(LC_CTYPE, "");
+
+ CommandLineSettings flags = parseArguments(name, argc, argv);
+
+ if (flags.readonly)
+ Settings_enableReadonly();
+
+ Platform_init();
+
+ Process_setupColumnWidths();
+
+ UsersTable* ut = UsersTable_new();
+ Hashtable* dc = DynamicColumns_new();
+ Hashtable* dm = DynamicMeters_new();
+ if (!dc)
+ dc = Hashtable_new(0, true);
+
+ ProcessList* pl = ProcessList_new(ut, dm, dc, flags.pidMatchList, flags.userId);
+
+ Settings* settings = Settings_new(pl->activeCPUs, dc);
+ pl->settings = settings;
+
+ Header* header = Header_new(pl, settings, 2);
+
+ Header_populateFromSettings(header);
+
+ if (flags.delay != -1)
+ settings->delay = flags.delay;
+ if (!flags.useColors)
+ settings->colorScheme = COLORSCHEME_MONOCHROME;
+#ifdef HAVE_GETMOUSE
+ if (!flags.enableMouse)
+ settings->enableMouse = false;
+#endif
+ if (flags.treeView)
+ settings->treeView = true;
+ if (flags.highlightChanges)
+ settings->highlightChanges = true;
+ if (flags.highlightDelaySecs != -1)
+ settings->highlightDelaySecs = flags.highlightDelaySecs;
+ if (flags.sortKey > 0) {
+ // -t -s <key> means "tree sorted by key"
+ // -s <key> means "list sorted by key" (previous existing behavior)
+ if (!flags.treeView) {
+ settings->treeView = false;
+ }
+ Settings_setSortKey(settings, flags.sortKey);
+ }
+
+ CRT_init(settings, flags.allowUnicode);
+
+ MainPanel* panel = MainPanel_new();
+ ProcessList_setPanel(pl, (Panel*) panel);
+
+ MainPanel_updateTreeFunctions(panel, settings->treeView);
+
+ State state = {
+ .settings = settings,
+ .ut = ut,
+ .pl = pl,
+ .mainPanel = panel,
+ .header = header,
+ .pauseProcessUpdate = false,
+ .hideProcessSelection = false,
+ };
+
+ MainPanel_setState(panel, &state);
+ if (flags.commFilter)
+ setCommFilter(&state, &(flags.commFilter));
+
+ ScreenManager* scr = ScreenManager_new(header, settings, &state, true);
+ ScreenManager_add(scr, (Panel*) panel, -1);
+
+ ProcessList_scan(pl, false);
+ CommandLine_delay(pl, 75);
+ ProcessList_scan(pl, false);
+
+ if (settings->allBranchesCollapsed)
+ ProcessList_collapseAllBranches(pl);
+
+ ScreenManager_run(scr, NULL, NULL);
+
+ attron(CRT_colors[RESET_COLOR]);
+ mvhline(LINES - 1, 0, ' ', COLS);
+ attroff(CRT_colors[RESET_COLOR]);
+ refresh();
+
+ Platform_done();
+
+ CRT_done();
+
+ if (settings->changed) {
+ int r = Settings_write(settings, false);
+ if (r < 0)
+ fprintf(stderr, "Can not save configuration to %s: %s\n", settings->filename, strerror(-r));
+ }
+
+ Header_delete(header);
+ ProcessList_delete(pl);
+
+ ScreenManager_delete(scr);
+ MetersPanel_cleanup();
+
+ UsersTable_delete(ut);
+
+ if (flags.pidMatchList)
+ Hashtable_delete(flags.pidMatchList);
+
+ CRT_resetSignalHandlers();
+
+ /* Delete these last, since they can get accessed in the crash handler */
+ Settings_delete(settings);
+ DynamicColumns_delete(dc);
+ DynamicMeters_delete(dm);
+
+ return 0;
+}

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