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