chiark / gitweb /
core: fix return value on OOM
[elogind.git] / src / core / path.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 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 <sys/inotify.h>
23 #include <sys/epoll.h>
24 #include <errno.h>
25 #include <unistd.h>
26
27 #include "unit.h"
28 #include "unit-name.h"
29 #include "path.h"
30 #include "mkdir.h"
31 #include "dbus-path.h"
32 #include "special.h"
33 #include "macro.h"
34 #include "bus-util.h"
35 #include "bus-error.h"
36
37 static const UnitActiveState state_translation_table[_PATH_STATE_MAX] = {
38         [PATH_DEAD] = UNIT_INACTIVE,
39         [PATH_WAITING] = UNIT_ACTIVE,
40         [PATH_RUNNING] = UNIT_ACTIVE,
41         [PATH_FAILED] = UNIT_FAILED
42 };
43
44 static int path_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
45
46 int path_spec_watch(PathSpec *s, sd_event_io_handler_t handler) {
47
48         static const int flags_table[_PATH_TYPE_MAX] = {
49                 [PATH_EXISTS] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB,
50                 [PATH_EXISTS_GLOB] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB,
51                 [PATH_CHANGED] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CLOSE_WRITE|IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO,
52                 [PATH_MODIFIED] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CLOSE_WRITE|IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO|IN_MODIFY,
53                 [PATH_DIRECTORY_NOT_EMPTY] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CREATE|IN_MOVED_TO
54         };
55
56         bool exists = false;
57         char *slash, *oldslash = NULL;
58         int r;
59
60         assert(s);
61         assert(s->unit);
62         assert(handler);
63
64         path_spec_unwatch(s);
65
66         s->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
67         if (s->inotify_fd < 0) {
68                 r = -errno;
69                 goto fail;
70         }
71
72         r = sd_event_add_io(s->unit->manager->event, &s->event_source, s->inotify_fd, EPOLLIN, handler, s);
73         if (r < 0)
74                 goto fail;
75
76         /* This assumes the path was passed through path_kill_slashes()! */
77
78         for (slash = strchr(s->path, '/'); ; slash = strchr(slash+1, '/')) {
79                 char *cut = NULL;
80                 int flags;
81                 char tmp;
82
83                 if (slash) {
84                         cut = slash + (slash == s->path);
85                         tmp = *cut;
86                         *cut = '\0';
87
88                         flags = IN_MOVE_SELF | IN_DELETE_SELF | IN_ATTRIB | IN_CREATE | IN_MOVED_TO;
89                 } else
90                         flags = flags_table[s->type];
91
92                 r = inotify_add_watch(s->inotify_fd, s->path, flags);
93                 if (r < 0) {
94                         if (errno == EACCES || errno == ENOENT) {
95                                 if (cut)
96                                         *cut = tmp;
97                                 break;
98                         }
99
100                         log_warning("Failed to add watch on %s: %s", s->path,
101                                     errno == ENOSPC ? "too many watches" : strerror(-r));
102                         r = -errno;
103                         if (cut)
104                                 *cut = tmp;
105                         goto fail;
106                 } else {
107                         exists = true;
108
109                         /* Path exists, we don't need to watch parent
110                            too closely. */
111                         if (oldslash) {
112                                 char *cut2 = oldslash + (oldslash == s->path);
113                                 char tmp2 = *cut2;
114                                 *cut2 = '\0';
115
116                                 inotify_add_watch(s->inotify_fd, s->path, IN_MOVE_SELF);
117                                 /* Error is ignored, the worst can happen is
118                                    we get spurious events. */
119
120                                 *cut2 = tmp2;
121                         }
122                 }
123
124                 if (cut)
125                         *cut = tmp;
126
127                 if (slash)
128                         oldslash = slash;
129                 else {
130                         /* whole path has been iterated over */
131                         s->primary_wd = r;
132                         break;
133                 }
134         }
135
136         if (!exists) {
137                 log_error_errno(errno, "Failed to add watch on any of the components of %s: %m",
138                           s->path);
139                 r = -errno; /* either EACCESS or ENOENT */
140                 goto fail;
141         }
142
143         return 0;
144
145 fail:
146         path_spec_unwatch(s);
147         return r;
148 }
149
150 void path_spec_unwatch(PathSpec *s) {
151         assert(s);
152
153         s->event_source = sd_event_source_unref(s->event_source);
154         s->inotify_fd = safe_close(s->inotify_fd);
155 }
156
157 int path_spec_fd_event(PathSpec *s, uint32_t revents) {
158         union inotify_event_buffer buffer;
159         struct inotify_event *e;
160         ssize_t l;
161         int r = 0;
162
163         if (revents != EPOLLIN) {
164                 log_error("Got invalid poll event on inotify.");
165                 return -EINVAL;
166         }
167
168         l = read(s->inotify_fd, &buffer, sizeof(buffer));
169         if (l < 0) {
170                 if (errno == EAGAIN || errno == EINTR)
171                         return 0;
172
173                 return log_error_errno(errno, "Failed to read inotify event: %m");
174         }
175
176         FOREACH_INOTIFY_EVENT(e, buffer, l) {
177                 if ((s->type == PATH_CHANGED || s->type == PATH_MODIFIED) &&
178                     s->primary_wd == e->wd)
179                         r = 1;
180         }
181
182         return r;
183 }
184
185 static bool path_spec_check_good(PathSpec *s, bool initial) {
186         bool good = false;
187
188         switch (s->type) {
189
190         case PATH_EXISTS:
191                 good = access(s->path, F_OK) >= 0;
192                 break;
193
194         case PATH_EXISTS_GLOB:
195                 good = glob_exists(s->path) > 0;
196                 break;
197
198         case PATH_DIRECTORY_NOT_EMPTY: {
199                 int k;
200
201                 k = dir_is_empty(s->path);
202                 good = !(k == -ENOENT || k > 0);
203                 break;
204         }
205
206         case PATH_CHANGED:
207         case PATH_MODIFIED: {
208                 bool b;
209
210                 b = access(s->path, F_OK) >= 0;
211                 good = !initial && b != s->previous_exists;
212                 s->previous_exists = b;
213                 break;
214         }
215
216         default:
217                 ;
218         }
219
220         return good;
221 }
222
223 static void path_spec_mkdir(PathSpec *s, mode_t mode) {
224         int r;
225
226         if (s->type == PATH_EXISTS || s->type == PATH_EXISTS_GLOB)
227                 return;
228
229         r = mkdir_p_label(s->path, mode);
230         if (r < 0)
231                 log_warning_errno(r, "mkdir(%s) failed: %m", s->path);
232 }
233
234 static void path_spec_dump(PathSpec *s, FILE *f, const char *prefix) {
235         fprintf(f,
236                 "%s%s: %s\n",
237                 prefix,
238                 path_type_to_string(s->type),
239                 s->path);
240 }
241
242 void path_spec_done(PathSpec *s) {
243         assert(s);
244         assert(s->inotify_fd == -1);
245
246         free(s->path);
247 }
248
249 static void path_init(Unit *u) {
250         Path *p = PATH(u);
251
252         assert(u);
253         assert(u->load_state == UNIT_STUB);
254
255         p->directory_mode = 0755;
256 }
257
258 void path_free_specs(Path *p) {
259         PathSpec *s;
260
261         assert(p);
262
263         while ((s = p->specs)) {
264                 path_spec_unwatch(s);
265                 LIST_REMOVE(spec, p->specs, s);
266                 path_spec_done(s);
267                 free(s);
268         }
269 }
270
271 static void path_done(Unit *u) {
272         Path *p = PATH(u);
273
274         assert(p);
275
276         path_free_specs(p);
277 }
278
279 static int path_add_mount_links(Path *p) {
280         PathSpec *s;
281         int r;
282
283         assert(p);
284
285         LIST_FOREACH(spec, s, p->specs) {
286                 r = unit_require_mounts_for(UNIT(p), s->path);
287                 if (r < 0)
288                         return r;
289         }
290
291         return 0;
292 }
293
294 static int path_verify(Path *p) {
295         assert(p);
296
297         if (UNIT(p)->load_state != UNIT_LOADED)
298                 return 0;
299
300         if (!p->specs) {
301                 log_unit_error(UNIT(p)->id,
302                                "%s lacks path setting. Refusing.", UNIT(p)->id);
303                 return -EINVAL;
304         }
305
306         return 0;
307 }
308
309 static int path_add_default_dependencies(Path *p) {
310         int r;
311
312         assert(p);
313
314         r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE,
315                                         SPECIAL_PATHS_TARGET, NULL, true);
316         if (r < 0)
317                 return r;
318
319         if (UNIT(p)->manager->running_as == SYSTEMD_SYSTEM) {
320                 r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES,
321                                                       SPECIAL_SYSINIT_TARGET, NULL, true);
322                 if (r < 0)
323                         return r;
324         }
325
326         return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS,
327                                                  SPECIAL_SHUTDOWN_TARGET, NULL, true);
328 }
329
330 static int path_load(Unit *u) {
331         Path *p = PATH(u);
332         int r;
333
334         assert(u);
335         assert(u->load_state == UNIT_STUB);
336
337         r = unit_load_fragment_and_dropin(u);
338         if (r < 0)
339                 return r;
340
341         if (u->load_state == UNIT_LOADED) {
342
343                 if (set_isempty(u->dependencies[UNIT_TRIGGERS])) {
344                         Unit *x;
345
346                         r = unit_load_related_unit(u, ".service", &x);
347                         if (r < 0)
348                                 return r;
349
350                         r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
351                         if (r < 0)
352                                 return r;
353                 }
354
355                 r = path_add_mount_links(p);
356                 if (r < 0)
357                         return r;
358
359                 if (UNIT(p)->default_dependencies) {
360                         r = path_add_default_dependencies(p);
361                         if (r < 0)
362                                 return r;
363                 }
364         }
365
366         return path_verify(p);
367 }
368
369 static void path_dump(Unit *u, FILE *f, const char *prefix) {
370         Path *p = PATH(u);
371         Unit *trigger;
372         PathSpec *s;
373
374         assert(p);
375         assert(f);
376
377         trigger = UNIT_TRIGGER(u);
378
379         fprintf(f,
380                 "%sPath State: %s\n"
381                 "%sResult: %s\n"
382                 "%sUnit: %s\n"
383                 "%sMakeDirectory: %s\n"
384                 "%sDirectoryMode: %04o\n",
385                 prefix, path_state_to_string(p->state),
386                 prefix, path_result_to_string(p->result),
387                 prefix, trigger ? trigger->id : "n/a",
388                 prefix, yes_no(p->make_directory),
389                 prefix, p->directory_mode);
390
391         LIST_FOREACH(spec, s, p->specs)
392                 path_spec_dump(s, f, prefix);
393 }
394
395 static void path_unwatch(Path *p) {
396         PathSpec *s;
397
398         assert(p);
399
400         LIST_FOREACH(spec, s, p->specs)
401                 path_spec_unwatch(s);
402 }
403
404 static int path_watch(Path *p) {
405         int r;
406         PathSpec *s;
407
408         assert(p);
409
410         LIST_FOREACH(spec, s, p->specs) {
411                 r = path_spec_watch(s, path_dispatch_io);
412                 if (r < 0)
413                         return r;
414         }
415
416         return 0;
417 }
418
419 static void path_set_state(Path *p, PathState state) {
420         PathState old_state;
421         assert(p);
422
423         old_state = p->state;
424         p->state = state;
425
426         if (state != PATH_WAITING &&
427             (state != PATH_RUNNING || p->inotify_triggered))
428                 path_unwatch(p);
429
430         if (state != old_state)
431                 log_debug("%s changed %s -> %s",
432                           UNIT(p)->id,
433                           path_state_to_string(old_state),
434                           path_state_to_string(state));
435
436         unit_notify(UNIT(p), state_translation_table[old_state], state_translation_table[state], true);
437 }
438
439 static void path_enter_waiting(Path *p, bool initial, bool recheck);
440
441 static int path_coldplug(Unit *u) {
442         Path *p = PATH(u);
443
444         assert(p);
445         assert(p->state == PATH_DEAD);
446
447         if (p->deserialized_state != p->state) {
448
449                 if (p->deserialized_state == PATH_WAITING ||
450                     p->deserialized_state == PATH_RUNNING)
451                         path_enter_waiting(p, true, true);
452                 else
453                         path_set_state(p, p->deserialized_state);
454         }
455
456         return 0;
457 }
458
459 static void path_enter_dead(Path *p, PathResult f) {
460         assert(p);
461
462         if (f != PATH_SUCCESS)
463                 p->result = f;
464
465         path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD);
466 }
467
468 static void path_enter_running(Path *p) {
469         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
470         int r;
471
472         assert(p);
473
474         /* Don't start job if we are supposed to go down */
475         if (unit_stop_pending(UNIT(p)))
476                 return;
477
478         r = manager_add_job(UNIT(p)->manager, JOB_START, UNIT_TRIGGER(UNIT(p)),
479                             JOB_REPLACE, true, &error, NULL);
480         if (r < 0)
481                 goto fail;
482
483         p->inotify_triggered = false;
484
485         r = path_watch(p);
486         if (r < 0)
487                 goto fail;
488
489         path_set_state(p, PATH_RUNNING);
490         return;
491
492 fail:
493         log_warning("%s failed to queue unit startup job: %s",
494                     UNIT(p)->id, bus_error_message(&error, r));
495         path_enter_dead(p, PATH_FAILURE_RESOURCES);
496 }
497
498 static bool path_check_good(Path *p, bool initial) {
499         PathSpec *s;
500         bool good = false;
501
502         assert(p);
503
504         LIST_FOREACH(spec, s, p->specs) {
505                 good = path_spec_check_good(s, initial);
506
507                 if (good)
508                         break;
509         }
510
511         return good;
512 }
513
514 static void path_enter_waiting(Path *p, bool initial, bool recheck) {
515         int r;
516
517         if (recheck)
518                 if (path_check_good(p, initial)) {
519                         log_debug("%s got triggered.", UNIT(p)->id);
520                         path_enter_running(p);
521                         return;
522                 }
523
524         r = path_watch(p);
525         if (r < 0)
526                 goto fail;
527
528         /* Hmm, so now we have created inotify watches, but the file
529          * might have appeared/been removed by now, so we must
530          * recheck */
531
532         if (recheck)
533                 if (path_check_good(p, false)) {
534                         log_debug("%s got triggered.", UNIT(p)->id);
535                         path_enter_running(p);
536                         return;
537                 }
538
539         path_set_state(p, PATH_WAITING);
540         return;
541
542 fail:
543         log_warning_errno(r, "%s failed to enter waiting state: %m", UNIT(p)->id);
544         path_enter_dead(p, PATH_FAILURE_RESOURCES);
545 }
546
547 static void path_mkdir(Path *p) {
548         PathSpec *s;
549
550         assert(p);
551
552         if (!p->make_directory)
553                 return;
554
555         LIST_FOREACH(spec, s, p->specs)
556                 path_spec_mkdir(s, p->directory_mode);
557 }
558
559 static int path_start(Unit *u) {
560         Path *p = PATH(u);
561
562         assert(p);
563         assert(p->state == PATH_DEAD || p->state == PATH_FAILED);
564
565         if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED)
566                 return -ENOENT;
567
568         path_mkdir(p);
569
570         p->result = PATH_SUCCESS;
571         path_enter_waiting(p, true, true);
572
573         return 1;
574 }
575
576 static int path_stop(Unit *u) {
577         Path *p = PATH(u);
578
579         assert(p);
580         assert(p->state == PATH_WAITING || p->state == PATH_RUNNING);
581
582         path_enter_dead(p, PATH_SUCCESS);
583         return 1;
584 }
585
586 static int path_serialize(Unit *u, FILE *f, FDSet *fds) {
587         Path *p = PATH(u);
588
589         assert(u);
590         assert(f);
591         assert(fds);
592
593         unit_serialize_item(u, f, "state", path_state_to_string(p->state));
594         unit_serialize_item(u, f, "result", path_result_to_string(p->result));
595
596         return 0;
597 }
598
599 static int path_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
600         Path *p = PATH(u);
601
602         assert(u);
603         assert(key);
604         assert(value);
605         assert(fds);
606
607         if (streq(key, "state")) {
608                 PathState state;
609
610                 state = path_state_from_string(value);
611                 if (state < 0)
612                         log_debug("Failed to parse state value %s", value);
613                 else
614                         p->deserialized_state = state;
615
616         } else if (streq(key, "result")) {
617                 PathResult f;
618
619                 f = path_result_from_string(value);
620                 if (f < 0)
621                         log_debug("Failed to parse result value %s", value);
622                 else if (f != PATH_SUCCESS)
623                         p->result = f;
624
625         } else
626                 log_debug("Unknown serialization key '%s'", key);
627
628         return 0;
629 }
630
631 _pure_ static UnitActiveState path_active_state(Unit *u) {
632         assert(u);
633
634         return state_translation_table[PATH(u)->state];
635 }
636
637 _pure_ static const char *path_sub_state_to_string(Unit *u) {
638         assert(u);
639
640         return path_state_to_string(PATH(u)->state);
641 }
642
643 static int path_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
644         PathSpec *s = userdata;
645         Path *p;
646         int changed;
647
648         assert(s);
649         assert(s->unit);
650         assert(fd >= 0);
651
652         p = PATH(s->unit);
653
654         if (p->state != PATH_WAITING &&
655             p->state != PATH_RUNNING)
656                 return 0;
657
658         /* log_debug("inotify wakeup on %s.", u->id); */
659
660         LIST_FOREACH(spec, s, p->specs)
661                 if (path_spec_owns_inotify_fd(s, fd))
662                         break;
663
664         if (!s) {
665                 log_error("Got event on unknown fd.");
666                 goto fail;
667         }
668
669         changed = path_spec_fd_event(s, revents);
670         if (changed < 0)
671                 goto fail;
672
673         /* If we are already running, then remember that one event was
674          * dispatched so that we restart the service only if something
675          * actually changed on disk */
676         p->inotify_triggered = true;
677
678         if (changed)
679                 path_enter_running(p);
680         else
681                 path_enter_waiting(p, false, true);
682
683         return 0;
684
685 fail:
686         path_enter_dead(p, PATH_FAILURE_RESOURCES);
687         return 0;
688 }
689
690 static void path_trigger_notify(Unit *u, Unit *other) {
691         Path *p = PATH(u);
692
693         assert(u);
694         assert(other);
695
696         /* Invoked whenever the unit we trigger changes state or gains
697          * or loses a job */
698
699         if (other->load_state != UNIT_LOADED)
700                 return;
701
702         if (p->state == PATH_RUNNING &&
703             UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
704                 log_unit_debug(UNIT(p)->id,
705                                "%s got notified about unit deactivation.",
706                                UNIT(p)->id);
707
708                 /* Hmm, so inotify was triggered since the
709                  * last activation, so I guess we need to
710                  * recheck what is going on. */
711                 path_enter_waiting(p, false, p->inotify_triggered);
712         }
713 }
714
715 static void path_reset_failed(Unit *u) {
716         Path *p = PATH(u);
717
718         assert(p);
719
720         if (p->state == PATH_FAILED)
721                 path_set_state(p, PATH_DEAD);
722
723         p->result = PATH_SUCCESS;
724 }
725
726 static const char* const path_state_table[_PATH_STATE_MAX] = {
727         [PATH_DEAD] = "dead",
728         [PATH_WAITING] = "waiting",
729         [PATH_RUNNING] = "running",
730         [PATH_FAILED] = "failed"
731 };
732
733 DEFINE_STRING_TABLE_LOOKUP(path_state, PathState);
734
735 static const char* const path_type_table[_PATH_TYPE_MAX] = {
736         [PATH_EXISTS] = "PathExists",
737         [PATH_EXISTS_GLOB] = "PathExistsGlob",
738         [PATH_DIRECTORY_NOT_EMPTY] = "DirectoryNotEmpty",
739         [PATH_CHANGED] = "PathChanged",
740         [PATH_MODIFIED] = "PathModified",
741 };
742
743 DEFINE_STRING_TABLE_LOOKUP(path_type, PathType);
744
745 static const char* const path_result_table[_PATH_RESULT_MAX] = {
746         [PATH_SUCCESS] = "success",
747         [PATH_FAILURE_RESOURCES] = "resources",
748 };
749
750 DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult);
751
752 const UnitVTable path_vtable = {
753         .object_size = sizeof(Path),
754
755         .sections =
756                 "Unit\0"
757                 "Path\0"
758                 "Install\0",
759
760         .init = path_init,
761         .done = path_done,
762         .load = path_load,
763
764         .coldplug = path_coldplug,
765
766         .dump = path_dump,
767
768         .start = path_start,
769         .stop = path_stop,
770
771         .serialize = path_serialize,
772         .deserialize_item = path_deserialize_item,
773
774         .active_state = path_active_state,
775         .sub_state_to_string = path_sub_state_to_string,
776
777         .trigger_notify = path_trigger_notify,
778
779         .reset_failed = path_reset_failed,
780
781         .bus_interface = "org.freedesktop.systemd1.Path",
782         .bus_vtable = bus_path_vtable
783 };