~ubuntu-branches/ubuntu/trusty/systemd/trusty

« back to all changes in this revision

Viewing changes to src/sd-daemon.c

  • Committer: Package Import Robot
  • Author(s): Michael Biebl, Michael Biebl, Michael Stapelberg, Daniel Schaal, Ondrej Balaz
  • Date: 2013-09-12 00:13:11 UTC
  • mfrom: (1.1.11) (9.1.2 experimental)
  • mto: This revision was merged to the branch mainline in revision 53.
  • Revision ID: package-import@ubuntu.com-20130912001311-dz35it34wr2lbday
Tags: 204-3
[ Michael Biebl ]
* Upload to unstable.
* Use /bin/bash in debug-shell.service as Debian doesn't have /sbin/sushell.
* Only import net.ifaces cmdline property for network devices.
* Generate strict dependencies between the binary packages using a
  shlibs.local file and add an explicit versioned dependency on
  libsystemd-login0 to systemd to ensure packages are upgraded in sync.
  Closes: #719444
* Drop obsolete Replaces: libudev0 from udev package.
* Use correct paths for various binaries, like /sbin/quotaon, which are
  installed in / and not /usr in Debian.  Closes: #721347
* Don't install kernel-install(8) man page since we don't install the
  corresponding binary either.  Closes: #722180
* Cherry-pick upstream fixes to make switching runlevels and starting
  reboot via ctrl-alt-del more robust.
* Cherry-pick upstream fix to properly apply ACLs to Journal files.

[ Michael Stapelberg ]
* Make systemctl enable|disable call update-rc.d for SysV init scripts.
  Closes: #709780
* Don't mount /tmp as tmpfs by default and make it possible to enable this
  feature via "systemctl enable tmp.mount".

[ Daniel Schaal ]
* Add bug-script to systemd and udev.  Closes: #711245

[ Ondrej Balaz ]
* Recognize discard option in /etc/crypttab.

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
 
#ifdef __BIONIC__
36
 
#include <linux/fcntl.h>
37
 
#else
38
 
#include <sys/fcntl.h>
39
 
#endif
40
 
#include <netinet/in.h>
41
 
#include <stdlib.h>
42
 
#include <errno.h>
43
 
#include <unistd.h>
44
 
#include <string.h>
45
 
#include <stdarg.h>
46
 
#include <stdio.h>
47
 
#include <stddef.h>
48
 
#include <limits.h>
49
 
 
50
 
#if defined(__linux__)
51
 
#include <mqueue.h>
52
 
#endif
53
 
 
54
 
#include "sd-daemon.h"
55
 
 
56
 
#if (__GNUC__ >= 4)
57
 
#ifdef SD_EXPORT_SYMBOLS
58
 
/* Export symbols */
59
 
#define _sd_export_ __attribute__ ((visibility("default")))
60
 
#else
61
 
/* Don't export the symbols */
62
 
#define _sd_export_ __attribute__ ((visibility("hidden")))
63
 
#endif
64
 
#else
65
 
#define _sd_export_
66
 
#endif
67
 
 
68
 
_sd_export_ int sd_listen_fds(int unset_environment) {
69
 
 
70
 
#if defined(DISABLE_SYSTEMD) || !defined(__linux__)
71
 
        return 0;
72
 
#else
73
 
        int r, fd;
74
 
        const char *e;
75
 
        char *p = NULL;
76
 
        unsigned long l;
77
 
 
78
 
        if (!(e = getenv("LISTEN_PID"))) {
79
 
                r = 0;
80
 
                goto finish;
81
 
        }
82
 
 
83
 
        errno = 0;
84
 
        l = strtoul(e, &p, 10);
85
 
 
86
 
        if (errno != 0) {
87
 
                r = -errno;
88
 
                goto finish;
89
 
        }
90
 
 
91
 
        if (!p || *p || l <= 0) {
92
 
                r = -EINVAL;
93
 
                goto finish;
94
 
        }
95
 
 
96
 
        /* Is this for us? */
97
 
        if (getpid() != (pid_t) l) {
98
 
                r = 0;
99
 
                goto finish;
100
 
        }
101
 
 
102
 
        if (!(e = getenv("LISTEN_FDS"))) {
103
 
                r = 0;
104
 
                goto finish;
105
 
        }
106
 
 
107
 
        errno = 0;
108
 
        l = strtoul(e, &p, 10);
109
 
 
110
 
        if (errno != 0) {
111
 
                r = -errno;
112
 
                goto finish;
113
 
        }
114
 
 
115
 
        if (!p || *p) {
116
 
                r = -EINVAL;
117
 
                goto finish;
118
 
        }
119
 
 
120
 
        for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) {
121
 
                int flags;
122
 
 
123
 
                if ((flags = fcntl(fd, F_GETFD)) < 0) {
124
 
                        r = -errno;
125
 
                        goto finish;
126
 
                }
127
 
 
128
 
                if (flags & FD_CLOEXEC)
129
 
                        continue;
130
 
 
131
 
                if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) {
132
 
                        r = -errno;
133
 
                        goto finish;
134
 
                }
