int main(int argc, char *argv[]) { int r; Hashmap *a = NULL, *b = NULL; unsigned iteration = 0; usec_t last_refresh = 0; bool quit = false, immediate_refresh = false; _cleanup_free_ char *root = NULL; CGroupMask mask; log_parse_environment(); log_open(); r = cg_mask_supported(&mask); if (r < 0) { log_error_errno(r, "Failed to determine supported controllers: %m"); goto finish; } arg_count = (mask & CGROUP_MASK_PIDS) ? COUNT_PIDS : COUNT_USERSPACE_PROCESSES; r = parse_argv(argc, argv); if (r <= 0) goto finish; r = get_cgroup_root(&root); if (r < 0) { log_error_errno(r, "Failed to get root control group path: %m"); goto finish; } a = hashmap_new(&string_hash_ops); b = hashmap_new(&string_hash_ops); if (!a || !b) { r = log_oom(); goto finish; } signal(SIGWINCH, columns_lines_cache_reset); if (arg_iterations == (unsigned) -1) arg_iterations = on_tty() ? 0 : 1; while (!quit) { Hashmap *c; usec_t t; char key; char h[FORMAT_TIMESPAN_MAX]; t = now(CLOCK_MONOTONIC); if (t >= last_refresh + arg_delay || immediate_refresh) { r = refresh(root, a, b, iteration++); if (r < 0) { log_error_errno(r, "Failed to refresh: %m"); goto finish; } group_hashmap_clear(b); c = a; a = b; b = c; last_refresh = t; immediate_refresh = false; } display(b); if (arg_iterations && iteration >= arg_iterations) break; if (!on_tty()) /* non-TTY: Empty newline as delimiter between polls */ fputs("\n", stdout); fflush(stdout); if (arg_batch) (void) usleep(last_refresh + arg_delay - t); else { r = read_one_char(stdin, &key, last_refresh + arg_delay - t, NULL); if (r == -ETIMEDOUT) continue; if (r < 0) { log_error_errno(r, "Couldn't read key: %m"); goto finish; } } if (on_tty()) { /* TTY: Clear any user keystroke */ fputs("\r \r", stdout); fflush(stdout); } if (arg_batch) continue; switch (key) { case ' ': immediate_refresh = true; break; case 'q': quit = true; break; case 'p': arg_order = ORDER_PATH; break; case 't': arg_order = ORDER_TASKS; break; case 'c': arg_order = ORDER_CPU; break; case 'm': arg_order = ORDER_MEMORY; break; case 'i': arg_order = ORDER_IO; break; case '%': arg_cpu_type = arg_cpu_type == CPU_TIME ? CPU_PERCENT : CPU_TIME; break; case 'k': arg_count = arg_count != COUNT_ALL_PROCESSES ? COUNT_ALL_PROCESSES : COUNT_PIDS; fprintf(stdout, "\nCounting: %s.", counting_what()); fflush(stdout); sleep(1); break; case 'P': arg_count = arg_count != COUNT_USERSPACE_PROCESSES ? COUNT_USERSPACE_PROCESSES : COUNT_PIDS; fprintf(stdout, "\nCounting: %s.", counting_what()); fflush(stdout); sleep(1); break; case 'r': if (arg_count == COUNT_PIDS) fprintf(stdout, "\n\aCannot toggle recursive counting, not available in task counting mode."); else { arg_recursive = !arg_recursive; fprintf(stdout, "\nRecursive process counting: %s", yes_no(arg_recursive)); } fflush(stdout); sleep(1); break; case '+': if (arg_delay < USEC_PER_SEC) arg_delay += USEC_PER_MSEC*250; else arg_delay += USEC_PER_SEC; fprintf(stdout, "\nIncreased delay to %s.", format_timespan(h, sizeof(h), arg_delay, 0)); fflush(stdout); sleep(1); break; case '-': if (arg_delay <= USEC_PER_MSEC*500) arg_delay = USEC_PER_MSEC*250; else if (arg_delay < USEC_PER_MSEC*1250) arg_delay -= USEC_PER_MSEC*250; else arg_delay -= USEC_PER_SEC; fprintf(stdout, "\nDecreased delay to %s.", format_timespan(h, sizeof(h), arg_delay, 0)); fflush(stdout); sleep(1); break; case '?': case 'h': #define ON ANSI_HIGHLIGHT #define OFF ANSI_NORMAL fprintf(stdout, "\t<" ON "p" OFF "> By path; <" ON "t" OFF "> By tasks/procs; <" ON "c" OFF "> By CPU; <" ON "m" OFF "> By memory; <" ON "i" OFF "> By I/O\n" "\t<" ON "+" OFF "> Inc. delay; <" ON "-" OFF "> Dec. delay; <" ON "%%" OFF "> Toggle time; <" ON "SPACE" OFF "> Refresh\n" "\t<" ON "P" OFF "> Toggle count userspace processes; <" ON "k" OFF "> Toggle count all processes\n" "\t<" ON "r" OFF "> Count processes recursively; <" ON "q" OFF "> Quit"); fflush(stdout); sleep(3); break; default: if (key < ' ') fprintf(stdout, "\nUnknown key '\\x%x'. Ignoring.", key); else fprintf(stdout, "\nUnknown key '%c'. Ignoring.", key); fflush(stdout); sleep(1); break; } } r = 0; finish: group_hashmap_free(a); group_hashmap_free(b); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
int main(int argc, char *argv[]) { int r, output_flags; log_parse_environment(); log_open(); r = parse_argv(argc, argv); if (r <= 0) goto finish; if (!arg_no_pager) { r = pager_open(false); if (r > 0 && arg_full < 0) arg_full = true; } output_flags = arg_all * OUTPUT_SHOW_ALL | (arg_full > 0) * OUTPUT_FULL_WIDTH; if (optind < argc) { _cleanup_free_ char *root = NULL; int i; r = get_cgroup_root(&root); if (r < 0) goto finish; for (i = optind; i < argc; i++) { int q; if (path_startswith(argv[i], "/sys/fs/cgroup")) { printf("Directory %s:\n", argv[i]); fflush(stdout); q = show_cgroup_by_path(argv[i], NULL, 0, arg_kernel_threads, output_flags); } else { _cleanup_free_ char *c = NULL, *p = NULL, *j = NULL; const char *controller, *path; r = cg_split_spec(argv[i], &c, &p); if (r < 0) { log_error_errno(r, "Failed to split argument %s: %m", argv[i]); goto finish; } controller = c ?: SYSTEMD_CGROUP_CONTROLLER; if (p) { j = strjoin(root, "/", p, NULL); if (!j) { r = log_oom(); goto finish; } path_kill_slashes(j); path = j; } else path = root; show_cg_info(controller, path); q = show_cgroup(controller, path, NULL, 0, arg_kernel_threads, output_flags); } if (q < 0) r = q; } } else {