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_standard_file_with_dropins(
37 config_item_table_lookup
, items
,
39 /* userdata= */ NULL
);
42 static int help(void) {
43 _cleanup_free_
char *link
= NULL
;
46 r
= terminal_urlify_man("systemd-oomd", "8", &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();
112 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
113 "This program takes no arguments.");
118 static int run(int argc
, char *argv
[]) {
119 _unused_
_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;
128 r
= parse_argv(argc
, argv
);
136 /* Do some basic requirement checks for running systemd-oomd. It's not exhaustive as some of the other
137 * requirements do not have a reliable means to check for in code. */
139 int n
= sd_listen_fds(0);
141 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Received too many file descriptors");
143 int fd
= n
== 1 ? SD_LISTEN_FDS_START
: -1;
145 /* SwapTotal is always available in /proc/meminfo and defaults to 0, even on swap-disabled kernels. */
146 r
= get_proc_field("/proc/meminfo", "SwapTotal", WHITESPACE
, &swap
);
148 return log_error_errno(r
, "Failed to get SwapTotal from /proc/meminfo: %m");
150 r
= safe_atollu(swap
, &s
);
152 log_warning("No swap; memory pressure usage will be degraded");
154 if (!is_pressure_supported())
155 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Pressure Stall Information (PSI) is not supported");
157 r
= cg_all_unified();
159 return log_error_errno(r
, "Failed to determine whether the unified cgroups hierarchy is used: %m");
161 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Requires the unified cgroups hierarchy");
163 r
= cg_mask_supported(&mask
);
165 return log_error_errno(r
, "Failed to get supported cgroup controllers: %m");
167 if (!FLAGS_SET(mask
, CGROUP_MASK_MEMORY
))
168 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Requires the cgroup memory controller.");
170 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGTERM
, SIGINT
) >= 0);
172 if (arg_mem_pressure_usec
> 0 && arg_mem_pressure_usec
< 1 * USEC_PER_SEC
)
173 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "DefaultMemoryPressureDurationSec= must be 0 or at least 1s");
177 return log_error_errno(r
, "Failed to create manager: %m");
182 arg_swap_used_limit_permyriad
,
183 arg_mem_pressure_limit_permyriad
,
184 arg_mem_pressure_usec
,
187 return log_error_errno(r
, "Failed to start up daemon: %m");
189 notify_msg
= notify_start(NOTIFY_READY
, NOTIFY_STOPPING
);
191 log_debug("systemd-oomd started%s.", arg_dry_run
? " in dry run mode" : "");
193 r
= sd_event_loop(m
->event
);
195 return log_error_errno(r
, "Event loop failed: %m");
200 DEFINE_MAIN_FUNCTION(run
);