1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include "bus-log-control-api.h"
6 #include "bus-object.h"
7 #include "cgroup-util.h"
8 #include "conf-parser.h"
9 #include "daemon-util.h"
11 #include "main-func.h"
12 #include "oomd-manager.h"
13 #include "oomd-manager-bus.h"
14 #include "parse-util.h"
15 #include "pretty-print.c"
17 #include "signal-util.h"
19 static bool arg_dry_run
= false;
20 static int arg_swap_used_limit
= -1;
21 static int arg_mem_pressure_limit_permyriad
= -1;
22 static usec_t arg_mem_pressure_usec
= 0;
24 static int parse_config(void) {
25 static const ConfigTableItem items
[] = {
26 { "OOM", "SwapUsedLimitPercent", config_parse_percent
, 0, &arg_swap_used_limit
},
27 { "OOM", "DefaultMemoryPressureLimit", config_parse_permyriad
, 0, &arg_mem_pressure_limit_permyriad
},
28 { "OOM", "DefaultMemoryPressureDurationSec", config_parse_sec
, 0, &arg_mem_pressure_usec
},
32 return config_parse_many_nulstr(PKGSYSCONFDIR
"/oomd.conf",
33 CONF_PATHS_NULSTR("systemd/oomd.conf.d"),
35 config_item_table_lookup
,
42 static int help(void) {
43 _cleanup_free_
char *link
= NULL
;
46 r
= terminal_urlify_man("systemd-oomd", "1", &link
);
50 printf("%s [OPTIONS...]\n\n"
51 "Run the userspace out-of-memory (OOM) killer.\n\n"
52 " -h --help Show this help\n"
53 " --version Show package version\n"
54 " --dry-run Only print destructive actions instead of doing them\n"
55 " --bus-introspect=PATH Write D-Bus XML introspection data\n"
56 "\nSee the %s for details.\n",
57 program_invocation_short_name
,
63 static int parse_argv(int argc
, char *argv
[]) {
70 static const struct option options
[] = {
71 { "help", no_argument
, NULL
, 'h' },
72 { "version", no_argument
, NULL
, ARG_VERSION
},
73 { "dry-run", no_argument
, NULL
, ARG_DRY_RUN
},
74 { "bus-introspect", required_argument
, NULL
, ARG_BUS_INTROSPECT
},
83 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
97 case ARG_BUS_INTROSPECT
:
98 return bus_introspect_implementations(
101 BUS_IMPLEMENTATIONS(&manager_object
,
102 &log_control_object
));
108 assert_not_reached("Unknown option code.");
112 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
113 "This program takes no arguments.");
118 static int run(int argc
, char *argv
[]) {
119 _cleanup_(notify_on_cleanup
) const char *notify_msg
= NULL
;
120 _cleanup_(manager_freep
) Manager
*m
= NULL
;
121 _cleanup_free_
char *swap
= NULL
;
122 unsigned long long s
= 0;
127 r
= parse_argv(argc
, argv
);
135 /* Do some basic requirement checks for running systemd-oomd. It's not exhaustive as some of the other
136 * requirements do not have a reliable means to check for in code. */
138 /* SwapTotal is always available in /proc/meminfo and defaults to 0, even on swap-disabled kernels. */
139 r
= get_proc_field("/proc/meminfo", "SwapTotal", WHITESPACE
, &swap
);
141 return log_error_errno(r
, "Failed to get SwapTotal from /proc/meminfo: %m");
143 r
= safe_atollu(swap
, &s
);
145 log_warning("Swap is currently not detected; memory pressure usage will be degraded");
147 if (!is_pressure_supported())
148 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Pressure Stall Information (PSI) is not supported");
150 r
= cg_all_unified();
152 return log_error_errno(r
, "Failed to determine whether the unified cgroups hierarchy is used: %m");
154 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Requires the unified cgroups hierarchy");
156 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGTERM
, SIGINT
, -1) >= 0);
160 return log_error_errno(r
, "Failed to create manager: %m");
162 r
= manager_start(m
, arg_dry_run
, arg_swap_used_limit
, arg_mem_pressure_limit_permyriad
, arg_mem_pressure_usec
);
164 return log_error_errno(r
, "Failed to start up daemon: %m");
166 notify_msg
= notify_start(NOTIFY_READY
, NOTIFY_STOPPING
);
168 log_info("systemd-oomd starting%s!", arg_dry_run
? " in dry run mode" : "");
170 r
= sd_event_loop(m
->event
);
172 return log_error_errno(r
, "Event loop failed: %m");
177 DEFINE_MAIN_FUNCTION(run
);