~ubuntu-branches/ubuntu/maverick/dbus/maverick-proposed

« back to all changes in this revision

Viewing changes to dbus/sd-daemon.c

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2010-09-27 13:06:32 UTC
  • mfrom: (1.1.23 upstream)
  • Revision ID: james.westby@ubuntu.com-20100927130632-bqs145trvchd2lmf
Tags: 1.4.0-0ubuntu1
* New upstream release
 - Fixes https://bugs.freedesktop.org/show_bug.cgi?id=17754 Race condition in protected_change_timeout
 - Requested by various upstream KDE developers http://lists.kde.org/?t=128514970000004&r=1&w=2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
 
2
 
 
3
/***
 
4
  Copyright 2010 Lennart Poettering
 
5
 
 
6
  Permission is hereby granted, free of charge, to any person
 
7
  obtaining a copy of this software and associated documentation files
 
8
  (the "Software"), to deal in the Software without restriction,
 
9
  including without limitation the rights to use, copy, modify, merge,
 
10
  publish, distribute, sublicense, and/or sell copies of the Software,
 
11
  and to permit persons to whom the Software is furnished to do so,
 
12
  subject to the following conditions:
 
13
 
 
14
  The above copyright notice and this permission notice shall be
 
15
  included in all copies or substantial portions of the Software.
 
16
 
 
17
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
18
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
19
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
20
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 
21
  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 
22
  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 
23
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 
24
  SOFTWARE.
 
25
***/
 
26
 
 
27
#ifndef _GNU_SOURCE
 
28
#define _GNU_SOURCE
 
29
#endif
 
30
 
 
31
#include <sys/types.h>
 
32
#include <sys/stat.h>
 
33
#include <sys/socket.h>
 
34
#include <sys/un.h>
 
35
#include <sys/fcntl.h>
 
36
#include <netinet/in.h>
 
37
#include <stdlib.h>
 
38
#include <errno.h>
 
39
#include <unistd.h>
 
40
#include <string.h>
 
41
#include <stdarg.h>
 
42
#include <stdio.h>
 
43
 
 
44
#include "sd-daemon.h"
 
45
 
 
46
int sd_listen_fds(int unset_environment) {
 
47
 
 
48
#if defined(DISABLE_SYSTEMD) || !defined(__linux__)
 
49
        return 0;
 
50
#else
 
51
        int r, fd;
 
52
        const char *e;
 
53
        char *p = NULL;
 
54
        unsigned long l;
 
55
 
 
56
        if (!(e = getenv("LISTEN_PID"))) {
 
57
                r = 0;
 
58
                goto finish;
 
59
        }
 
60
 
 
61
        errno = 0;
 
62
        l = strtoul(e, &p, 10);
 
63
 
 
64
        if (errno != 0) {
 
65
                r = -errno;
 
66
                goto finish;
 
67
        }
 
68
 
 
69
        if (!p || *p || l <= 0) {
 
70
                r = -EINVAL;
 
71
                goto finish;
 
72
        }
 
73
 
 
74
        /* Is this for us? */
 
75
        if (getpid() != (pid_t) l) {
 
76
                r = 0;
 
77
                goto finish;
 
78
        }
 
79
 
 
80
        if (!(e = getenv("LISTEN_FDS"))) {
 
81
                r = 0;
 
82
                goto finish;
 
83
        }
 
84
 
 
85
        errno = 0;
 
86
        l = strtoul(e, &p, 10);
 
87
 
 
88
        if (errno != 0) {
 
89
                r = -errno;
 
90
                goto finish;
 
91
        }
 
92
 
 
93
        if (!p || *p) {
 
94
                r = -EINVAL;
 
95
                goto finish;
 
96
        }
 
97
 
 
98
        for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) {
 
99
                int flags;
 
100
 
 
101
                if ((flags = fcntl(fd, F_GETFD)) < 0) {
 
102
                        r = -errno;
 
103
                        goto finish;
 
104
                }
 
105
 
 
106
                if (flags & FD_CLOEXEC)
 
107
                        continue;
 
108
 
 
109
                if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
 
110
                        r = -errno;
 
111
                        goto finish;
 
112
                }
 
113
        }
 
114
 
 
115
        r = (int) l;
 
116
 
 
117
finish:
 
118
        if (unset_environment) {
 
119
                unsetenv("LISTEN_PID");
 
120
                unsetenv("LISTEN_FDS");
 
121
        }
 
122
 
 
123
        return r;
 
124
#endif
 
125
}
 
