Merge pull request #6841 from poettering/doc-exit-codes

document exit codes
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2017-09-15 17:26:35 +02:00 committed by GitHub
commit a52c016265
4 changed files with 348 additions and 17 deletions

View file

@ -2197,6 +2197,316 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
</variablelist>
</refsect1>
<refsect1>
<title>Process exit codes</title>
<para>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 <citerefentry
project='man-pages'><refentrytitle>fork</refentrytitle><manvolnum>2</manvolnum></citerefentry> system call, but
before the matching <citerefentry
project='man-pages'><refentrytitle>execve</refentrytitle><manvolnum>2</manvolnum></citerefentry> 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.</para>
<para>The following basic service exit codes are defined by the C library.</para>
<table>
<title>Basic C library exit codes</title>
<tgroup cols='3'>
<thead>
<row>
<entry>Exit Code</entry>
<entry>Symbolic Name</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>0</entry>
<entry><constant>EXIT_SUCCESS</constant></entry>
<entry>Generic success code.</entry>
</row>
<row>
<entry>1</entry>
<entry><constant>EXIT_FAILURE</constant></entry>
<entry>Generic failure or unspecified error.</entry>
</row>
</tbody>
</tgroup>
</table>
<para>The following service exit codes are defined by the <ulink
url="https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html">LSB specification
</ulink>.
</para>
<table>
<title>LSB service exit codes</title>
<tgroup cols='3'>
<thead>
<row>
<entry>Exit Code</entry>
<entry>Symbolic Name</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>2</entry>
<entry><constant>EXIT_INVALIDARGUMENT</constant></entry>
<entry>Invalid or excess arguments.</entry>
</row>
<row>
<entry>3</entry>
<entry><constant>EXIT_NOTIMPLEMENTED</constant></entry>
<entry>Unimplemented feature.</entry>
</row>
<row>
<entry>4</entry>
<entry><constant>EXIT_NOPERMISSION</constant></entry>
<entry>The user has insufficient privileges.</entry>
</row>
<row>
<entry>5</entry>
<entry><constant>EXIT_NOTINSTALLED</constant></entry>
<entry>The program is not installed.</entry>
</row>
<row>
<entry>6</entry>
<entry><constant>EXIT_NOTCONFIGURED</constant></entry>
<entry>The program is not configured.</entry>
</row>
<row>
<entry>7</entry>
<entry><constant>EXIT_NOTRUNNING</constant></entry>
<entry>The program is not running.</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
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:
</para>
<table>
<title>systemd-specific exit codes</title>
<tgroup cols='3'>
<thead>
<row>
<entry>Exit Code</entry>
<entry>Symbolic Name</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>200</entry>
<entry><constant>EXIT_CHDIR</constant></entry>
<entry>Changing to the requested working directory failed. See <varname>WorkingDirectory=</varname> above.</entry>
</row>
<row>
<entry>201</entry>
<entry><constant>EXIT_NICE</constant></entry>
<entry>Failed to set up process scheduling priority (nice level). See <varname>Nice=</varname> above.</entry>
</row>
<row>
<entry>202</entry>
<entry><constant>EXIT_FDS</constant></entry>
<entry>Failed to close unwanted file descriptors, or to adjust passed file descriptors.</entry>
</row>
<row>
<entry>203</entry>
<entry><constant>EXIT_EXEC</constant></entry>
<entry>The actual process execution failed (specifically, the <citerefentry project='man-pages'><refentrytitle>execve</refentrytitle><manvolnum>2</manvolnum></citerefentry> system call). Most likely this is caused by a missing or non-accessible executable file.</entry>
</row>
<row>
<entry>204</entry>
<entry><constant>EXIT_MEMORY</constant></entry>
<entry>Failed to perform an action due to memory shortage.</entry>
</row>
<row>
<entry>205</entry>
<entry><constant>EXIT_LIMITS</constant></entry>
<entry>Failed to adjust resoure limits. See <varname>LimitCPU=</varname> and related settings above.</entry>
</row>
<row>
<entry>206</entry>
<entry><constant>EXIT_OOM_ADJUST</constant></entry>
<entry>Failed to adjust the OOM setting. See <varname>OOMScoreAdjust=</varname> above.</entry>
</row>
<row>
<entry>207</entry>
<entry><constant>EXIT_SIGNAL_MASK</constant></entry>
<entry>Failed to set process signal mask.</entry>
</row>
<row>
<entry>208</entry>
<entry><constant>EXIT_STDIN</constant></entry>
<entry>Failed to set up standard input. See <varname>StandardInput=</varname> above.</entry>
</row>
<row>
<entry>209</entry>
<entry><constant>EXIT_STDOUT</constant></entry>
<entry>Failed to set up standard output. See <varname>StandardOutput=</varname> above.</entry>
</row>
<row>
<entry>210</entry>
<entry><constant>EXIT_CHROOT</constant></entry>
<entry>Failed to change root directory (<citerefentry project='man-pages'><refentrytitle>chroot</refentrytitle><manvolnum>2</manvolnum></citerefentry>). See <varname>RootDirectory=</varname>/<varname>RootImage=</varname> above.</entry>
</row>
<row>
<entry>211</entry>
<entry><constant>EXIT_IOPRIO</constant></entry>
<entry>Failed to set up IO scheduling priority. See <varname>IOSchedulingClass=</varname>/<varname>IOSchedulingPriority=</varname> above.</entry>
</row>
<row>
<entry>212</entry>
<entry><constant>EXIT_TIMERSLACK</constant></entry>
<entry>Failed to set up timer slack. See <varname>TimerSlackNSec=</varname> above.</entry>
</row>
<row>
<entry>213</entry>
<entry><constant>EXIT_SECUREBITS</constant></entry>
<entry>Failed to set process secure bits. See <varname>SecureBits=</varname> above.</entry>
</row>
<row>
<entry>214</entry>
<entry><constant>EXIT_SETSCHEDULER</constant></entry>
<entry>Failed to set up CPU scheduling. See <varname>CPUSchedulingPolicy=</varname>/<varname>CPUSchedulingPriority=</varname> above.</entry>
</row>
<row>
<entry>215</entry>
<entry><constant>EXIT_CPUAFFINITY</constant></entry>
<entry>Failed to set up CPU affinity. See <varname>CPUAffinity=</varname> above.</entry>
</row>
<row>
<entry>216</entry>
<entry><constant>EXIT_GROUP</constant></entry>
<entry>Failed to determine or change group credentials. See <varname>Group=</varname>/<varname>SupplementaryGroups=</varname> above.</entry>
</row>
<row>
<entry>217</entry>
<entry><constant>EXIT_USER</constant></entry>
<entry>Failed to determine or change user credentials, or to set up user namespacing. See <varname>User=</varname>/<varname>PrivateUsers=</varname> above.</entry>
</row>
<row>
<entry>218</entry>
<entry><constant>EXIT_CAPABILITIES</constant></entry>
<entry>Failed to drop capabilities, or apply ambient capabilities. See <varname>CapabilityBoundingSet=</varname>/<varname>AmbientCapabilities=</varname> above.</entry>
</row>
<row>
<entry>219</entry>
<entry><constant>EXIT_CGROUP</constant></entry>
<entry>Setting up the service control group failed.</entry>
</row>
<row>
<entry>220</entry>
<entry><constant>EXIT_SETSID</constant></entry>
<entry>Failed to create new process session.</entry>
</row>
<row>
<entry>221</entry>
<entry><constant>EXIT_CONFIRM</constant></entry>
<entry>Execution has been cancelled by the user. See the <varname>systemd.confirm_spawn=</varname> kernel command line setting on <citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry> for details.</entry>
</row>
<row>
<entry>222</entry>
<entry><constant>EXIT_STDERR</constant></entry>
<entry>Failed to set up standard error output. See <varname>StandardError=</varname> above.</entry>
</row>
<row>
<entry>224</entry>
<entry><constant>EXIT_PAM</constant></entry>
<entry>Failed to set up PAM session. See <varname>PAMName=</varname> above.</entry>
</row>
<row>
<entry>225</entry>
<entry><constant>EXIT_NETWORK</constant></entry>
<entry>Failed to set up network namespacing. See <varname>PrivateNetwork=</varname> above.</entry>
</row>
<row>
<entry>226</entry>
<entry><constant>EXIT_NAMESPACE</constant></entry>
<entry>Failed to set up mount namespacing. See <varname>ReadOnlyPaths=</varname> and related settings above.</entry>
</row>
<row>
<entry>227</entry>
<entry><constant>EXIT_NO_NEW_PRIVILEGES</constant></entry>
<entry>Failed to disable new priviliges. See <varname>NoNewPrivileges=yes</varname> above.</entry>
</row>
<row>
<entry>228</entry>
<entry><constant>EXIT_SECCOMP</constant></entry>
<entry>Failed to apply system call filters. See <varname>SystemCallFilter=</varname> and related settings above.</entry>
</row>
<row>
<entry>229</entry>
<entry><constant>EXIT_SELINUX_CONTEXT</constant></entry>
<entry>Determining or changing SELinux context failed. See <varname>SELinuxContext=</varname> above.</entry>
</row>
<row>
<entry>230</entry>
<entry><constant>EXIT_PERSONALITY</constant></entry>
<entry>Failed to set up a execution domain (personality). See <varname>Personality=</varname> above.</entry>
</row>
<row>
<entry>231</entry>
<entry><constant>EXIT_APPARMOR_PROFILE</constant></entry>
<entry>Failed to prepare changing AppArmor profile. See <varname>AppArmorProfile=</varname> above.</entry>
</row>
<row>
<entry>232</entry>
<entry><constant>EXIT_ADDRESS_FAMILIES</constant></entry>
<entry>Failed to restrict address families. See <varname>RestrictAddressFamilies=</varname> above.</entry>
</row>
<row>
<entry>233</entry>
<entry><constant>EXIT_RUNTIME_DIRECTORY</constant></entry>
<entry>Setting up runtime directory failed. See <varname>RuntimeDirectory=</varname> and related settings above.</entry>
</row>
<row>
<entry>235</entry>
<entry><constant>EXIT_CHOWN</constant></entry>
<entry>Failed to adjust socket ownership. Used for socket units only.</entry>
</row>
<row>
<entry>236</entry>
<entry><constant>EXIT_SMACK_PROCESS_LABEL</constant></entry>
<entry>Failed to set SMACK label. See <varname>SmackProcessLabel=</varname> above.</entry>
</row>
<row>
<entry>237</entry>
<entry><constant>EXIT_KEYRING</constant></entry>
<entry>Failed to set up kernel keyring.</entry>
</row>
<row>
<entry>238</entry>
<entry><constant>EXIT_STATE_DIRECTORY</constant></entry>
<entry>Failed to set up a the unit's state directory. See <varname>StateDirectory=</varname> above.</entry>
</row>
<row>
<entry>239</entry>
<entry><constant>EXIT_CACHE_DIRECTORY</constant></entry>
<entry>Failed to set up a the unit's cache directory. See <varname>CacheDirectory=</varname> above.</entry>
</row>
<row>
<entry>240</entry>
<entry><constant>EXIT_LOGS_DIRECTORY</constant></entry>
<entry>Failed to set up a the unit's logging directory. See <varname>LogsDirectory=</varname> above.</entry>
</row>
<row>
<entry>241</entry>
<entry><constant>EXIT_CONFIGURATION_DIRECTORY</constant></entry>
<entry>Failed to set up a the unit's configuration directory. See <varname>ConfigurationDirectory=</varname> above.</entry>
</row>
</tbody>
</tgroup>
</table>
</refsect1>
<refsect1>
<title>See Also</title>
<para>

View file

@ -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";

View file

@ -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,

View file

@ -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(
&param);
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