1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
33 #include "alloc-util.h"
34 #include "bus-error.h"
36 #include "cgroup-util.h"
40 #include "parse-util.h"
41 #include "path-util.h"
42 #include "process-util.h"
43 #include "stdio-util.h"
44 #include "terminal-util.h"
45 #include "unit-name.h"
48 typedef struct Group
{
58 unsigned cpu_iteration
;
65 unsigned io_iteration
;
66 uint64_t io_input
, io_output
;
68 uint64_t io_input_bps
, io_output_bps
;
71 static unsigned arg_depth
= 3;
72 static unsigned arg_iterations
= (unsigned) -1;
73 static bool arg_batch
= false;
74 static bool arg_raw
= false;
75 static usec_t arg_delay
= 1*USEC_PER_SEC
;
76 static char* arg_machine
= NULL
;
80 COUNT_USERSPACE_PROCESSES
,
82 } arg_count
= COUNT_PIDS
;
83 static bool arg_recursive
= true;
91 } arg_order
= ORDER_CPU
;
96 } arg_cpu_type
= CPU_PERCENT
;
98 static void group_free(Group
*g
) {
105 static void group_hashmap_clear(Hashmap
*h
) {
108 while ((g
= hashmap_steal_first(h
)))
112 static void group_hashmap_free(Hashmap
*h
) {
113 group_hashmap_clear(h
);
117 static const char *maybe_format_bytes(char *buf
, size_t l
, bool is_valid
, uint64_t t
) {
121 snprintf(buf
, l
, "%jd", t
);
124 return format_bytes(buf
, l
, t
);
128 const char *controller
,
142 g
= hashmap_get(a
, path
);
144 g
= hashmap_get(b
, path
);
150 g
->path
= strdup(path
);
156 r
= hashmap_put(a
, g
->path
, g
);
162 r
= hashmap_move_one(a
, b
, path
);
166 g
->cpu_valid
= g
->memory_valid
= g
->io_valid
= g
->n_tasks_valid
= false;
170 if (streq(controller
, SYSTEMD_CGROUP_CONTROLLER
) && IN_SET(arg_count
, COUNT_ALL_PROCESSES
, COUNT_USERSPACE_PROCESSES
)) {
171 _cleanup_fclose_
FILE *f
= NULL
;
174 r
= cg_enumerate_processes(controller
, path
, &f
);
181 while (cg_read_pid(f
, &pid
) > 0) {
183 if (arg_count
== COUNT_USERSPACE_PROCESSES
&& is_kernel_thread(pid
) > 0)
190 g
->n_tasks_valid
= true;
192 } else if (streq(controller
, "pids") && arg_count
== COUNT_PIDS
) {
193 _cleanup_free_
char *p
= NULL
, *v
= NULL
;
195 r
= cg_get_path(controller
, path
, "pids.current", &p
);
199 r
= read_one_line_file(p
, &v
);
205 r
= safe_atou64(v
, &g
->n_tasks
);
210 g
->n_tasks_valid
= true;
212 } else if (streq(controller
, "cpuacct") && cg_unified() <= 0) {
213 _cleanup_free_
char *p
= NULL
, *v
= NULL
;
217 r
= cg_get_path(controller
, path
, "cpuacct.usage", &p
);
221 r
= read_one_line_file(p
, &v
);
227 r
= safe_atou64(v
, &new_usage
);
231 timestamp
= now_nsec(CLOCK_MONOTONIC
);
233 if (g
->cpu_iteration
== iteration
- 1 &&
234 (nsec_t
) new_usage
> g
->cpu_usage
) {
238 x
= timestamp
- g
->cpu_timestamp
;
242 y
= (nsec_t
) new_usage
- g
->cpu_usage
;
243 g
->cpu_fraction
= (double) y
/ (double) x
;
247 g
->cpu_usage
= (nsec_t
) new_usage
;
248 g
->cpu_timestamp
= timestamp
;
249 g
->cpu_iteration
= iteration
;
251 } else if (streq(controller
, "memory")) {
252 _cleanup_free_
char *p
= NULL
, *v
= NULL
;
254 if (cg_unified() <= 0)
255 r
= cg_get_path(controller
, path
, "memory.usage_in_bytes", &p
);
257 r
= cg_get_path(controller
, path
, "memory.current", &p
);
261 r
= read_one_line_file(p
, &v
);
267 r
= safe_atou64(v
, &g
->memory
);
272 g
->memory_valid
= true;
274 } else if (streq(controller
, "blkio") && cg_unified() <= 0) {
275 _cleanup_fclose_
FILE *f
= NULL
;
276 _cleanup_free_
char *p
= NULL
;
277 uint64_t wr
= 0, rd
= 0;
280 r
= cg_get_path(controller
, path
, "blkio.io_service_bytes", &p
);
292 char line
[LINE_MAX
], *l
;
295 if (!fgets(line
, sizeof(line
), f
))
299 l
+= strcspn(l
, WHITESPACE
);
300 l
+= strspn(l
, WHITESPACE
);
302 if (first_word(l
, "Read")) {
305 } else if (first_word(l
, "Write")) {
311 l
+= strspn(l
, WHITESPACE
);
312 r
= safe_atou64(l
, &k
);
319 timestamp
= now_nsec(CLOCK_MONOTONIC
);
321 if (g
->io_iteration
== iteration
- 1) {
324 x
= (uint64_t) (timestamp
- g
->io_timestamp
);
328 if (rd
> g
->io_input
)
329 yr
= rd
- g
->io_input
;
333 if (wr
> g
->io_output
)
334 yw
= wr
- g
->io_output
;
338 if (yr
> 0 || yw
> 0) {
339 g
->io_input_bps
= (yr
* 1000000000ULL) / x
;
340 g
->io_output_bps
= (yw
* 1000000000ULL) / x
;
347 g
->io_timestamp
= timestamp
;
348 g
->io_iteration
= iteration
;
357 static int refresh_one(
358 const char *controller
,
366 _cleanup_closedir_
DIR *d
= NULL
;
374 if (depth
> arg_depth
)
377 r
= process(controller
, path
, a
, b
, iteration
, &ours
);
381 r
= cg_enumerate_subgroups(controller
, path
, &d
);
388 _cleanup_free_
char *fn
= NULL
, *p
= NULL
;
391 r
= cg_read_subgroup(d
, &fn
);
397 p
= strjoin(path
, "/", fn
, NULL
);
401 path_kill_slashes(p
);
403 r
= refresh_one(controller
, p
, a
, b
, iteration
, depth
+ 1, &child
);
408 IN_SET(arg_count
, COUNT_ALL_PROCESSES
, COUNT_USERSPACE_PROCESSES
) &&
410 child
->n_tasks_valid
&&
411 streq(controller
, SYSTEMD_CGROUP_CONTROLLER
)) {
413 /* Recursively sum up processes */
415 if (ours
->n_tasks_valid
)
416 ours
->n_tasks
+= child
->n_tasks
;
418 ours
->n_tasks
= child
->n_tasks
;
419 ours
->n_tasks_valid
= true;
430 static int refresh(const char *root
, Hashmap
*a
, Hashmap
*b
, unsigned iteration
) {
435 r
= refresh_one(SYSTEMD_CGROUP_CONTROLLER
, root
, a
, b
, iteration
, 0, NULL
);
438 r
= refresh_one("cpuacct", root
, a
, b
, iteration
, 0, NULL
);
441 r
= refresh_one("memory", root
, a
, b
, iteration
, 0, NULL
);
444 r
= refresh_one("blkio", root
, a
, b
, iteration
, 0, NULL
);
447 r
= refresh_one("pids", root
, a
, b
, iteration
, 0, NULL
);
454 static int group_compare(const void*a
, const void *b
) {
455 const Group
*x
= *(Group
**)a
, *y
= *(Group
**)b
;
457 if (arg_order
!= ORDER_TASKS
|| arg_recursive
) {
458 /* Let's make sure that the parent is always before
459 * the child. Except when ordering by tasks and
460 * recursive summing is off, since that is actually
461 * not accumulative for all children. */
463 if (path_startswith(y
->path
, x
->path
))
465 if (path_startswith(x
->path
, y
->path
))
475 if (arg_cpu_type
== CPU_PERCENT
) {
476 if (x
->cpu_valid
&& y
->cpu_valid
) {
477 if (x
->cpu_fraction
> y
->cpu_fraction
)
479 else if (x
->cpu_fraction
< y
->cpu_fraction
)
481 } else if (x
->cpu_valid
)
483 else if (y
->cpu_valid
)
486 if (x
->cpu_usage
> y
->cpu_usage
)
488 else if (x
->cpu_usage
< y
->cpu_usage
)
495 if (x
->n_tasks_valid
&& y
->n_tasks_valid
) {
496 if (x
->n_tasks
> y
->n_tasks
)
498 else if (x
->n_tasks
< y
->n_tasks
)
500 } else if (x
->n_tasks_valid
)
502 else if (y
->n_tasks_valid
)
508 if (x
->memory_valid
&& y
->memory_valid
) {
509 if (x
->memory
> y
->memory
)
511 else if (x
->memory
< y
->memory
)
513 } else if (x
->memory_valid
)
515 else if (y
->memory_valid
)
521 if (x
->io_valid
&& y
->io_valid
) {
522 if (x
->io_input_bps
+ x
->io_output_bps
> y
->io_input_bps
+ y
->io_output_bps
)
524 else if (x
->io_input_bps
+ x
->io_output_bps
< y
->io_input_bps
+ y
->io_output_bps
)
526 } else if (x
->io_valid
)
528 else if (y
->io_valid
)
532 return path_compare(x
->path
, y
->path
);
535 static void display(Hashmap
*a
) {
540 unsigned rows
, n
= 0, j
, maxtcpu
= 0, maxtpath
= 3; /* 3 for ellipsize() to work properly */
541 char buffer
[MAX3(21, FORMAT_BYTES_MAX
, FORMAT_TIMESPAN_MAX
)];
546 fputs(ANSI_HOME_CLEAR
, stdout
);
548 array
= alloca(sizeof(Group
*) * hashmap_size(a
));
550 HASHMAP_FOREACH(g
, a
, i
)
551 if (g
->n_tasks_valid
|| g
->cpu_valid
|| g
->memory_valid
|| g
->io_valid
)
554 qsort_safe(array
, n
, sizeof(Group
*), group_compare
);
556 /* Find the longest names in one run */
557 for (j
= 0; j
< n
; j
++) {
558 unsigned cputlen
, pathtlen
;
560 format_timespan(buffer
, sizeof(buffer
), (usec_t
) (array
[j
]->cpu_usage
/ NSEC_PER_USEC
), 0);
561 cputlen
= strlen(buffer
);
562 maxtcpu
= MAX(maxtcpu
, cputlen
);
564 pathtlen
= strlen(array
[j
]->path
);
565 maxtpath
= MAX(maxtpath
, pathtlen
);
568 if (arg_cpu_type
== CPU_PERCENT
)
569 xsprintf(buffer
, "%6s", "%CPU");
571 xsprintf(buffer
, "%*s", maxtcpu
, "CPU Time");
578 const char *on
, *off
;
580 path_columns
= columns() - 36 - strlen(buffer
);
581 if (path_columns
< 10)
584 on
= ansi_highlight_underline();
585 off
= ansi_underline();
587 printf("%s%s%-*s%s %s%7s%s %s%s%s %s%8s%s %s%8s%s %s%8s%s%s\n",
589 arg_order
== ORDER_PATH
? on
: "", path_columns
, "Control Group",
590 arg_order
== ORDER_PATH
? off
: "",
591 arg_order
== ORDER_TASKS
? on
: "", arg_count
== COUNT_PIDS
? "Tasks" : arg_count
== COUNT_USERSPACE_PROCESSES
? "Procs" : "Proc+",
592 arg_order
== ORDER_TASKS
? off
: "",
593 arg_order
== ORDER_CPU
? on
: "", buffer
,
594 arg_order
== ORDER_CPU
? off
: "",
595 arg_order
== ORDER_MEMORY
? on
: "", "Memory",
596 arg_order
== ORDER_MEMORY
? off
: "",
597 arg_order
== ORDER_IO
? on
: "", "Input/s",
598 arg_order
== ORDER_IO
? off
: "",
599 arg_order
== ORDER_IO
? on
: "", "Output/s",
600 arg_order
== ORDER_IO
? off
: "",
603 path_columns
= maxtpath
;
605 for (j
= 0; j
< n
; j
++) {
606 _cleanup_free_
char *ellipsized
= NULL
;
609 if (on_tty() && j
+ 6 > rows
)
614 path
= isempty(g
->path
) ? "/" : g
->path
;
615 ellipsized
= ellipsize(path
, path_columns
, 33);
616 printf("%-*s", path_columns
, ellipsized
?: path
);
618 if (g
->n_tasks_valid
)
619 printf(" %7" PRIu64
, g
->n_tasks
);
623 if (arg_cpu_type
== CPU_PERCENT
) {
625 printf(" %6.1f", g
->cpu_fraction
*100);
629 printf(" %*s", maxtcpu
, format_timespan(buffer
, sizeof(buffer
), (usec_t
) (g
->cpu_usage
/ NSEC_PER_USEC
), 0));
631 printf(" %8s", maybe_format_bytes(buffer
, sizeof(buffer
), g
->memory_valid
, g
->memory
));
632 printf(" %8s", maybe_format_bytes(buffer
, sizeof(buffer
), g
->io_valid
, g
->io_input_bps
));
633 printf(" %8s", maybe_format_bytes(buffer
, sizeof(buffer
), g
->io_valid
, g
->io_output_bps
));
639 static void help(void) {
640 printf("%s [OPTIONS...]\n\n"
641 "Show top control groups by their resource usage.\n\n"
642 " -h --help Show this help\n"
643 " --version Show package version\n"
644 " -p --order=path Order by path\n"
645 " -t --order=tasks Order by number of tasks/processes\n"
646 " -c --order=cpu Order by CPU load (default)\n"
647 " -m --order=memory Order by memory load\n"
648 " -i --order=io Order by IO load\n"
649 " -r --raw Provide raw (not human-readable) numbers\n"
650 " --cpu=percentage Show CPU usage as percentage (default)\n"
651 " --cpu=time Show CPU usage as time\n"
652 " -P Count userspace processes instead of tasks (excl. kernel)\n"
653 " -k Count all processes instead of tasks (incl. kernel)\n"
654 " --recursive=BOOL Sum up process count recursively\n"
655 " -d --delay=DELAY Delay between updates\n"
656 " -n --iterations=N Run for N iterations before exiting\n"
657 " -b --batch Run in batch mode, accepting no input\n"
658 " --depth=DEPTH Maximum traversal depth (default: %u)\n"
659 " -M --machine= Show container\n"
660 , program_invocation_short_name
, arg_depth
);
663 static int parse_argv(int argc
, char *argv
[]) {
673 static const struct option options
[] = {
674 { "help", no_argument
, NULL
, 'h' },
675 { "version", no_argument
, NULL
, ARG_VERSION
},
676 { "delay", required_argument
, NULL
, 'd' },
677 { "iterations", required_argument
, NULL
, 'n' },
678 { "batch", no_argument
, NULL
, 'b' },
679 { "raw", no_argument
, NULL
, 'r' },
680 { "depth", required_argument
, NULL
, ARG_DEPTH
},
681 { "cpu", optional_argument
, NULL
, ARG_CPU_TYPE
},
682 { "order", required_argument
, NULL
, ARG_ORDER
},
683 { "recursive", required_argument
, NULL
, ARG_RECURSIVE
},
684 { "machine", required_argument
, NULL
, 'M' },
688 bool recursive_unset
= false;
694 while ((c
= getopt_long(argc
, argv
, "hptcmin:brd:kPM:", options
, NULL
)) >= 0)
707 if (streq(optarg
, "time"))
708 arg_cpu_type
= CPU_TIME
;
709 else if (streq(optarg
, "percentage"))
710 arg_cpu_type
= CPU_PERCENT
;
712 log_error("Unknown argument to --cpu=: %s", optarg
);
716 arg_cpu_type
= CPU_TIME
;
721 r
= safe_atou(optarg
, &arg_depth
);
723 log_error("Failed to parse depth parameter.");
730 r
= parse_sec(optarg
, &arg_delay
);
731 if (r
< 0 || arg_delay
<= 0) {
732 log_error("Failed to parse delay parameter.");
739 r
= safe_atou(optarg
, &arg_iterations
);
741 log_error("Failed to parse iterations parameter.");
756 arg_order
= ORDER_PATH
;
760 arg_order
= ORDER_TASKS
;
764 arg_order
= ORDER_CPU
;
768 arg_order
= ORDER_MEMORY
;
772 arg_order
= ORDER_IO
;
776 if (streq(optarg
, "path"))
777 arg_order
= ORDER_PATH
;
778 else if (streq(optarg
, "tasks"))
779 arg_order
= ORDER_TASKS
;
780 else if (streq(optarg
, "cpu"))
781 arg_order
= ORDER_CPU
;
782 else if (streq(optarg
, "memory"))
783 arg_order
= ORDER_MEMORY
;
784 else if (streq(optarg
, "io"))
785 arg_order
= ORDER_IO
;
787 log_error("Invalid argument to --order=: %s", optarg
);
793 arg_count
= COUNT_ALL_PROCESSES
;
797 arg_count
= COUNT_USERSPACE_PROCESSES
;
801 r
= parse_boolean(optarg
);
803 log_error("Failed to parse --recursive= argument: %s", optarg
);
808 recursive_unset
= r
== 0;
812 arg_machine
= optarg
;
819 assert_not_reached("Unhandled option");
823 log_error("Too many arguments.");
827 if (recursive_unset
&& arg_count
== COUNT_PIDS
) {
828 log_error("Non-recursive counting is only supported when counting processes, not tasks. Use -P or -k.");
835 static const char* counting_what(void) {
836 if (arg_count
== COUNT_PIDS
)
838 else if (arg_count
== COUNT_ALL_PROCESSES
)
839 return "all processes (incl. kernel)";
841 return "userspace processes (excl. kernel)";
844 static int get_cgroup_root(char **ret
) {
845 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
846 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
847 _cleanup_free_
char *unit
= NULL
, *path
= NULL
;
852 r
= cg_get_root_path(ret
);
854 return log_error_errno(r
, "Failed to get root control group path: %m");
859 m
= strjoina("/run/systemd/machines/", arg_machine
);
860 r
= parse_env_file(m
, NEWLINE
, "SCOPE", &unit
, NULL
);
862 return log_error_errno(r
, "Failed to load machine data: %m");
864 path
= unit_dbus_path_from_name(unit
);
868 r
= bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL
, NULL
, false, &bus
);
870 return log_error_errno(r
, "Failed to create bus connection: %m");
872 r
= sd_bus_get_property_string(
874 "org.freedesktop.systemd1",
876 unit_dbus_interface_from_name(unit
),
881 return log_error_errno(r
, "Failed to query unit control group path: %s", bus_error_message(&error
, r
));
886 int main(int argc
, char *argv
[]) {
888 Hashmap
*a
= NULL
, *b
= NULL
;
889 unsigned iteration
= 0;
890 usec_t last_refresh
= 0;
891 bool quit
= false, immediate_refresh
= false;
892 _cleanup_free_
char *root
= NULL
;
895 log_parse_environment();
898 r
= cg_mask_supported(&mask
);
900 log_error_errno(r
, "Failed to determine supported controllers: %m");
904 arg_count
= (mask
& CGROUP_MASK_PIDS
) ? COUNT_PIDS
: COUNT_USERSPACE_PROCESSES
;
906 r
= parse_argv(argc
, argv
);
910 r
= get_cgroup_root(&root
);
912 log_error_errno(r
, "Failed to get root control group path: %m");
916 a
= hashmap_new(&string_hash_ops
);
917 b
= hashmap_new(&string_hash_ops
);
923 signal(SIGWINCH
, columns_lines_cache_reset
);
925 if (arg_iterations
== (unsigned) -1)
926 arg_iterations
= on_tty() ? 0 : 1;
932 char h
[FORMAT_TIMESPAN_MAX
];
934 t
= now(CLOCK_MONOTONIC
);
936 if (t
>= last_refresh
+ arg_delay
|| immediate_refresh
) {
938 r
= refresh(root
, a
, b
, iteration
++);
940 log_error_errno(r
, "Failed to refresh: %m");
944 group_hashmap_clear(b
);
951 immediate_refresh
= false;
956 if (arg_iterations
&& iteration
>= arg_iterations
)
959 if (!on_tty()) /* non-TTY: Empty newline as delimiter between polls */
964 (void) usleep(last_refresh
+ arg_delay
- t
);
966 r
= read_one_char(stdin
, &key
, last_refresh
+ arg_delay
- t
, NULL
);
970 log_error_errno(r
, "Couldn't read key: %m");
975 if (on_tty()) { /* TTY: Clear any user keystroke */
976 fputs("\r \r", stdout
);
986 immediate_refresh
= true;
994 arg_order
= ORDER_PATH
;
998 arg_order
= ORDER_TASKS
;
1002 arg_order
= ORDER_CPU
;
1006 arg_order
= ORDER_MEMORY
;
1010 arg_order
= ORDER_IO
;
1014 arg_cpu_type
= arg_cpu_type
== CPU_TIME
? CPU_PERCENT
: CPU_TIME
;
1018 arg_count
= arg_count
!= COUNT_ALL_PROCESSES
? COUNT_ALL_PROCESSES
: COUNT_PIDS
;
1019 fprintf(stdout
, "\nCounting: %s.", counting_what());
1025 arg_count
= arg_count
!= COUNT_USERSPACE_PROCESSES
? COUNT_USERSPACE_PROCESSES
: COUNT_PIDS
;
1026 fprintf(stdout
, "\nCounting: %s.", counting_what());
1032 if (arg_count
== COUNT_PIDS
)
1033 fprintf(stdout
, "\n\aCannot toggle recursive counting, not available in task counting mode.");
1035 arg_recursive
= !arg_recursive
;
1036 fprintf(stdout
, "\nRecursive process counting: %s", yes_no(arg_recursive
));
1043 if (arg_delay
< USEC_PER_SEC
)
1044 arg_delay
+= USEC_PER_MSEC
*250;
1046 arg_delay
+= USEC_PER_SEC
;
1048 fprintf(stdout
, "\nIncreased delay to %s.", format_timespan(h
, sizeof(h
), arg_delay
, 0));
1054 if (arg_delay
<= USEC_PER_MSEC
*500)
1055 arg_delay
= USEC_PER_MSEC
*250;
1056 else if (arg_delay
< USEC_PER_MSEC
*1250)
1057 arg_delay
-= USEC_PER_MSEC
*250;
1059 arg_delay
-= USEC_PER_SEC
;
1061 fprintf(stdout
, "\nDecreased delay to %s.", format_timespan(h
, sizeof(h
), arg_delay
, 0));
1069 #define ON ANSI_HIGHLIGHT
1070 #define OFF ANSI_NORMAL
1073 "\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"
1074 "\t<" ON
"+" OFF
"> Inc. delay; <" ON
"-" OFF
"> Dec. delay; <" ON
"%%" OFF
"> Toggle time; <" ON
"SPACE" OFF
"> Refresh\n"
1075 "\t<" ON
"P" OFF
"> Toggle count userspace processes; <" ON
"k" OFF
"> Toggle count all processes\n"
1076 "\t<" ON
"r" OFF
"> Count processes recursively; <" ON
"q" OFF
"> Quit");
1083 fprintf(stdout
, "\nUnknown key '\\x%x'. Ignoring.", key
);
1085 fprintf(stdout
, "\nUnknown key '%c'. Ignoring.", key
);
1095 group_hashmap_free(a
);
1096 group_hashmap_free(b
);
1098 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;