diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 53daff0f64..61e51becc6 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -2197,6 +2197,316 @@ CapabilityBoundingSet=~CAP_B CAP_C
+
+ Process exit codes
+
+ When invoking a unit process the service manager possibly fails to apply the execution parameters configured
+ with the settings above. In that case the already created service process will exit with a non-zero exit code
+ before the configured command line is executed. (Or in other words, the child process possibly exits with these
+ error codes, after having been created by the fork2 system call, but
+ before the matching execve2 system call is
+ called.) Specifically, exit codes defined by the C library, by the LSB specification and by the systemd service
+ manager itself are used.
+
+ The following basic service exit codes are defined by the C library.
+
+
+ Basic C library exit codes
+
+
+
+ Exit Code
+ Symbolic Name
+ Description
+
+
+
+
+ 0
+ EXIT_SUCCESS
+ Generic success code.
+
+
+ 1
+ EXIT_FAILURE
+ Generic failure or unspecified error.
+
+
+
+
+
+ The following service exit codes are defined by the LSB specification
+ .
+
+
+
+ LSB service exit codes
+
+
+
+ Exit Code
+ Symbolic Name
+ Description
+
+
+
+
+ 2
+ EXIT_INVALIDARGUMENT
+ Invalid or excess arguments.
+
+
+ 3
+ EXIT_NOTIMPLEMENTED
+ Unimplemented feature.
+
+
+ 4
+ EXIT_NOPERMISSION
+ The user has insufficient privileges.
+
+
+ 5
+ EXIT_NOTINSTALLED
+ The program is not installed.
+
+
+ 6
+ EXIT_NOTCONFIGURED
+ The program is not configured.
+
+
+ 7
+ EXIT_NOTRUNNING
+ The program is not running.
+
+
+
+
+
+
+ The LSB specification suggests that error codes 200 and above are reserved for implementations. Some of them are
+ used by the service manager to indicate problems during process invocation:
+
+
+ systemd-specific exit codes
+
+
+
+ Exit Code
+ Symbolic Name
+ Description
+
+
+
+
+ 200
+ EXIT_CHDIR
+ Changing to the requested working directory failed. See WorkingDirectory= above.
+
+
+ 201
+ EXIT_NICE
+ Failed to set up process scheduling priority (nice level). See Nice= above.
+
+
+ 202
+ EXIT_FDS
+ Failed to close unwanted file descriptors, or to adjust passed file descriptors.
+
+
+ 203
+ EXIT_EXEC
+ The actual process execution failed (specifically, the execve2 system call). Most likely this is caused by a missing or non-accessible executable file.
+
+
+ 204
+ EXIT_MEMORY
+ Failed to perform an action due to memory shortage.
+
+
+ 205
+ EXIT_LIMITS
+ Failed to adjust resoure limits. See LimitCPU= and related settings above.
+
+
+ 206
+ EXIT_OOM_ADJUST
+ Failed to adjust the OOM setting. See OOMScoreAdjust= above.
+
+
+ 207
+ EXIT_SIGNAL_MASK
+ Failed to set process signal mask.
+
+
+ 208
+ EXIT_STDIN
+ Failed to set up standard input. See StandardInput= above.
+
+
+ 209
+ EXIT_STDOUT
+ Failed to set up standard output. See StandardOutput= above.
+
+
+ 210
+ EXIT_CHROOT
+ Failed to change root directory (chroot2). See RootDirectory=/RootImage= above.
+
+
+ 211
+ EXIT_IOPRIO
+ Failed to set up IO scheduling priority. See IOSchedulingClass=/IOSchedulingPriority= above.
+
+
+ 212
+ EXIT_TIMERSLACK
+ Failed to set up timer slack. See TimerSlackNSec= above.
+
+
+ 213
+ EXIT_SECUREBITS
+ Failed to set process secure bits. See SecureBits= above.
+
+
+ 214
+ EXIT_SETSCHEDULER
+ Failed to set up CPU scheduling. See CPUSchedulingPolicy=/CPUSchedulingPriority= above.
+
+
+ 215
+ EXIT_CPUAFFINITY
+ Failed to set up CPU affinity. See CPUAffinity= above.
+
+
+ 216
+ EXIT_GROUP
+ Failed to determine or change group credentials. See Group=/SupplementaryGroups= above.
+
+
+ 217
+ EXIT_USER
+ Failed to determine or change user credentials, or to set up user namespacing. See User=/PrivateUsers= above.
+
+
+ 218
+ EXIT_CAPABILITIES
+ Failed to drop capabilities, or apply ambient capabilities. See CapabilityBoundingSet=/AmbientCapabilities= above.
+
+
+ 219
+ EXIT_CGROUP
+ Setting up the service control group failed.
+
+
+ 220
+ EXIT_SETSID
+ Failed to create new process session.
+
+
+ 221
+ EXIT_CONFIRM
+ Execution has been cancelled by the user. See the systemd.confirm_spawn= kernel command line setting on kernel-command-line7 for details.
+
+
+ 222
+ EXIT_STDERR
+ Failed to set up standard error output. See StandardError= above.
+
+
+ 224
+ EXIT_PAM
+ Failed to set up PAM session. See PAMName= above.
+
+
+ 225
+ EXIT_NETWORK
+ Failed to set up network namespacing. See PrivateNetwork= above.
+
+
+ 226
+ EXIT_NAMESPACE
+ Failed to set up mount namespacing. See ReadOnlyPaths= and related settings above.
+
+
+ 227
+ EXIT_NO_NEW_PRIVILEGES
+ Failed to disable new priviliges. See NoNewPrivileges=yes above.
+
+
+ 228
+ EXIT_SECCOMP
+ Failed to apply system call filters. See SystemCallFilter= and related settings above.
+
+
+ 229
+ EXIT_SELINUX_CONTEXT
+ Determining or changing SELinux context failed. See SELinuxContext= above.
+
+
+ 230
+ EXIT_PERSONALITY
+ Failed to set up a execution domain (personality). See Personality= above.
+
+
+ 231
+ EXIT_APPARMOR_PROFILE
+ Failed to prepare changing AppArmor profile. See AppArmorProfile= above.
+
+
+ 232
+ EXIT_ADDRESS_FAMILIES
+ Failed to restrict address families. See RestrictAddressFamilies= above.
+
+
+ 233
+ EXIT_RUNTIME_DIRECTORY
+ Setting up runtime directory failed. See RuntimeDirectory= and related settings above.
+
+
+ 235
+ EXIT_CHOWN
+ Failed to adjust socket ownership. Used for socket units only.
+
+
+ 236
+ EXIT_SMACK_PROCESS_LABEL
+ Failed to set SMACK label. See SmackProcessLabel= above.
+
+
+ 237
+ EXIT_KEYRING
+ Failed to set up kernel keyring.
+
+
+ 238
+ EXIT_STATE_DIRECTORY
+ Failed to set up a the unit's state directory. See StateDirectory= above.
+
+
+ 239
+ EXIT_CACHE_DIRECTORY
+ Failed to set up a the unit's cache directory. See CacheDirectory= above.
+
+
+ 240
+ EXIT_LOGS_DIRECTORY
+ Failed to set up a the unit's logging directory. See LogsDirectory= above.
+
+
+ 241
+ EXIT_CONFIGURATION_DIRECTORY
+ Failed to set up a the unit's configuration directory. See ConfigurationDirectory= above.
+
+
+
+
+
+
See Also
diff --git a/src/basic/exit-status.c b/src/basic/exit-status.c
index fba012601d..7cfebbae72 100644
--- a/src/basic/exit-status.c
+++ b/src/basic/exit-status.c
@@ -140,9 +140,6 @@ const char* exit_status_to_string(int status, ExitStatusLevel level) {
case EXIT_RUNTIME_DIRECTORY:
return "RUNTIME_DIRECTORY";
- case EXIT_MAKE_STARTER:
- return "MAKE_STARTER";
-
case EXIT_CHOWN:
return "CHOWN";
diff --git a/src/basic/exit-status.h b/src/basic/exit-status.h
index e2c76f84f8..195b3bc486 100644
--- a/src/basic/exit-status.h
+++ b/src/basic/exit-status.h
@@ -79,7 +79,7 @@ enum {
EXIT_APPARMOR_PROFILE,
EXIT_ADDRESS_FAMILIES,
EXIT_RUNTIME_DIRECTORY,
- EXIT_MAKE_STARTER,
+ _EXIT_RESERVED2, /* used to be used by kdbus, don't reuse */
EXIT_CHOWN,
EXIT_SMACK_PROCESS_LABEL,
EXIT_KEYRING,
diff --git a/src/core/execute.c b/src/core/execute.c
index e2d84feb0d..9e1add3e7f 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -2399,7 +2399,7 @@ static int exec_child(
r = reset_signal_mask();
if (r < 0) {
*exit_status = EXIT_SIGNAL_MASK;
- *error_message = strdup("Failed to reset signal mask");
+ *error_message = strdup("Failed to set process signal mask");
/* If strdup fails, here and below, we will just print the generic error message. */
return r;
}
@@ -2417,13 +2417,14 @@ static int exec_child(
r = close_remaining_fds(params, runtime, dcreds, user_lookup_fd, socket_fd, fds, n_fds);
if (r < 0) {
*exit_status = EXIT_FDS;
- *error_message = strdup("Failed to close remaining fds");
+ *error_message = strdup("Failed to close unwanted file descriptors");
return r;
}
if (!context->same_pgrp)
if (setsid() < 0) {
*exit_status = EXIT_SETSID;
+ *error_message = strdup("Failed to create new process session");
return -errno;
}
@@ -2435,7 +2436,7 @@ static int exec_child(
cmdline = exec_command_line(argv);
if (!cmdline) {
- *exit_status = EXIT_CONFIRM;
+ *exit_status = EXIT_MEMORY;
return -ENOMEM;
}
@@ -2446,7 +2447,7 @@ static int exec_child(
return 0;
}
*exit_status = EXIT_CONFIRM;
- *error_message = strdup("Execution cancelled");
+ *error_message = strdup("Execution cancelled by the user");
return -ECANCELED;
}
}
@@ -2532,21 +2533,21 @@ static int exec_child(
r = setup_input(context, params, socket_fd, named_iofds);
if (r < 0) {
*exit_status = EXIT_STDIN;
- *error_message = strdup("Failed to set up stdin");
+ *error_message = strdup("Failed to set up standard input");
return r;
}
r = setup_output(unit, context, params, STDOUT_FILENO, socket_fd, named_iofds, basename(command->path), uid, gid, &journal_stream_dev, &journal_stream_ino);
if (r < 0) {
*exit_status = EXIT_STDOUT;
- *error_message = strdup("Failed to set up stdout");
+ *error_message = strdup("Failed to set up standard output");
return r;
}
r = setup_output(unit, context, params, STDERR_FILENO, socket_fd, named_iofds, basename(command->path), uid, gid, &journal_stream_dev, &journal_stream_ino);
if (r < 0) {
*exit_status = EXIT_STDERR;
- *error_message = strdup("Failed to set up stderr");
+ *error_message = strdup("Failed to set up standard error output");
return r;
}
@@ -2575,7 +2576,7 @@ static int exec_child(
log_close();
} else if (r < 0) {
*exit_status = EXIT_OOM_ADJUST;
- *error_message = strdup("Failed to write /proc/self/oom_score_adj");
+ *error_message = strdup("Failed to adjust OOM setting");
return -errno;
}
}
@@ -2583,6 +2584,7 @@ static int exec_child(
if (context->nice_set)
if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) {
*exit_status = EXIT_NICE;
+ *error_message = strdup("Failed to set up process scheduling priority (nice level");
return -errno;
}
@@ -2598,6 +2600,7 @@ static int exec_child(
¶m);
if (r < 0) {
*exit_status = EXIT_SETSCHEDULER;
+ *error_message = strdup("Failed to set up CPU scheduling");
return -errno;
}
}
@@ -2605,18 +2608,21 @@ static int exec_child(
if (context->cpuset)
if (sched_setaffinity(0, CPU_ALLOC_SIZE(context->cpuset_ncpus), context->cpuset) < 0) {
*exit_status = EXIT_CPUAFFINITY;
+ *error_message = strdup("Failed to set up CPU affinity");
return -errno;
}
if (context->ioprio_set)
if (ioprio_set(IOPRIO_WHO_PROCESS, 0, context->ioprio) < 0) {
*exit_status = EXIT_IOPRIO;
+ *error_message = strdup("Failed to set up IO scheduling priority");
return -errno;
}
if (context->timer_slack_nsec != NSEC_INFINITY)
if (prctl(PR_SET_TIMERSLACK, context->timer_slack_nsec) < 0) {
*exit_status = EXIT_TIMERSLACK;
+ *error_message = strdup("Failed to set up timer slack");
return -errno;
}
@@ -2624,6 +2630,7 @@ static int exec_child(
r = safe_personality(context->personality);
if (r < 0) {
*exit_status = EXIT_PERSONALITY;
+ *error_message = strdup("Failed to set up execution domain (personality)");
return r;
}
}
@@ -2640,6 +2647,7 @@ static int exec_child(
r = chown_terminal(STDIN_FILENO, uid);
if (r < 0) {
*exit_status = EXIT_STDIN;
+ *error_message = strdup("Failed to change ownership of terminal");
return r;
}
}
@@ -2651,6 +2659,7 @@ static int exec_child(
r = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, 0644, uid, gid);
if (r < 0) {
*exit_status = EXIT_CGROUP;
+ *error_message = strdup("Failed to adjust control group access");
return r;
}
@@ -2658,14 +2667,17 @@ static int exec_child(
r = cg_set_group_access(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, 0755, uid, gid);
if (r < 0) {
*exit_status = EXIT_CGROUP;
+ *error_message = strdup("Failed to adjust control group access");
return r;
}
}
for (dt = 0; dt < _EXEC_DIRECTORY_MAX; dt++) {
r = setup_exec_directory(context, params, uid, gid, dt, exit_status);
- if (r < 0)
+ if (r < 0) {
+ *error_message = strdup("Failed to set up special execution directory");
return r;
+ }
}
r = build_environment(
@@ -2708,6 +2720,7 @@ static int exec_child(
r = setup_keyring(unit, params, uid, gid);
if (r < 0) {
*exit_status = EXIT_KEYRING;
+ *error_message = strdup("Failed to set up kernel keyring");
return r;
}
@@ -2744,6 +2757,7 @@ static int exec_child(
r = setup_pam(context->pam_name, username, uid, gid, context->tty_path, &accum_env, fds, n_fds);
if (r < 0) {
*exit_status = EXIT_PAM;
+ *error_message = strdup("Failed to set up PAM session");
return r;
}
}
@@ -2753,6 +2767,7 @@ static int exec_child(
r = setup_netns(runtime->netns_storage_socket);
if (r < 0) {
*exit_status = EXIT_NETWORK;
+ *error_message = strdup("Failed to set up network namespacing");
return r;
}
}
@@ -2762,19 +2777,23 @@ static int exec_child(
r = apply_mount_namespace(unit, command, context, params, runtime);
if (r < 0) {
*exit_status = EXIT_NAMESPACE;
+ *error_message = strdup("Failed to set up mount namespacing");
return r;
}
}
/* Apply just after mount namespace setup */
r = apply_working_directory(context, params, home, needs_mount_namespace, exit_status);
- if (r < 0)
+ if (r < 0) {
+ *error_message = strdup("Changing to the requested working directory failed");
return r;
+ }
/* Drop groups as early as possbile */
if (needs_setuid) {
r = enforce_groups(context, gid, supplementary_gids, ngids);
if (r < 0) {
+ *error_message = strdup("Changing group credentials failed");
*exit_status = EXIT_GROUP;
return r;
}
@@ -2785,6 +2804,7 @@ static int exec_child(
if (use_selinux && params->selinux_context_net && socket_fd >= 0) {
r = mac_selinux_get_child_mls_label(socket_fd, command->path, context->selinux_context, &mac_selinux_context_net);
if (r < 0) {
+ *error_message = strdup("Failed to determine SELinux context");
*exit_status = EXIT_SELINUX_CONTEXT;
return r;
}
@@ -2794,6 +2814,7 @@ static int exec_child(
if (context->private_users) {
r = setup_private_users(uid, gid);
if (r < 0) {
+ *error_message = strdup("Failed to set up user namespacing");
*exit_status = EXIT_USER;
return r;
}
@@ -2809,6 +2830,7 @@ static int exec_child(
if (r >= 0)
r = flags_fds(fds, n_storage_fds, n_socket_fds, context->non_blocking);
if (r < 0) {
+ *error_message = strdup("Failed to adjust passed file descriptors");
*exit_status = EXIT_FDS;
return r;
}
@@ -2825,6 +2847,7 @@ static int exec_child(
r = setrlimit_closest(i, context->rlimit[i]);
if (r < 0) {
+ *error_message = strdup("Failed to adjust resource limits");
*exit_status = EXIT_LIMITS;
return r;
}
@@ -2833,6 +2856,7 @@ static int exec_child(
/* Set the RTPRIO resource limit to 0, but only if nothing else was explicitly requested. */
if (context->restrict_realtime && !context->rlimit[RLIMIT_RTPRIO]) {
if (setrlimit(RLIMIT_RTPRIO, &RLIMIT_MAKE_CONST(0)) < 0) {
+ *error_message = strdup("Failed to adjust RLIMIT_RTPRIO resource limit");
*exit_status = EXIT_LIMITS;
return -errno;
}
@@ -2915,7 +2939,7 @@ static int exec_child(
r = setexeccon(exec_context);
if (r < 0) {
*exit_status = EXIT_SELINUX_CONTEXT;
- (void) asprintf(error_message, "Failed to set SELinux context to %s", exec_context);
+ (void) asprintf(error_message, "Failed to change SELinux context to %s", exec_context);
return r;
}
}
@@ -2951,7 +2975,7 @@ static int exec_child(
if (prctl(PR_GET_SECUREBITS) != secure_bits)
if (prctl(PR_SET_SECUREBITS, secure_bits) < 0) {
*exit_status = EXIT_SECUREBITS;
- *error_message = strdup("Failed to set secure bits");
+ *error_message = strdup("Failed to set process secure bits");
return -errno;
}
@@ -3031,7 +3055,7 @@ static int exec_child(
r = apply_syscall_filter(unit, context, needs_ambient_hack);
if (r < 0) {
*exit_status = EXIT_SECCOMP;
- *error_message = strdup("Failed to apply syscall filters");
+ *error_message = strdup("Failed to apply system call filters");
return r;
}
#endif