135
 
        }
136
 
 
137
 
        r = (int) l;
138
 
 
139
 
finish:
140
 
        if (unset_environment) {
141
 
                unsetenv("LISTEN_PID");
142
 
                unsetenv("LISTEN_FDS");
143
 
        }
144
 
 
145
 
        return r;
146
 
#endif
147
 
}
148
 
 
149
 
_sd_export_ int sd_is_fifo(int fd, const char *path) {
150
 
        struct stat st_fd;
151
 
 
152
 
        if (fd < 0)
153
 
                return -EINVAL;
154
 
 
155
 
        memset(&st_fd, 0, sizeof(st_fd));
156
 
        if (fstat(fd, &st_fd) < 0)
157
 
                return -errno;
158
 
 
159
 
        if (!S_ISFIFO(st_fd.st_mode))
160
 
                return 0;
161
 
 
162
 
        if (path) {
163
 
                struct stat st_path;
164
 
 
165
 
                memset(&st_path, 0, sizeof(st_path));
166
 
                if (stat(path, &st_path) < 0) {
167
 
 
168
 
                        if (errno == ENOENT || errno == ENOTDIR)
169
 
                                return 0;
170
 
 
171
 
                        return -errno;
172
 
                }
173
 
 
174
 
                return
175
 
                        st_path.st_dev == st_fd.st_dev &&
176
 
                        st_path.st_ino == st_fd.st_ino;
177
 
        }
178
 
 
179
 
        return 1;
180
 
}
181
 
 
182
 
_sd_export_ int sd_is_special(int fd, const char *path) {
183
 
        struct stat st_fd;
184
 
 
185
 
        if (fd < 0)
186
 
                return -EINVAL;
187
 
 
188
 
        if (fstat(fd, &st_fd) < 0)
189
 
                return -errno;
190
 
 
191
 
        if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode))
192
 
                return 0;
193
 
 
194
 
        if (path) {
195
 
                struct stat st_path;
196
 
 
197
 
                if (stat(path, &st_path) < 0) {
198
 
 
199
 
                        if (errno == ENOENT || errno == ENOTDIR)
200
 
                                return 0;
201
 
 
202
 
                        return -errno;
203
 
                }
204
 
 
205
 
                if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode))
206
 
                        return
207
 
                                st_path.st_dev == st_fd.st_dev &&
208
 
                                st_path.st_ino == st_fd.st_ino;
209
 
                else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode))
210
 
                        return st_path.st_rdev == st_fd.st_rdev;
211
 
                else
212
 
                        return 0;
213
 
        }
214
 
 
215
 
        return 1;
216
 
}
217
 
 
218
 
static int sd_is_socket_internal(int fd, int type, int listening) {
219
 
        struct stat st_fd;
220
 
 
221
 
        if (fd < 0 || type < 0)
222
 
                return -EINVAL;
223
 
 
224
 
        if (fstat(fd, &st_fd) < 0)
225
 
                return -errno;
226
 
 
227
 
        if (!S_ISSOCK(st_fd.st_mode))
228
 
                return 0;
229
 
 
230
 
        if (type != 0) {
231
 
                int other_type = 0;
232
 
                socklen_t l = sizeof(other_type);
233
 
 
234
 
                if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0)
235
 
                        return -errno;
236
 
 
237
 
                if (l != sizeof(other_type))
238
 
                        return -EINVAL;
239
 
 
240
 
                if (other_type != type)
241
 
                        return 0;
242
 
        }
243
 
 
244
 
        if (listening >= 0) {
245
 
                int accepting = 0;
246
 
                socklen_t l = sizeof(accepting);
247
 
 
248
 
                if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0)
249
 
                        return -errno;
250
 
 
251
 
                if (l != sizeof(accepting))
252
 
                        return -EINVAL;
253
 
 
254
 
                if (!accepting != !listening)
255
 
                        return 0;
256
 
        }
257
 
 
258
 
        return 1;
259
 
}
260
 
 
261
 
union sockaddr_union {
262
 
        struct sockaddr sa;
263
 
        struct sockaddr_in in4;
264
 
        struct sockaddr_in6 in6;
265
 
        struct sockaddr_un un;
266
 
