sd-login: rework error handling

Makre sure we always return sensible errors for the various, following
the same rules, and document them in a comment in sd-login.c. Also,
update all relevant man pages accordingly.
This commit is contained in:
Lennart Poettering 2015-09-04 09:05:52 +02:00
parent 9da4cb2be2
commit 707b66c663
9 changed files with 325 additions and 103 deletions

View File

@ -115,6 +115,29 @@
errno-style error code.</para>
</refsect1>
<refsect1>
<title>Errors</title>
<para>Returned errors may indicate the following problems:</para>
<variablelist>
<varlistentry>
<term><constant>-EINVAL</constant></term>
<listitem><para>An input parameter was invalid (out of range,
or NULL, where that's not accepted).</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENOMEM</constant></term>
<listitem><para>Memory allocation failed.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Notes</title>

View File

@ -161,20 +161,20 @@
is no timeout to wait for this will fill in <constant>(uint64_t)
-1</constant> instead. Note that <function>poll()</function> takes
a relative timeout in milliseconds rather than an absolute timeout
in microseconds. To convert the absolute 'us' timeout into
in microseconds. To convert the absolute 'µs' timeout into
relative 'ms', use code like the following:</para>
<programlisting>uint64_t t;
int msec;
sd_login_monitor_get_timeout(m, &amp;t);
if (t == (uint64_t) -1)
msec = -1;
msec = -1;
else {
struct timespec ts;
uint64_t n;
clock_getttime(CLOCK_MONOTONIC, &amp;ts);
n = (uint64_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
msec = t > n ? (int) ((t - n + 999) / 1000) : 0;
struct timespec ts;
uint64_t n;
clock_getttime(CLOCK_MONOTONIC, &amp;ts);
n = (uint64_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
msec = t > n ? (int) ((t - n + 999) / 1000) : 0;
}</programlisting>
<para>The code above does not do any error checking for brevity's
@ -203,6 +203,29 @@ else {
always returns <constant>NULL</constant>.</para>
</refsect1>
<refsect1>
<title>Errors</title>
<para>Returned errors may indicate the following problems:</para>
<variablelist>
<varlistentry>
<term><constant>-EINVAL</constant></term>
<listitem><para>An input parameter was invalid (out of range,
or NULL, where that's not accepted). The specified category to
watch is not known.</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENOMEM</constant></term>
<listitem><para>Memory allocation failed.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Notes</title>

View File

@ -56,7 +56,7 @@
<funcprototype>
<funcdef>int <function>sd_machine_get_class</function></funcdef>
<paramdef>const char* <parameter>machine</parameter></paramdef>
<paramdef>char *<parameter>class</parameter></paramdef>
<paramdef>char **<parameter>class</parameter></paramdef>
</funcprototype>
<funcprototype>
@ -98,6 +98,35 @@
code.</para>
</refsect1>
<refsect1>
<title>Errors</title>
<para>Returned errors may indicate the following problems:</para>
<variablelist>
<varlistentry>
<term><constant>-ENXIO</constant></term>
<listitem><para>The specified machine does not exist or is currently not running.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>-EINVAL</constant></term>
<listitem><para>An input parameter was invalid (out of range,
or NULL, where that's not accepted).</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENOMEM</constant></term>
<listitem><para>Memory allocation failed.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Notes</title>

View File

@ -1,4 +1,4 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
@ -163,7 +163,7 @@
processes, user processes that are shared between multiple
sessions of the same user, or kernel threads). For processes not
being part of a login session this function will fail with
-ENXIO. The returned string needs to be freed with the libc
-ENODATA. The returned string needs to be freed with the libc
<citerefentry
project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
call after use.</para>
@ -175,9 +175,9 @@
paths. Note that not all processes are part of a system
unit/service (e.g. user processes, or kernel threads). For
processes not being part of a systemd system unit this function
will fail with -ENXIO (More specifically: this call will not work
for kernel threads.) The returned string needs to be freed with
the libc <citerefentry
will fail with -ENODATA (More specifically: this call will not
work for kernel threads.) The returned string needs to be freed
with the libc <citerefentry
project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
call after use.</para>
@ -194,7 +194,7 @@
multiple login sessions of the same user, where
<function>sd_pid_get_session()</function> will fail. For processes
not being part of a login session and not being a shared process
of a user this function will fail with -ENXIO.</para>
of a user this function will fail with -ENODATA.</para>
<para><function>sd_pid_get_machine_name()</function> may be used
to determine the name of the VM or container is a member of. The
@ -203,7 +203,7 @@
<citerefentry
project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
call after use. For processes not part of a VM or containers this
function fails with -ENXIO.</para>
function fails with -ENODATA.</para>
<para><function>sd_pid_get_slice()</function> may be used to
determine the slice unit the process is a member of. See
@ -251,7 +251,22 @@
<variablelist>
<varlistentry>
<term><constant>-ENXIO</constant></term>
<term><constant>-ESRCH</constant></term>
<listitem><para>The specified PID does not refer to a running
process.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>-BADF</constant></term>
<listitem><para>The specified socket file descriptor was
invalid.</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENODATA</constant></term>
<listitem><para>Given field is not specified for the described
process or peer.</para>
@ -259,11 +274,10 @@
</varlistentry>
<varlistentry>
<term><constant>-ESRCH</constant></term>
<term><constant>-EINVAL</constant></term>
<listitem><para>The specified PID does not refer to a running
process.</para>
</listitem>
<listitem><para>An input parameter was invalid (out of range,
or NULL, where that's not accepted).</para></listitem>
</varlistentry>
<varlistentry>

View File

@ -148,6 +148,43 @@
errno-style error code.</para>
</refsect1>
<refsect1>
<title>Errors</title>
<para>Returned errors may indicate the following problems:</para>
<variablelist>
<varlistentry>
<term><constant>-ENODATA</constant></term>
<listitem><para>Given field is not specified for the described
seat.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENXIO</constant></term>
<listitem><para>The specified seat is unknown.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>-EINVAL</constant></term>
<listitem><para>An input parameter was invalid (out of range,
or NULL, where that's not accepted).</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENOMEM</constant></term>
<listitem><para>Memory allocation failed.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Notes</title>

View File

@ -289,6 +289,43 @@
negative errno-style error code.</para>
</refsect1>
<refsect1>
<title>Errors</title>
<para>Returned errors may indicate the following problems:</para>
<variablelist>
<varlistentry>
<term><constant>-ENXIO</constant></term>
<listitem><para>The specified session does not exist.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENODATA</constant></term>
<listitem><para>Given field is not specified for the described
session.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>-EINVAL</constant></term>
<listitem><para>An input parameter was invalid (out of range,
or NULL, where that's not accepted).</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENOMEM</constant></term>
<listitem><para>Memory allocation failed.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Notes</title>

View File

@ -169,6 +169,45 @@
errno-style error code.</para>
</refsect1>
<refsect1>
<title>Errors</title>
<para>Returned errors may indicate the following problems:</para>
<variablelist>
<varlistentry>
<term><constant>-ENODATA</constant></term>
<listitem><para>Given field is not specified for the described
user.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENXIO</constant></term>
<listitem><para>The specified seat is unknown.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><constant>-EINVAL</constant></term>
<listitem><para>An input parameter was invalid (out of range,
or NULL, where that's not accepted). This is also returned if
the passed user ID is 0xFFFF or 0xFFFFFFFF, which are
undefined on Linux.</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENOMEM</constant></term>
<listitem><para>Memory allocation failed.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Notes</title>

View File

@ -35,6 +35,16 @@
#include "hostname-util.h"
#include "sd-login.h"
/* Error codes:
*
* invalid input parameters -EINVAL
* invalid fd -EBADF
* process does not exist -ESRCH
* cgroup does not exist -ENOENT
* machine, session does not exist -ENXIO
* requested metadata on object is missing -ENODATA
*/
_public_ int sd_pid_get_session(pid_t pid, char **session) {
assert_return(pid >= 0, -EINVAL);
@ -190,6 +200,8 @@ _public_ int sd_peer_get_user_slice(int fd, char **slice) {
}
static int file_of_uid(uid_t uid, char **p) {
assert_return(uid_is_valid(uid), -EINVAL);
assert(p);
if (asprintf(p, "/run/systemd/users/" UID_FMT, uid) < 0)
@ -203,7 +215,6 @@ _public_ int sd_uid_get_state(uid_t uid, char**state) {
char *s = NULL;
int r;
assert_return(uid_is_valid(uid), -EINVAL);
assert_return(state, -EINVAL);
r = file_of_uid(uid, &p);
@ -217,11 +228,15 @@ _public_ int sd_uid_get_state(uid_t uid, char**state) {
if (!s)
return -ENOMEM;
} else if (r < 0) {
}
if (r < 0) {
free(s);
return r;
} else if (!s)
}
if (isempty(s)) {
free(s);
return -EIO;
}
*state = s;
return 0;
@ -231,7 +246,6 @@ _public_ int sd_uid_get_display(uid_t uid, char **session) {
_cleanup_free_ char *p = NULL, *s = NULL;
int r;
assert_return(uid_is_valid(uid), -EINVAL);
assert_return(session, -EINVAL);
r = file_of_uid(uid, &p);
@ -240,12 +254,11 @@ _public_ int sd_uid_get_display(uid_t uid, char **session) {
r = parse_env_file(p, NEWLINE, "DISPLAY", &s, NULL);
if (r == -ENOENT)
return -ENXIO;
return -ENODATA;
if (r < 0)
return r;
if (isempty(s))
return -ENXIO;
return -ENODATA;
*session = s;
s = NULL;
@ -253,6 +266,35 @@ _public_ int sd_uid_get_display(uid_t uid, char **session) {
return 0;
}
static int file_of_seat(const char *seat, char **_p) {
char *p;
int r;
assert(_p);
if (seat) {
if (!filename_is_valid(seat))
return -EINVAL;
p = strappend("/run/systemd/seats/", seat);
} else {
_cleanup_free_ char *buf = NULL;
r = sd_session_get_seat(NULL, &buf);
if (r < 0)
return r;
p = strappend("/run/systemd/seats/", buf);
}
if (!p)
return -ENOMEM;
*_p = p;
p = NULL;
return 0;
}
_public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
_cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
size_t l;
@ -260,29 +302,27 @@ _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat)
const char *word, *variable, *state;
assert_return(uid_is_valid(uid), -EINVAL);
assert_return(seat, -EINVAL);
variable = require_active ? "ACTIVE_UID" : "UIDS";
p = strappend("/run/systemd/seats/", seat);
if (!p)
return -ENOMEM;
r = parse_env_file(p, NEWLINE, variable, &s, NULL);
r = file_of_seat(seat, &p);
if (r < 0)
return r;
if (!s)
return -EIO;
variable = require_active ? "ACTIVE_UID" : "UIDS";
r = parse_env_file(p, NEWLINE, variable, &s, NULL);
if (r == -ENOENT)
return 0;
if (r < 0)
return r;
if (isempty(s))
return 0;
if (asprintf(&t, UID_FMT, uid) < 0)
return -ENOMEM;
FOREACH_WORD(word, l, s, state) {
FOREACH_WORD(word, l, s, state)
if (strneq(t, word, l))
return 1;
}
return 0;
}
@ -292,33 +332,22 @@ static int uid_get_array(uid_t uid, const char *variable, char ***array) {
char **a;
int r;
assert_return(uid_is_valid(uid), -EINVAL);
assert(variable);
r = file_of_uid(uid, &p);
if (r < 0)
return r;
r = parse_env_file(p, NEWLINE,
variable, &s,
NULL);
if (r < 0) {
if (r == -ENOENT) {
if (array)
*array = NULL;
return 0;
}
return r;
}
if (!s) {
r = parse_env_file(p, NEWLINE, variable, &s, NULL);
if (r == -ENOENT || (r >= 0 && isempty(s))) {
if (array)
*array = NULL;
return 0;
}
if (r < 0)
return r;
a = strv_split(s, " ");
if (!a)
return -ENOMEM;
@ -380,37 +409,39 @@ static int file_of_session(const char *session, char **_p) {
}
_public_ int sd_session_is_active(const char *session) {
int r;
_cleanup_free_ char *p = NULL, *s = NULL;
int r;
r = file_of_session(session, &p);
if (r < 0)
return r;
r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
if (r == -ENOENT)
return -ENXIO;
if (r < 0)
return r;
if (!s)
if (isempty(s))
return -EIO;
return parse_boolean(s);
}
_public_ int sd_session_is_remote(const char *session) {
int r;
_cleanup_free_ char *p = NULL, *s = NULL;
int r;
r = file_of_session(session, &p);
if (r < 0)
return r;
r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
if (r == -ENOENT)
return -ENXIO;
if (r < 0)
return r;
if (!s)
return -EIO;
if (isempty(s))
return -ENODATA;
return parse_boolean(s);
}
@ -426,9 +457,11 @@ _public_ int sd_session_get_state(const char *session, char **state) {
return r;
r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
if (r == -ENOENT)
return -ENXIO;
if (r < 0)
return r;
else if (!s)
if (isempty(s))
return -EIO;
*state = s;
@ -448,10 +481,11 @@ _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
return r;
r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
if (r == -ENOENT)
return -ENXIO;
if (r < 0)
return r;
if (!s)
if (isempty(s))
return -EIO;
return parse_uid(s, uid);
@ -462,17 +496,19 @@ static int session_get_string(const char *session, const char *field, char **val
int r;
assert_return(value, -EINVAL);
assert(field);
r = file_of_session(session, &p);
if (r < 0)
return r;
r = parse_env_file(p, NEWLINE, field, &s, NULL);
if (r == -ENOENT)
return -ENXIO;
if (r < 0)
return r;
if (isempty(s))
return -ENXIO;
return -ENODATA;
*value = s;
s = NULL;
@ -492,6 +528,8 @@ _public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
unsigned u;
int r;
assert_return(vtnr, -EINVAL);
r = session_get_string(session, "VTNR", &vtnr_string);
if (r < 0)
return r;
@ -547,32 +585,6 @@ _public_ int sd_session_get_remote_host(const char *session, char **remote_host)
return session_get_string(session, "REMOTE_HOST", remote_host);
}
static int file_of_seat(const char *seat, char **_p) {
char *p;
int r;
assert(_p);
if (seat)
p = strappend("/run/systemd/seats/", seat);
else {
_cleanup_free_ char *buf = NULL;
r = sd_session_get_seat(NULL, &buf);
if (r < 0)
return r;
p = strappend("/run/systemd/seats/", buf);
}
if (!p)
return -ENOMEM;
*_p = p;
p = NULL;
return 0;
}
_public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
_cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
int r;
@ -587,6 +599,8 @@ _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
"ACTIVE", &s,
"ACTIVE_UID", &t,
NULL);
if (r == -ENOENT)
return -ENXIO;
if (r < 0)
return r;
@ -625,7 +639,8 @@ _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **ui
"SESSIONS", &s,
"ACTIVE_SESSIONS", &t,
NULL);
if (r == -ENOENT)
return -ENXIO;
if (r < 0)
return r;
@ -657,7 +672,6 @@ _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **ui
return -ENOMEM;
r = parse_uid(k, b + i);
if (r < 0)
continue;
@ -688,7 +702,7 @@ static int seat_get_can(const char *seat, const char *variable) {
_cleanup_free_ char *p = NULL, *s = NULL;
int r;
assert_return(variable, -EINVAL);
assert(variable);
r = file_of_seat(seat, &p);
if (r < 0)
@ -697,10 +711,12 @@ static int seat_get_can(const char *seat, const char *variable) {
r = parse_env_file(p, NEWLINE,
variable, &s,
NULL);
if (r == -ENOENT)
return -ENXIO;
if (r < 0)
return r;
if (!s)
return 0;
if (isempty(s))
return -ENODATA;
return parse_boolean(s);
}
@ -824,6 +840,8 @@ _public_ int sd_machine_get_class(const char *machine, char **class) {
p = strjoina("/run/systemd/machines/", machine);
r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
if (r == -ENOENT)
return -ENXIO;
if (r < 0)
return r;
if (!c)
@ -847,6 +865,8 @@ _public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
p = strjoina("/run/systemd/machines/", machine);
r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL);
if (r == -ENOENT)
return -ENXIO;
if (r < 0)
return r;
if (!netif) {

View File

@ -52,7 +52,7 @@ static void test_login(void) {
display_session = NULL;
r = sd_uid_get_display(u2, &display_session);
assert_se(r >= 0 || r == -ENXIO);
assert_se(r >= 0 || r == -ENODATA);
printf("user's display session = %s\n", strna(display_session));
free(display_session);
@ -108,19 +108,19 @@ static void test_login(void) {
display = NULL;
r = sd_session_get_display(session, &display);
assert_se(r >= 0 || r == -ENXIO);
assert_se(r >= 0 || r == -ENODATA);
printf("display = %s\n", strna(display));
free(display);
remote_user = NULL;
r = sd_session_get_remote_user(session, &remote_user);
assert_se(r >= 0 || r == -ENXIO);
assert_se(r >= 0 || r == -ENODATA);
printf("remote_user = %s\n", strna(remote_user));
free(remote_user);
remote_host = NULL;
r = sd_session_get_remote_host(session, &remote_host);
assert_se(r >= 0 || r == -ENXIO);
assert_se(r >= 0 || r == -ENODATA);
printf("remote_host = %s\n", strna(remote_host));
free(remote_host);