126
 
 
127
int sd_is_fifo(int fd, const char *path) {
 
128
        struct stat st_fd;
 
129
 
 
130
        if (fd < 0)
 
131
                return -EINVAL;
 
132
 
 
133
        memset(&st_fd, 0, sizeof(st_fd));
 
134
        if (fstat(fd, &st_fd) < 0)
 
135
                return -errno;
 
136
 
 
137
        if (!S_ISFIFO(st_fd.st_mode))
 
138
                return 0;
 
139
 
 
140
        if (path) {
 
141
                struct stat st_path;
 
142
 
 
143
                memset(&st_path, 0, sizeof(st_path));
 
144
                if (stat(path, &st_path) < 0) {
 
145
 
 
146
                        if (errno == ENOENT || errno == ENOTDIR)
 
147
                                return 0;
 
148
 
 
149
                        return -errno;
 
150
                }
 
151
 
 
152
                return
 
153
                        st_path.st_dev == st_fd.st_dev &&
 
154
                        st_path.st_ino == st_fd.st_ino;
 
155
        }
 
156
 
 
157
        return 1;
 
158
}
 
159
 
 
160
static int sd_is_socket_internal(int fd, int type, int listening) {
 
161
        struct stat st_fd;
 
162
 
 
163
        if (fd < 0 || type < 0)
 
164
                return -EINVAL;
 
165
 
 
166
        if (fstat(fd, &st_fd) < 0)
 
167
                return -errno;
 
168
 
 
169
        if (!S_ISSOCK(st_fd.st_mode))
 
170
                return 0;
 
171
 
 
172
        if (type != 0) {
 
173
                int other_type = 0;
 
174
                socklen_t l = sizeof(other_type);
 
175
 
 
176
                if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
 
177
                        return -errno;
 
178
 
 
179
                if (l != sizeof(other_type))
 
180
                        return -EINVAL;
 
181
 
 
182
                if (other_type != type)
 
183
                        return 0;
 
184
        }
 
185
 
 
186
        if (listening >= 0) {
 
187
                int accepting = 0;
 
188
                socklen_t l = sizeof(accepting);
 
189
 
 
190
                if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
 
191
                        return -errno;
 
192
 
 
193
                if (l != sizeof(accepting))
 
194
                        return -EINVAL;
 
195
 
 
196
                if (!accepting != !listening)
 
197
                        return 0;
 
198
        }
 
199
 
 
200
        return 1;
 
201
}
 
202
 
 
203
union sockaddr_union {
 
204
        struct sockaddr sa;
 
205
        struct sockaddr_in in4;
 
206
        struct sockaddr_in6 in6;
 
207
        struct sockaddr_un un;
 
208
        struct sockaddr_storage storage;
 
209
};
 
210
 
 
211
int sd_is_socket(int fd, int family, int type, int listening) {
 
212
        int r;
 
213
 
 
214
        if (family < 0)
 
215
                return -EINVAL;
 
216
 
 
217
        if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
 
218
                return r;
 
219
 
 
220
        if (family > 0) {
 
221
                union sockaddr_union sockaddr;
 
222
                socklen_t l;
 
223
 
 
224
                memset(&sockaddr, 0, sizeof(sockaddr));
 
225
                l = sizeof(sockaddr);
 
226
 
 
227
                if (getsockname(fd, &sockaddr.sa, &l) < 0)
 
228
                        return -errno;
 
229
 
 
230
                if (l < sizeof(sa_family_t))
 
231
                        return -EINVAL;
 
232
 
 
233
                return sockaddr.sa.sa_family == family;
 
234
        }
 
235
 
 
236
        return 1;
 
237
}
 
238
 
 
239
int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
 
240
        union sockaddr_union sockaddr;
 
241
        socklen_t l;
 
242
        int r;
 
243
 
 
244
        if (family != 0 && family != AF_INET && family != AF_INET6)
 
245
                return -EINVAL;
 
246
 
 
247
        if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
 
248
                return r;
 
249
 
 
250
        memset(&sockaddr, 0, sizeof(sockaddr));
 
251
        l = sizeof(sockaddr);
 
252
 
 
253
        if (getsockname(fd, &sockaddr.sa, &l) < 0)
 
254
                return -errno;
 
255
 
 
256
        if (l < sizeof(sa_family_t))
 
257
                return -EINVAL;
 
258
 
 
259
        if (sockaddr.sa.sa_family != AF_INET &&
 
260
            sockaddr.sa.sa_family != AF_INET6)
 
261
                return 0;
 
262
 
 
263
        if (family > 0)
 
264
                if (sockaddr.sa.sa_family != family)
 
265
                        return 0;
 
266
 
 
267
        if (port > 0) {
 
268
                if (sockaddr.sa.sa_family == AF_INET) {
 
269
                        if (l < sizeof(struct sockaddr_in))
 
270
                                return -EINVAL;
 
271
 
 
272
                        return htons(port) == sockaddr.in4.sin_port;
 
273
                } else {
 
274
                        if (l < sizeof(struct sockaddr_in6))
 
275
                                return -EINVAL;
 
276
 
 
277
                        return htons(port) == sockaddr.in6.sin6_port;
 
278
                }
 
279
        }
 
280
 
 
281
        return 1;
 
282
}
 
283
 
 
284
int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
 
285
        union sockaddr_union sockaddr;
 
286
        socklen_t l;
 
287
        int r;
 
288
 
 
289
        if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
 
290
                return r;
 
291
 
 
292
        memset(&sockaddr, 0, sizeof(sockaddr));
 
293
        l = sizeof(sockaddr);
 