        struct sockaddr_storage storage;
267
 
};
268
 
 
269
 
_sd_export_ int sd_is_socket(int fd, int family, int type, int listening) {
270
 
        int r;
271
 
 
272
 
        if (family < 0)
273
 
                return -EINVAL;
274
 
 
275
 
        if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
276
 
                return r;
277
 
 
278
 
        if (family > 0) {
279
 
                union sockaddr_union sockaddr;
280
 
                socklen_t l;
281
 
 
282
 
                memset(&sockaddr, 0, sizeof(sockaddr));
283
 
                l = sizeof(sockaddr);
284
 
 
285
 
                if (getsockname(fd, &sockaddr.sa, &l) < 0)
286
 
                        return -errno;
287
 
 
288
 
                if (l < sizeof(sa_family_t))
289
 
                        return -EINVAL;
290
 
 
291
 
                return sockaddr.sa.sa_family == family;
292
 
        }
293
 
 
294
 
        return 1;
295
 
}
296
 
 
297
 
_sd_export_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) {
298
 
        union sockaddr_union sockaddr;
299
 
        socklen_t l;
300
 
        int r;
301
 
 
302
 
        if (family != 0 && family != AF_INET && family != AF_INET6)
303
 
                return -EINVAL;
304
 
 
305
 
        if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
306
 
                return r;
307
 
 
308
 
        memset(&sockaddr, 0, sizeof(sockaddr));
309
 
        l = sizeof(sockaddr);
310
 
 
311
 
        if (getsockname(fd, &sockaddr.sa, &l) < 0)
312
 
                return -errno;
313
 
 
314
 
        if (l < sizeof(sa_family_t))
315
 
                return -EINVAL;
316
 
 
317
 
        if (sockaddr.sa.sa_family != AF_INET &&
318
 
            sockaddr.sa.sa_family != AF_INET6)
319
 
                return 0;
320
 
 
321
 
        if (family > 0)
322
 
                if (sockaddr.sa.sa_family != family)
323
 
                        return 0;
324
 
 
325
 
        if (port > 0) {
326
 
                if (sockaddr.sa.sa_family == AF_INET) {
327
 
                        if (l < sizeof(struct sockaddr_in))
328
 
                                return -EINVAL;
329
 
 
330
 
                        return htons(port) == sockaddr.in4.sin_port;
331
 
                } else {
332
 
                        if (l < sizeof(struct sockaddr_in6))
333
 
                                return -EINVAL;
334
 
 
335
 
                        return htons(port) == sockaddr.in6.sin6_port;
336
 
                }
337
 
        }
338
 
 
339
 
        return 1;
340
 
}
341
 
 
342
 
_sd_export_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) {
343
 
        union sockaddr_union sockaddr;
344
 
        socklen_t l;
345
 
        int r;
346
 
 
347
 
        if ((r = sd_is_socket_internal(fd, type, listening)) <= 0)
348
 
                return r;
349
 
 
350
 
        memset(&sockaddr, 0, sizeof(sockaddr));
351
 
        l = sizeof(sockaddr);
352
 
 
353
 
        if (getsockname(fd, &sockaddr.sa, &l) < 0)
354
 
                return -errno;
355
 
 
356
 
        if (l < sizeof(sa_family_t))
357
 
                return -EINVAL;
358
 
 
359
 
        if (sockaddr.sa.sa_family != AF_UNIX)
360
 
                return 0;
361
 
 
362
 
        if (path) {
363
 
                if (length <= 0)
364
 
                        length = strlen(path);
365
 
 
366
 
                if (length <= 0)
367
 
                        /* Unnamed socket */
368
 
                        return l == offsetof(struct sockaddr_un, sun_path);
369
 
 
370
 
                if (path[0])
371
 
                        /* Normal path socket */
372
 
                        return
373
 
                                (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) &&
374
 
                                memcmp(path, sockaddr.un.sun_path, length+1) == 0;
375
 
                else
376
 
                        /* Abstract namespace socket */
377
 
                        return
378
 
                                (l == offsetof(struct sockaddr_un, sun_path) + length) &&
379
 
                                memcmp(path, sockaddr.un.sun_path, length) == 0;
380
 
        }
381
 
 
382
 
        return 1;
383
 
}
384
 
 
385
 
