LCOV - code coverage report
Current view: top level - cgls - cgls.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 24 142 16.9 %
Date: 2019-08-22 15:41:25 Functions: 5 6 83.3 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <errno.h>
       4             : #include <getopt.h>
       5             : #include <stdio.h>
       6             : #include <string.h>
       7             : #include <unistd.h>
       8             : 
       9             : #include "sd-bus.h"
      10             : 
      11             : #include "alloc-util.h"
      12             : #include "bus-util.h"
      13             : #include "cgroup-show.h"
      14             : #include "cgroup-util.h"
      15             : #include "fileio.h"
      16             : #include "log.h"
      17             : #include "main-func.h"
      18             : #include "output-mode.h"
      19             : #include "pager.h"
      20             : #include "path-util.h"
      21             : #include "pretty-print.h"
      22             : #include "strv.h"
      23             : #include "unit-name.h"
      24             : #include "util.h"
      25             : 
      26             : static PagerFlags arg_pager_flags = 0;
      27             : static bool arg_kernel_threads = false;
      28             : static bool arg_all = false;
      29             : 
      30             : static enum {
      31             :         SHOW_UNIT_NONE,
      32             :         SHOW_UNIT_SYSTEM,
      33             :         SHOW_UNIT_USER,
      34             : } arg_show_unit = SHOW_UNIT_NONE;
      35             : static char **arg_names = NULL;
      36             : 
      37             : static int arg_full = -1;
      38             : static const char* arg_machine = NULL;
      39             : 
      40           4 : STATIC_DESTRUCTOR_REGISTER(arg_names, freep); /* don't free the strings */
      41             : 
      42           3 : static int help(void) {
      43           3 :         _cleanup_free_ char *link = NULL;
      44             :         int r;
      45             : 
      46           3 :         r = terminal_urlify_man("systemd-cgls", "1", &link);
      47           3 :         if (r < 0)
      48           0 :                 return log_oom();
      49             : 
      50           3 :         printf("%s [OPTIONS...] [CGROUP...]\n\n"
      51             :                "Recursively show control group contents.\n\n"
      52             :                "  -h --help           Show this help\n"
      53             :                "     --version        Show package version\n"
      54             :                "     --no-pager       Do not pipe output into a pager\n"
      55             :                "  -a --all            Show all groups, including empty\n"
      56             :                "  -u --unit           Show the subtrees of specified system units\n"
      57             :                "     --user-unit      Show the subtrees of specified user units\n"
      58             :                "  -l --full           Do not ellipsize output\n"
      59             :                "  -k                  Include kernel threads in output\n"
      60             :                "  -M --machine=       Show container\n"
      61             :                "\nSee the %s for details.\n"
      62             :                , program_invocation_short_name
      63             :                , link
      64             :         );
      65             : 
      66           3 :         return 0;
      67             : }
      68             : 
      69           4 : static int parse_argv(int argc, char *argv[]) {
      70             : 
      71             :         enum {
      72             :                 ARG_NO_PAGER = 0x100,
      73             :                 ARG_VERSION,
      74             :                 ARG_USER_UNIT,
      75             :         };
      76             : 
      77             :         static const struct option options[] = {
      78             :                 { "help",      no_argument,       NULL, 'h'           },
      79             :                 { "version",   no_argument,       NULL, ARG_VERSION   },
      80             :                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
      81             :                 { "all",       no_argument,       NULL, 'a'           },
      82             :                 { "full",      no_argument,       NULL, 'l'           },
      83             :                 { "machine",   required_argument, NULL, 'M'           },
      84             :                 { "unit",      optional_argument, NULL, 'u'           },
      85             :                 { "user-unit", optional_argument, NULL, ARG_USER_UNIT },
      86             :                 {}
      87             :         };
      88             : 
      89             :         int c;
      90             : 
      91           4 :         assert(argc >= 1);
      92           4 :         assert(argv);
      93             : 
      94           4 :         while ((c = getopt_long(argc, argv, "-hkalM:u::", options, NULL)) >= 0)
      95             : 
      96           4 :                 switch (c) {
      97             : 
      98           3 :                 case 'h':
      99           3 :                         return help();
     100             : 
     101           0 :                 case ARG_VERSION:
     102           0 :                         return version();
     103             : 
     104           0 :                 case ARG_NO_PAGER:
     105           0 :                         arg_pager_flags |= PAGER_DISABLE;
     106           0 :                         break;
     107             : 
     108           0 :                 case 'a':
     109           0 :                         arg_all = true;
     110           0 :                         break;
     111             : 
     112           0 :                 case 'u':
     113           0 :                         arg_show_unit = SHOW_UNIT_SYSTEM;
     114           0 :                         if (strv_push(&arg_names, optarg) < 0) /* push optarg if not empty */
     115           0 :                                 return log_oom();
     116           0 :                         break;
     117             : 
     118           0 :                 case ARG_USER_UNIT:
     119           0 :                         arg_show_unit = SHOW_UNIT_USER;
     120           0 :                         if (strv_push(&arg_names, optarg) < 0) /* push optarg if not empty */
     121           0 :                                 return log_oom();
     122           0 :                         break;
     123             : 
     124           0 :                 case 1:
     125             :                         /* positional argument */
     126           0 :                         if (strv_push(&arg_names, optarg) < 0)
     127           0 :                                 return log_oom();
     128           0 :                         break;
     129             : 
     130           0 :                 case 'l':
     131           0 :                         arg_full = true;
     132           0 :                         break;
     133             : 
     134           0 :                 case 'k':
     135           0 :                         arg_kernel_threads = true;
     136           0 :                         break;
     137             : 
     138           0 :                 case 'M':
     139           0 :                         arg_machine = optarg;
     140           0 :                         break;
     141             : 
     142           1 :                 case '?':
     143           1 :                         return -EINVAL;
     144             : 
     145           0 :                 default:
     146           0 :                         assert_not_reached("Unhandled option");
     147             :                 }
     148             : 
     149           0 :         if (arg_machine && arg_show_unit != SHOW_UNIT_NONE)
     150           0 :                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
     151             :                                        "Cannot combine --unit or --user-unit with --machine=.");
     152             : 
     153           0 :         return 1;
     154             : }
     155             : 
     156           0 : static void show_cg_info(const char *controller, const char *path) {
     157             : 
     158           0 :         if (cg_all_unified() == 0 && controller && !streq(controller, SYSTEMD_CGROUP_CONTROLLER))
     159           0 :                 printf("Controller %s; ", controller);
     160             : 
     161           0 :         printf("Control group %s:\n", empty_to_root(path));
     162           0 :         fflush(stdout);
     163           0 : }
     164             : 
     165           4 : static int run(int argc, char *argv[]) {
     166             :         int r, output_flags;
     167             : 
     168           4 :         log_show_color(true);
     169           4 :         log_parse_environment();
     170           4 :         log_open();
     171             : 
     172           4 :         r = parse_argv(argc, argv);
     173           4 :         if (r <= 0)
     174           4 :                 return r;
     175             : 
     176           0 :         r = pager_open(arg_pager_flags);
     177           0 :         if (r > 0 && arg_full < 0)
     178           0 :                 arg_full = true;
     179             : 
     180           0 :         output_flags =
     181           0 :                 arg_all * OUTPUT_SHOW_ALL |
     182           0 :                 (arg_full > 0) * OUTPUT_FULL_WIDTH |
     183           0 :                 arg_kernel_threads * OUTPUT_KERNEL_THREADS;
     184             : 
     185           0 :         if (arg_names) {
     186           0 :                 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
     187           0 :                 _cleanup_free_ char *root = NULL;
     188             :                 char **name;
     189             : 
     190           0 :                 STRV_FOREACH(name, arg_names) {
     191             :                         int q;
     192             : 
     193           0 :                         if (arg_show_unit != SHOW_UNIT_NONE) {
     194             :                                 /* Command line arguments are unit names */
     195           0 :                                 _cleanup_free_ char *cgroup = NULL;
     196             : 
     197           0 :                                 if (!bus) {
     198             :                                         /* Connect to the bus only if necessary */
     199           0 :                                         r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL,
     200             :                                                                           arg_show_unit == SHOW_UNIT_USER,
     201             :                                                                           &bus);
     202           0 :                                         if (r < 0)
     203           0 :                                                 return log_error_errno(r, "Failed to create bus connection: %m");
     204             :                                 }
     205             : 
     206           0 :                                 q = show_cgroup_get_unit_path_and_warn(bus, *name, &cgroup);
     207           0 :                                 if (q < 0)
     208           0 :                                         goto failed;
     209             : 
     210           0 :                                 if (isempty(cgroup)) {
     211           0 :                                         log_warning("Unit %s not found.", *name);
     212           0 :                                         q = -ENOENT;
     213           0 :                                         goto failed;
     214             :                                 }
     215             : 
     216           0 :                                 printf("Unit %s (%s):\n", *name, cgroup);
     217           0 :                                 fflush(stdout);
     218             : 
     219           0 :                                 q = show_cgroup_by_path(cgroup, NULL, 0, output_flags);
     220             : 
     221           0 :                         } else if (path_startswith(*name, "/sys/fs/cgroup")) {
     222             : 
     223           0 :                                 printf("Directory %s:\n", *name);
     224           0 :                                 fflush(stdout);
     225             : 
     226           0 :                                 q = show_cgroup_by_path(*name, NULL, 0, output_flags);
     227             :                         } else {
     228           0 :                                 _cleanup_free_ char *c = NULL, *p = NULL, *j = NULL;
     229             :                                 const char *controller, *path;
     230             : 
     231           0 :                                 if (!root) {
     232             :                                         /* Query root only if needed, treat error as fatal */
     233           0 :                                         r = show_cgroup_get_path_and_warn(arg_machine, NULL, &root);
     234           0 :                                         if (r < 0)
     235           0 :                                                 return log_error_errno(r, "Failed to list cgroup tree: %m");
     236             :                                 }
     237             : 
     238           0 :                                 q = cg_split_spec(*name, &c, &p);
     239           0 :                                 if (q < 0) {
     240           0 :                                         log_error_errno(q, "Failed to split argument %s: %m", *name);
     241           0 :                                         goto failed;
     242             :                                 }
     243             : 
     244           0 :                                 controller = c ?: SYSTEMD_CGROUP_CONTROLLER;
     245           0 :                                 if (p) {
     246           0 :                                         j = path_join(root, p);
     247           0 :                                         if (!j)
     248           0 :                                                 return log_oom();
     249             : 
     250           0 :                                         path_simplify(j, false);
     251           0 :                                         path = j;
     252             :                                 } else
     253           0 :                                         path = root;
     254             : 
     255           0 :                                 show_cg_info(controller, path);
     256             : 
     257           0 :                                 q = show_cgroup(controller, path, NULL, 0, output_flags);
     258             :                         }
     259             : 
     260           0 :                 failed:
     261           0 :                         if (q < 0 && r >= 0)
     262           0 :                                 r = q;
     263             :                 }
     264             : 
     265             :         } else {
     266           0 :                 bool done = false;
     267             : 
     268           0 :                 if (!arg_machine)  {
     269           0 :                         _cleanup_free_ char *cwd = NULL;
     270             : 
     271           0 :                         r = safe_getcwd(&cwd);
     272           0 :                         if (r < 0)
     273           0 :                                 return log_error_errno(r, "Cannot determine current working directory: %m");
     274             : 
     275           0 :                         if (path_startswith(cwd, "/sys/fs/cgroup")) {
     276           0 :                                 printf("Working directory %s:\n", cwd);
     277           0 :                                 fflush(stdout);
     278             : 
     279           0 :                                 r = show_cgroup_by_path(cwd, NULL, 0, output_flags);
     280           0 :                                 done = true;
     281             :                         }
     282             :                 }
     283             : 
     284           0 :                 if (!done) {
     285           0 :                         _cleanup_free_ char *root = NULL;
     286             : 
     287           0 :                         r = show_cgroup_get_path_and_warn(arg_machine, NULL, &root);
     288           0 :                         if (r < 0)
     289           0 :                                 return log_error_errno(r, "Failed to list cgroup tree: %m");
     290             : 
     291           0 :                         show_cg_info(SYSTEMD_CGROUP_CONTROLLER, root);
     292             : 
     293           0 :                         printf("-.slice\n");
     294           0 :                         r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, output_flags);
     295             :                 }
     296             :         }
     297           0 :         if (r < 0)
     298           0 :                 return log_error_errno(r, "Failed to list cgroup tree: %m");
     299             : 
     300           0 :         return 0;
     301             : }
     302             : 
     303           4 : DEFINE_MAIN_FUNCTION(run);

Generated by: LCOV version 1.14