]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/oom/oomd.c
Merge pull request #18701 from bugaevc/mdns-unicast
[thirdparty/systemd.git] / src / oom / oomd.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
9de5e321
AZ
2
3#include <getopt.h>
4
c9a00f5a
ZJS
5#include "bus-log-control-api.h"
6#include "bus-object.h"
9de5e321
AZ
7#include "cgroup-util.h"
8#include "conf-parser.h"
9#include "daemon-util.h"
10#include "log.h"
11#include "main-func.h"
12#include "oomd-manager.h"
c9a00f5a 13#include "oomd-manager-bus.h"
9de5e321
AZ
14#include "parse-util.h"
15#include "pretty-print.c"
16#include "psi-util.h"
17#include "signal-util.h"
18
19static bool arg_dry_run = false;
d06e7fb5 20static int arg_swap_used_limit_permyriad = -1;
0a9f9344 21static int arg_mem_pressure_limit_permyriad = -1;
c20aa7b1 22static usec_t arg_mem_pressure_usec = 0;
9de5e321
AZ
23
24static int parse_config(void) {
25 static const ConfigTableItem items[] = {
d06e7fb5 26 { "OOM", "SwapUsedLimit", config_parse_permyriad, 0, &arg_swap_used_limit_permyriad },
0a9f9344
AZ
27 { "OOM", "DefaultMemoryPressureLimit", config_parse_permyriad, 0, &arg_mem_pressure_limit_permyriad },
28 { "OOM", "DefaultMemoryPressureDurationSec", config_parse_sec, 0, &arg_mem_pressure_usec },
9de5e321
AZ
29 {}
30 };
31
32 return config_parse_many_nulstr(PKGSYSCONFDIR "/oomd.conf",
33 CONF_PATHS_NULSTR("systemd/oomd.conf.d"),
34 "OOM\0",
35 config_item_table_lookup,
36 items,
37 CONFIG_PARSE_WARN,
38 NULL,
39 NULL);
40}
41
42static int help(void) {
43 _cleanup_free_ char *link = NULL;
44 int r;
45
46 r = terminal_urlify_man("systemd-oomd", "1", &link);
47 if (r < 0)
48 return log_oom();
49
50 printf("%s [OPTIONS...]\n\n"
ddc543be
ZJS
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"
c9a00f5a 55 " --bus-introspect=PATH Write D-Bus XML introspection data\n"
bc556335
DDM
56 "\nSee the %s for details.\n",
57 program_invocation_short_name,
58 link);
9de5e321
AZ
59
60 return 0;
61}
62
63static int parse_argv(int argc, char *argv[]) {
64 enum {
ddc543be 65 ARG_VERSION = 0x100,
9de5e321 66 ARG_DRY_RUN,
c9a00f5a 67 ARG_BUS_INTROSPECT,
9de5e321
AZ
68 };
69
70 static const struct option options[] = {
ddc543be
ZJS
71 { "help", no_argument, NULL, 'h' },
72 { "version", no_argument, NULL, ARG_VERSION },
73 { "dry-run", no_argument, NULL, ARG_DRY_RUN },
c9a00f5a 74 { "bus-introspect", required_argument, NULL, ARG_BUS_INTROSPECT },
9de5e321
AZ
75 {}
76 };
77
78 int c;
79
80 assert(argc >= 0);
81 assert(argv);
82
83 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
84
85 switch (c) {
86
ddc543be
ZJS
87 case 'h':
88 return help();
9de5e321 89
ddc543be
ZJS
90 case ARG_VERSION:
91 return version();
9de5e321 92
ddc543be
ZJS
93 case ARG_DRY_RUN:
94 arg_dry_run = true;
95 break;
9de5e321 96
c9a00f5a
ZJS
97 case ARG_BUS_INTROSPECT:
98 return bus_introspect_implementations(
99 stdout,
100 optarg,
101 BUS_IMPLEMENTATIONS(&manager_object,
102 &log_control_object));
103
ddc543be
ZJS
104 case '?':
105 return -EINVAL;
106
107 default:
108 assert_not_reached("Unknown option code.");
9de5e321
AZ
109 }
110
ddc543be
ZJS
111 if (optind < argc)
112 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
113 "This program takes no arguments.");
114
9de5e321
AZ
115 return 1;
116}
117
118static int run(int argc, char *argv[]) {
119 _cleanup_(notify_on_cleanup) const char *notify_msg = NULL;
120 _cleanup_(manager_freep) Manager *m = NULL;
532855be
AZ
121 _cleanup_free_ char *swap = NULL;
122 unsigned long long s = 0;
9de5e321
AZ
123 int r;
124
d2acb93d 125 log_setup();
9de5e321
AZ
126
127 r = parse_argv(argc, argv);
128 if (r <= 0)
129 return r;
130
131 r = parse_config();
132 if (r < 0)
133 return r;
134
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. */
532855be
AZ
137
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);
140 if (r < 0)
141 return log_error_errno(r, "Failed to get SwapTotal from /proc/meminfo: %m");
142
143 r = safe_atollu(swap, &s);
408a3bbd
AZ
144 if (r < 0 || s == 0)
145 log_warning("Swap is currently not detected; memory pressure usage will be degraded");
9de5e321
AZ
146
147 if (!is_pressure_supported())
148 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Pressure Stall Information (PSI) is not supported");
149
150 r = cg_all_unified();
151 if (r < 0)
152 return log_error_errno(r, "Failed to determine whether the unified cgroups hierarchy is used: %m");
153 if (r == 0)
154 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Requires the unified cgroups hierarchy");
155
156 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
157
a858355e
AZ
158 if (arg_mem_pressure_usec > 0 && arg_mem_pressure_usec < 1 * USEC_PER_SEC)
159 log_error_errno(SYNTHETIC_ERRNO(EINVAL), "DefaultMemoryPressureDurationSec= must be 0 or at least 1s");
160
9de5e321
AZ
161 r = manager_new(&m);
162 if (r < 0)
163 return log_error_errno(r, "Failed to create manager: %m");
164
d06e7fb5
LP
165 r = manager_start(
166 m,
167 arg_dry_run,
168 arg_swap_used_limit_permyriad,
169 arg_mem_pressure_limit_permyriad,
170 arg_mem_pressure_usec);
9de5e321
AZ
171 if (r < 0)
172 return log_error_errno(r, "Failed to start up daemon: %m");
173
174 notify_msg = notify_start(NOTIFY_READY, NOTIFY_STOPPING);
175
a19c1a4b 176 log_debug("systemd-oomd started%s.", arg_dry_run ? " in dry run mode" : "");
9de5e321
AZ
177
178 r = sd_event_loop(m->event);
179 if (r < 0)
180 return log_error_errno(r, "Event loop failed: %m");
181
182 return 0;
183}
184
185DEFINE_MAIN_FUNCTION(run);