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"
12 #include "main-func.h"
13 #include "oomd-manager-bus.h"
14 #include "oomd-manager.h"
15 #include "parse-util.h"
16 #include "pretty-print.h"
18 #include "signal-util.h"
20 static bool arg_dry_run
= false;
21 static int arg_swap_used_limit_permyriad
= -1;
22 static int arg_mem_pressure_limit_permyriad
= -1;
23 static usec_t arg_mem_pressure_usec
= 0;
25 static int parse_config(void) {
26 static const ConfigTableItem items
[] = {
27 { "OOM", "SwapUsedLimit", config_parse_permyriad
, 0, &arg_swap_used_limit_permyriad
},
28 { "OOM", "DefaultMemoryPressureLimit", config_parse_permyriad
, 0, &arg_mem_pressure_limit_permyriad
},
29 { "OOM", "DefaultMemoryPressureDurationSec", config_parse_sec
, 0, &arg_mem_pressure_usec
},
33 return config_parse_many_nulstr(PKGSYSCONFDIR
"/oomd.conf",
34 CONF_PATHS_NULSTR("systemd/oomd.conf.d"),
36 config_item_table_lookup
,
43 static int help(void) {
44 _cleanup_free_
char *link
= NULL
;
47 r
= terminal_urlify_man("systemd-oomd", "1", &link
);
51 printf("%s [OPTIONS...]\n\n"
52 "Run the userspace out-of-memory (OOM) killer.\n\n"
53 " -h --help Show this help\n"
54 " --version Show package version\n"
55 " --dry-run Only print destructive actions instead of doing them\n"
56 " --bus-introspect=PATH Write D-Bus XML introspection data\n"
57 "\nSee the %s for details.\n",
58 program_invocation_short_name
,
64 static int parse_argv(int argc
, char *argv
[]) {
71 static const struct option options
[] = {
72 { "help", no_argument
, NULL
, 'h' },
73 { "version", no_argument
, NULL
, ARG_VERSION
},
74 { "dry-run", no_argument
, NULL
, ARG_DRY_RUN
},
75 { "bus-introspect", required_argument
, NULL
, ARG_BUS_INTROSPECT
},
84 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
98 case ARG_BUS_INTROSPECT
:
99 return bus_introspect_implementations(
102 BUS_IMPLEMENTATIONS(&manager_object
,
103 &log_control_object
));
109 assert_not_reached();
113 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
114 "This program takes no arguments.");
119 static int run(int argc
, char *argv
[]) {
120 _unused_
_cleanup_(notify_on_cleanup
) const char *notify_msg
= NULL
;
121 _cleanup_(manager_freep
) Manager
*m
= NULL
;
122 _cleanup_free_
char *swap
= NULL
;
123 unsigned long long s
= 0;
129 r
= parse_argv(argc
, argv
);
137 /* Do some basic requirement checks for running systemd-oomd. It's not exhaustive as some of the other
138 * requirements do not have a reliable means to check for in code. */
140 int n
= sd_listen_fds(0);
142 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Received too many file descriptors");
144 int fd
= n
== 1 ? SD_LISTEN_FDS_START
: -1;
146 /* SwapTotal is always available in /proc/meminfo and defaults to 0, even on swap-disabled kernels. */
147 r
= get_proc_field("/proc/meminfo", "SwapTotal", WHITESPACE
, &swap
);
149 return log_error_errno(r
, "Failed to get SwapTotal from /proc/meminfo: %m");
151 r
= safe_atollu(swap
, &s
);
153 log_warning("Swap is currently not detected; memory pressure usage will be degraded");
155 if (!is_pressure_supported())
156 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Pressure Stall Information (PSI) is not supported");
158 r
= cg_all_unified();
160 return log_error_errno(r
, "Failed to determine whether the unified cgroups hierarchy is used: %m");
162 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Requires the unified cgroups hierarchy");
164 r
= cg_mask_supported(&mask
);
166 return log_error_errno(r
, "Failed to get supported cgroup controllers: %m");
168 if (!FLAGS_SET(mask
, CGROUP_MASK_MEMORY
))
169 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Requires the cgroup memory controller.");
171 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGTERM
, SIGINT
, -1) >= 0);
173 if (arg_mem_pressure_usec
> 0 && arg_mem_pressure_usec
< 1 * USEC_PER_SEC
)
174 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "DefaultMemoryPressureDurationSec= must be 0 or at least 1s");
178 return log_error_errno(r
, "Failed to create manager: %m");
183 arg_swap_used_limit_permyriad
,
184 arg_mem_pressure_limit_permyriad
,
185 arg_mem_pressure_usec
,
188 return log_error_errno(r
, "Failed to start up daemon: %m");
190 notify_msg
= notify_start(NOTIFY_READY
, NOTIFY_STOPPING
);
192 log_debug("systemd-oomd started%s.", arg_dry_run
? " in dry run mode" : "");
194 r
= sd_event_loop(m
->event
);
196 return log_error_errno(r
, "Event loop failed: %m");
201 DEFINE_MAIN_FUNCTION(run
);