chiark / gitweb /
bus: calculate iovec for messages only when we need it
[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         char *x, *y = NULL;
90
91         if (!dest)
92                 return 0;
93         if (bus_error_is_dirty(dest))
94                 return -EINVAL;
95         if (!sd_bus_error_is_set(e))
96                 return 0;
97
98         x = strdup(e->name);
99         if (!x)
100                 return -ENOMEM;
101
102         if (e->message) {
103                 y = strdup(e->message);
104                 if (!y) {
105                         free(x);
106                         return -ENOMEM;
107                 }
108         }
109
110         dest->name = x;
111         dest->message = y;
112         dest->need_free = true;
113         return 0;
114 }
115
116 void sd_bus_error_set_const(sd_bus_error *e, const char *name, const char *message) {
117         if (!e)
118                 return;
119         if (bus_error_is_dirty(e))
120                 return;
121
122         e->name = name;
123         e->message = message;
124         e->need_free = false;
125 }
126
127 int sd_bus_error_is_set(const sd_bus_error *e) {
128         if (!e)
129                 return 0;
130
131         return !!e->name;
132 }
133
134 int sd_bus_error_has_name(const sd_bus_error *e, const char *name) {
135         if (!e)
136                 return 0;
137
138         return streq_ptr(e->name, name);
139 }
140
141 int bus_error_to_errno(const sd_bus_error* e) {
142
143         /* Better replce this with a gperf table */
144
145         if (!e->name)
146                 return -EIO;
147
148         if (streq(e->name, "org.freedesktop.DBus.Error.NoMemory"))
149                 return -ENOMEM;
150
151         if (streq(e->name, "org.freedesktop.DBus.Error.AuthFailed") ||
152             streq(e->name, "org.freedesktop.DBus.Error.AccessDenied"))
153                 return -EPERM;
154
155         return -EIO;
156 }
157
158 int bus_error_from_errno(sd_bus_error *e, int error) {
159         if (!e)
160                 return error;
161
162         if (error == -ENOMEM)
163                 sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.NoMemory", strerror(-error));
164         else if (error == -EPERM || error == -EACCES)
165                 sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.AccessDenied", strerror(-error));
166         else
167                 sd_bus_error_set_const(e, "org.freedesktop.DBus.Error.Failed", "Operation failed");
168
169         return error;
170 }
171
172 const char *bus_error_message(const sd_bus_error *e, int error) {
173         if (e && e->message)
174                 return e->message;
175
176         return strerror(error);
177 }