294
 
 
295
        if (getsockname(fd, &sockaddr.sa, &l) < 0)
 
296
                return -errno;
 
297
 
 
298
        if (l < sizeof(sa_family_t))
 
299
                return -EINVAL;
 
300
 
 
301
        if (sockaddr.sa.sa_family != AF_UNIX)
 
302
                return 0;
 
303
 
 
304
        if (path) {
 
305
                if (length <= 0)
 
306
                        length = strlen(path);
 
307
 
 
308
                if (length <= 0)
 
309
                        /* Unnamed socket */
 
310
                        return l == sizeof(sa_family_t);
 
311
 
 
312
                if (path[0])
 
313
                        /* Normal path socket */
 
314
                        return
 
315
                                (l >= sizeof(sa_family_t) + length + 1) &&
 
316
                                memcmp(path, sockaddr.un.sun_path, length+1) == 0;
 
317
                else
 
318
                        /* Abstract namespace socket */
 
319
                        return
 
320
                                (l == sizeof(sa_family_t) + length) &&
 
321
                                memcmp(path, sockaddr.un.sun_path, length) == 0;
 
322
        }
 
323
 
 
324
        return 1;
 
325
}
 
326
 
 
327
int sd_notify(int unset_environment, const char *state) {
 
328
#if defined(DISABLE_SYSTEMD) || !defined(__linux__) || !defined(SOCK_CLOEXEC)
 
329
        return 0;
 
330
#else
 
331
        int fd = -1, r;
 
332
        struct msghdr msghdr;
 
333
        struct iovec iovec;
 
334
        union sockaddr_union sockaddr;
 
335
        const char *e;
 
336
 
 
337
        if (!state) {
 
338
                r = -EINVAL;
 
339
                goto finish;
 
340
        }
 
341
 
 
342
        if (!(e = getenv("NOTIFY_SOCKET")))
 
343
                return 0;
 
344
 
 
345
        /* Must be an abstract socket, or an absolute path */
 
346
        if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
 
347
                r = -EINVAL;
 
348
                goto finish;
 
349
        }
 
350
 
 
351
        if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) {
 
352
                r = -errno;
 
353
                goto finish;
 
354
        }
 
355
 
 
356
        memset(&sockaddr, 0, sizeof(sockaddr));
 
357
        sockaddr.sa.sa_family = AF_UNIX;
 
358
        strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
 
359
 
 
360
        if (sockaddr.un.sun_path[0] == '@')
 
361
                sockaddr.un.sun_path[0] = 0;
 
362
 
 
363
        memset(&iovec, 0, sizeof(iovec));
 
364
        iovec.iov_base = (char*) state;
 
365
        iovec.iov_len = strlen(state);
 
366
 
 
367
        memset(&msghdr, 0, sizeof(msghdr));
 
368
        msghdr.msg_name = &sockaddr;
 
369
        msghdr.msg_namelen = sizeof(sa_family_t) + strlen(e);
 
370
 
 
371
        if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
 
372
                msghdr.msg_namelen = sizeof(struct sockaddr_un);
 
373
 
 
374
        msghdr.msg_iov = &iovec;
 
375
        msghdr.msg_iovlen = 1;
 
376
 
 
377
        if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
 
378
                r = -errno;
 
379
                goto finish;
 
380
        }
 
381
 
 
382
        r = 1;
 
383
 
 
384
finish:
 
385
        if (unset_environment)
 
386
                unsetenv("NOTIFY_SOCKET");
 
387
 
 
388
        if (fd >= 0)
 
389
                close(fd);
 
390
 
 
391
        return r;
 
392
#endif
 
393
}
 
394
 
 
395
int sd_notifyf(int unset_environment, const char *format, ...) {
 
396
#if defined(DISABLE_SYSTEMD) || !defined(__linux__)
 
397
        return 0;
 
398
#else
 
399
        va_list ap;
 
400
        char *p = NULL;
 
401
        int r;
 
402
 
 
403
        va_start(ap, format);
 
404
        r = vasprintf(&p, format, ap);
 
405
        va_end(ap);
 
406
 
 
407
        if (r < 0 || !p)
 
408
                return -ENOMEM;
 
409
 
 
410
        r = sd_notify(unset_environment, p);
 
411
        free(p);
 
412
 
 
413
        return r;
 
414
#endif
 
415
}
 
416
 
 
417
int sd_booted(void) {
 
418
#if defined(DISABLE_SYSTEMD) || !defined(__linux__)
 
419
        return 0;
 
420
#else
 
421
 
 
422
        struct stat a, b;
 
423
 
 
424
        /* We simply test whether the systemd cgroup hierarchy is
 
425
         * mounted */
 
426
 
 
427
        if (lstat("/sys/fs/cgroup", &a) < 0)
 
428
                return 0;
 
429
 
 
430
        if (lstat("/sys/fs/cgroup/systemd", &b) < 0)
 
431
                return 0;
 
432
 
 
433
        return a.st_dev != b.st_dev;
 
434
#endif
 
435
}