_sd_export_ int sd_is_mq(int fd, const char *path) {
386
 
#if !defined(__linux__)
387
 
        return 0;
388
 
#else
389
 
        struct mq_attr attr;
390
 
 
391
 
        if (fd < 0)
392
 
                return -EINVAL;
393
 
 
394
 
        if (mq_getattr(fd, &attr) < 0)
395
 
                return -errno;
396
 
 
397
 
        if (path) {
398
 
                char fpath[PATH_MAX];
399
 
                struct stat a, b;
400
 
 
401
 
                if (path[0] != '/')
402
 
                        return -EINVAL;
403
 
 
404
 
                if (fstat(fd, &a) < 0)
405
 
                        return -errno;
406
 
 
407
 
                strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12);
408
 
                fpath[sizeof(fpath)-1] = 0;
409
 
 
410
 
                if (stat(fpath, &b) < 0)
411
 
                        return -errno;
412
 
 
413
 
                if (a.st_dev != b.st_dev ||
414
 
                    a.st_ino != b.st_ino)
415
 
                        return 0;
416
 
        }
417
 
 
418
 
        return 1;
419
 
#endif
420
 
}
421
 
 
422
 
_sd_export_ int sd_notify(int unset_environment, const char *state) {
423
 
#if defined(DISABLE_SYSTEMD) || !defined(__linux__) || !defined(SOCK_CLOEXEC)
424
 
        return 0;
425
 
#else
426
 
        int fd = -1, r;
427
 
        struct msghdr msghdr;
428
 
        struct iovec iovec;
429
 
        union sockaddr_union sockaddr;
430
 
        const char *e;
431
 
 
432
 
        if (!state) {
433
 
                r = -EINVAL;
434
 
                goto finish;
435
 
        }
436
 
 
437
 
        if (!(e = getenv("NOTIFY_SOCKET")))
438
 
                return 0;
439
 
 
440
 
        /* Must be an abstract socket, or an absolute path */
441
 
        if ((e[0] != '@' && e[0] != '/') || e[1] == 0) {
442
 
                r = -EINVAL;
443
 
                goto finish;
444
 
        }
445
 
 
446
 
        if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) {
447
 
                r = -errno;
448
 
                goto finish;
449
 
        }
450
 
 
451
 
        memset(&sockaddr, 0, sizeof(sockaddr));
452
 
        sockaddr.sa.sa_family = AF_UNIX;
453
 
        strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path));
454
 
 
455
 
        if (sockaddr.un.sun_path[0] == '@')
456
 
                sockaddr.un.sun_path[0] = 0;
457
 
 
458
 
        memset(&iovec, 0, sizeof(iovec));
459
 
        iovec.iov_base = (char*) state;
460
 
        iovec.iov_len = strlen(state);
461
 
 
462
 
        memset(&msghdr, 0, sizeof(msghdr));
463
 
        msghdr.msg_name = &sockaddr;
464
 
        msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e);
465
 
 
466
 
        if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
467
 
                msghdr.msg_namelen = sizeof(struct sockaddr_un);
468
 
 
469
 
        msghdr.msg_iov = &iovec;
470
 
        msghdr.msg_iovlen = 1;
471
 
 
472
 
        if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) {
473
 
                r = -errno;
474
 
                goto finish;
475
 
        }
476
 
 
477
 
        r = 1;
478
 
 
479
 
finish:
480
 
        if (unset_environment)
481
 
                unsetenv("NOTIFY_SOCKET");
482
 
 
483
 
        if (fd >= 0)
484
 
                close(fd);
485
 
 
486
 
        return r;
487
 
#endif
488
 
}
489
 
 
490
 
_sd_export_ int sd_notifyf(int unset_environment, const char *format, ...) {
491
 
#if defined(DISABLE_SYSTEMD) || !defined(__linux__)
492
 
        return 0;
493
 
#else
494
 
        va_list ap;
495
 
        char *p = NULL;
496
 
        int r;
497
 
 
498
 
        va_start(ap, format);
499
 
        r = vasprintf(&p, format, ap);
500
 
        va_end(ap);
501
 
 
502
 
        if (r < 0 || !p)
503
 
                return -ENOMEM;
504
 
 
505
 
        r = sd_notify(unset_environment, p);
506
 
        free(p);
507
 
 
508
 
        return r;
509
 
#endif
510
 
}
511
 
 
512
 
_sd_export_ int sd_booted(void) {
513
 
#if defined(DISABLE_SYSTEMD) || !defined(__linux__)
514
 
        return 0;
515
 
#else
516
 
 
517
 
        struct stat a, b;
518
 
 
519
 
        /* We simply test whether the systemd cgroup hierarchy is
520
 
         * mounted */
521
 
 
522
 
        if (lstat("/sys/fs/cgroup", &a) < 0)
523
 
                return 0;
524
 
 
525
 
        if (lstat("/sys/fs/cgroup/systemd", &b) < 0)
526
 
                return 0;
527
 
 
528
 
        return a.st_dev != b.st_dev;
529
 
#endif
530
 
}