1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
6 #include "bus-log-control-api.h"
7 #include "bus-object.h"
8 #include "cgroup-util.h"
9 #include "conf-parser.h"
10 #include "daemon-util.h"
13 #include "main-func.h"
14 #include "oomd-manager-bus.h"
15 #include "oomd-manager.h"
16 #include "parse-util.h"
17 #include "pretty-print.h"
19 #include "signal-util.h"
21 static bool arg_dry_run
= false;
22 static int arg_swap_used_limit_permyriad
= -1;
23 static int arg_mem_pressure_limit_permyriad
= -1;
24 static usec_t arg_mem_pressure_usec
= 0;
26 static int parse_config(void) {
27 static const ConfigTableItem items
[] = {
28 { "OOM", "SwapUsedLimit", config_parse_permyriad
, 0, &arg_swap_used_limit_permyriad
},
29 { "OOM", "DefaultMemoryPressureLimit", config_parse_permyriad
, 0, &arg_mem_pressure_limit_permyriad
},
30 { "OOM", "DefaultMemoryPressureDurationSec", config_parse_sec
, 0, &arg_mem_pressure_usec
},
34 return config_parse_config_file("oomd.conf", "OOM\0",
35 config_item_table_lookup
, items
,
36 CONFIG_PARSE_WARN
, NULL
);
39 static int help(void) {
40 _cleanup_free_
char *link
= NULL
;
43 r
= terminal_urlify_man("systemd-oomd", "8", &link
);
47 printf("%s [OPTIONS...]\n\n"
48 "Run the userspace out-of-memory (OOM) killer.\n\n"
49 " -h --help Show this help\n"
50 " --version Show package version\n"
51 " --dry-run Only print destructive actions instead of doing them\n"
52 " --bus-introspect=PATH Write D-Bus XML introspection data\n"
53 "\nSee the %s for details.\n",
54 program_invocation_short_name
,
60 static int parse_argv(int argc
, char *argv
[]) {
67 static const struct option options
[] = {
68 { "help", no_argument
, NULL
, 'h' },
69 { "version", no_argument
, NULL
, ARG_VERSION
},
70 { "dry-run", no_argument
, NULL
, ARG_DRY_RUN
},
71 { "bus-introspect", required_argument
, NULL
, ARG_BUS_INTROSPECT
},
80 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
94 case ARG_BUS_INTROSPECT
:
95 return bus_introspect_implementations(
98 BUS_IMPLEMENTATIONS(&manager_object
,
99 &log_control_object
));
105 assert_not_reached();
109 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
110 "This program takes no arguments.");
115 static int run(int argc
, char *argv
[]) {
116 _unused_
_cleanup_(notify_on_cleanup
) const char *notify_msg
= NULL
;
117 _cleanup_(manager_freep
) Manager
*m
= NULL
;
118 _cleanup_free_
char *swap
= NULL
;
119 unsigned long long s
= 0;
125 r
= parse_argv(argc
, argv
);
133 /* Do some basic requirement checks for running systemd-oomd. It's not exhaustive as some of the other
134 * requirements do not have a reliable means to check for in code. */
136 int n
= sd_listen_fds(0);
138 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Received too many file descriptors");
140 int fd
= n
== 1 ? SD_LISTEN_FDS_START
: -1;
142 /* SwapTotal is always available in /proc/meminfo and defaults to 0, even on swap-disabled kernels. */
143 r
= get_proc_field("/proc/meminfo", "SwapTotal", WHITESPACE
, &swap
);
145 return log_error_errno(r
, "Failed to get SwapTotal from /proc/meminfo: %m");
147 r
= safe_atollu(swap
, &s
);
149 log_warning("No swap; memory pressure usage will be degraded");
151 if (!is_pressure_supported())
152 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Pressure Stall Information (PSI) is not supported");
154 r
= cg_all_unified();
156 return log_error_errno(r
, "Failed to determine whether the unified cgroups hierarchy is used: %m");
158 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Requires the unified cgroups hierarchy");
160 r
= cg_mask_supported(&mask
);
162 return log_error_errno(r
, "Failed to get supported cgroup controllers: %m");
164 if (!FLAGS_SET(mask
, CGROUP_MASK_MEMORY
))
165 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Requires the cgroup memory controller.");
167 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGTERM
, SIGINT
, -1) >= 0);
169 if (arg_mem_pressure_usec
> 0 && arg_mem_pressure_usec
< 1 * USEC_PER_SEC
)
170 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "DefaultMemoryPressureDurationSec= must be 0 or at least 1s");
174 return log_error_errno(r
, "Failed to create manager: %m");
179 arg_swap_used_limit_permyriad
,
180 arg_mem_pressure_limit_permyriad
,
181 arg_mem_pressure_usec
,
184 return log_error_errno(r
, "Failed to start up daemon: %m");
186 notify_msg
= notify_start(NOTIFY_READY
, NOTIFY_STOPPING
);
188 log_debug("systemd-oomd started%s.", arg_dry_run
? " in dry run mode" : "");
190 r
= sd_event_loop(m
->event
);
192 return log_error_errno(r
, "Event loop failed: %m");
197 DEFINE_MAIN_FUNCTION(run
);