chiark / gitweb /
bus: introduce bus_error_is_dirty() independently of sd_bus_error_is_set()
[elogind.git] / src / libsystemd-bus / bus-error.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <errno.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <stdbool.h>
26 #include <string.h>
27 #include <stdio.h>
28
29 #include "util.h"
30
31 #include "sd-bus.h"
32 #include "bus-error.h"
33
34 bool bus_error_is_dirty(sd_bus_error *e) {
35         if (!e)
36                 return 0;
37
38         return e->name || e->message || e->need_free;
39 }
40
41 void sd_bus_error_free(sd_bus_error *e) {
42         if (!e)
43                 return;
44
45         if (e->need_free) {
46                 free((void*) e->name);
47                 free((void*) e->message);
48         }
49
50         e->name = e->message = NULL;
51         e->need_free = false;
52 }
53
54 int sd_bus_error_set(sd_bus_error *e, const char *name, const char *format, ...) {
55         char *n, *m = NULL;
56         va_list ap;
57         int r;
58
59         if (!e)
60                 return 0;
61         if (bus_error_is_dirty(e))
62                 return -EINVAL;
63         if (!name)
64                 return -EINVAL;
65
66         n = strdup(name);
67         if (!n)
68                 return -ENOMEM;
69
70         if (format) {
71                 va_start(ap, format);
72                 r = vasprintf(&m, format, ap);
73                 va_end(ap);
74
75                 if (r < 0) {
76                         free(n);
77                         return -ENOMEM;
78                 }
79         }
80
81         e->name = n;
82         e->message = m;
83         e->need_free = true;
84
85         return 0;
86 }
87
88 int sd_bus_error_copy(sd_bus_error *dest, const sd_bus_error *e) {
89         if (!dest)
90                 return 0;
91         if (bus_error_is_dirty(dest))
92                 return -EINVAL;
93         if (!sd_bus_error_is_set(e))
94                 return 0;
95
96         if (e->need_free) {
97                 char *x, *y = NULL;
98
99                 x = strdup(e->name);
100                 if (!x)
101                         return -ENOMEM;
102
103                 if (e->message) {
104                         y = strdup(e->message);
105                         if (!y) {
106                                 free(x);
107                                 return -ENOMEM;
108                         }
109                 }
110
111                 dest->name = x;
112                 dest->message = y;
113                 dest->need_free = true;
114         } else
115                 *dest = *e;
116
117         return 0;
118 }
119
120 void sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *message) {
121         if (!e)
122                 return;
123         if (bus_error_is_dirty(e))
124                 return;
125
126         e->name = name;
127         e->message = message;
128         e->need_free = false;
129 }
130
131 int sd_bus_error_is_set(const sd_bus_error *e) {
132         if (!e)
133                 return 0;
134
135         return !!e->name;
136 }
137
138 int sd_bus_error_has_name(const sd_bus_error *e, const char *name) {
139         if (!e)
140                 return 0;
141
142         return streq_ptr(e->name, name);
143 }
144
145 int bus_error_to_errno(const sd_bus_error* e) {
146
147         /* Better replce this with a gperf table */
148
149         if (!e->name)
150                 return -EIO;
151
152         if (streq(e->name, "org.freedesktop.DBus.Error.NoMemory"))
153                 return -ENOMEM;
154
155         if (streq(e->name, "org.freedesktop.DBus.Error.AuthFailed") ||
156             streq(e->name, "org.freedesktop.DBus.Error.AccessDenied"))
157                 return -EPERM;
158
159         return -EIO;
160 }
161
162 int bus_error_from_errno(sd_bus_error *e, int error) {
163         if (!e)
164                 return error;
165
166         if (error == -ENOMEM)
167                 sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.NoMemory", strerror(-error));
168         else if (error == -EPERM || error == EACCES)
169                 sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.AccessDenied", strerror(-error));
170         else
171                 sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.Failed", "Operation failed");
172
173         return error;
174 }