#include <poll.h>
#include <unistd.h>
#include <time.h>
+#include <signal.h>
#include <sys/inotify.h>
#include <fs-util.h>
+#include <sd-journal.h>
#define PATH_SYSTEM "/run/systemd/system/"
#define PATH_USER "/run/user/5001/systemd/"
#define GRAPHICAL_TARGET_DONE "graphical.target.done"
#define DEFAULT_TARGET_DONE "default.target.done"
-#define WAIT_TIMEOUT_MS 30000 /* 30 seconds */
+#define WAIT_TIMEOUT 30 /* 30 seconds */
static int wd[2];
static unsigned char remains;
+static struct sigaction sa;
+
static long get_current_monotonic_ms(void)
{
struct timespec current;
return (current.tv_sec * 1000) + (current.tv_nsec / 1000000);
}
-static void handle_events(int fd)
+static void exit_failure_error(const char *format, ...)
+{
+ va_list ap;
+
+ alarm(0); /* cancel alarm */
+
+ va_start(ap, format);
+ sd_journal_printv(LOG_ERR, format, ap);
+ va_end(ap);
+
+ exit(EXIT_FAILURE);
+}
+
+static void exit_failure_timeout(int signum)
+{
+ exit_failure_error("30s timeout expired, Remains: %#x", remains);
+}
+
+static void exit_success(void)
+{
+ alarm(0); /* cancel alarm */
+ exit(EXIT_SUCCESS);
+}
+
+static void init_timer(void)
+{
+ sa.sa_handler = exit_failure_timeout;
+ sigaction(SIGALRM, &sa, NULL);
+
+ /* timer for 30s timeout, raise SIGALRM on expire */
+ alarm(WAIT_TIMEOUT);
+}
+
+static void handle_file_event(int fd)
{
union inotify_event_buffer buffer;
struct inotify_event *e;
ssize_t l;
+ long current_ms;
while (1) {
l = read(fd, &buffer, sizeof(buffer));
- if (l== -1 && errno != EAGAIN) {
- perror("read");
- exit(EXIT_FAILURE);
- }
+ if (l== -1 && errno != EAGAIN)
+ exit_failure_error("Failed to read.");
if (l <= 0)
break;
FOREACH_INOTIFY_EVENT(e, buffer, l) {
if (e->mask & IN_CREATE) {
- if (e->wd == wd[0] && strstr(e->name, GRAPHICAL_TARGET_DONE))
+ current_ms = get_current_monotonic_ms();
+ if (e->wd == wd[0] && !strcmp(e->name, GRAPHICAL_TARGET_DONE)) {
+ sd_journal_print(LOG_DEBUG, "%s%s is created. (%ld)",
+ PATH_SYSTEM, GRAPHICAL_TARGET_DONE, current_ms);
remains &= ~(1 << 0);
- else if (e->wd == wd[1] && strstr(e->name, DEFAULT_TARGET_DONE))
+ } else if (e->wd == wd[1] && !strcmp(e->name, DEFAULT_TARGET_DONE)) {
+ sd_journal_print(LOG_DEBUG, "%s%s is created. (%ld)",
+ PATH_USER, DEFAULT_TARGET_DONE, current_ms);
remains &= ~(1 << 1);
- else if (e->wd == wd[0] && strstr(e->name, DELAYED_TARGET_DONE))
+ } else if (e->wd == wd[0] && !strcmp(e->name, DELAYED_TARGET_DONE)) {
+ sd_journal_print(LOG_DEBUG, "%s%s is created. (%ld)",
+ PATH_SYSTEM, DELAYED_TARGET_DONE, current_ms);
remains &= ~(1 << 2);
- else if (e->wd == wd[1] && strstr(e->name, DELAYED_TARGET_DONE))
+ } else if (e->wd == wd[1] && !strcmp(e->name, DELAYED_TARGET_DONE)) {
+ sd_journal_print(LOG_DEBUG, "%s%s is created. (%ld)",
+ PATH_USER, DELAYED_TARGET_DONE, current_ms);
remains &= ~(1 << 3);
+ }
}
}
int fd, poll_num;
nfds_t nfds;
struct pollfd fds[1];
- long current_ms, timeout_ms;
+
+ sd_journal_print(LOG_DEBUG, "Start main.");
+
+ init_timer();
remains = 0;
- fd = inotify_init();
- if (fd < 0) {
- perror("inotify_init");
- exit(EXIT_FAILURE);
- }
+ fd = inotify_init1(IN_NONBLOCK);
+ if (fd < 0)
+ exit_failure_error("Failed to inotify_init.");
- wd[0] = inotify_add_watch(fd, PATH_SYSTEM, IN_CREATE);
- while (wd[0] < 0)
- wd[0] = inotify_add_watch(fd, PATH_SYSTEM, IN_CREATE);
+ /* add watch descriptor for directory PATH_SYSTEM */
+ while (access(PATH_SYSTEM, F_OK) != 0) {
+ sleep(1);
+ }
+ wd[0] = inotify_add_watch(fd, PATH_SYSTEM, IN_ALL_EVENTS);
+ if (wd[0] < 0)
+ exit_failure_error("Failed to add wd to %s: %s", PATH_SYSTEM, strerror(errno));
- wd[1] = inotify_add_watch(fd, PATH_USER, IN_CREATE);
- while (wd[1] < 0)
- wd[1] = inotify_add_watch(fd, PATH_USER, IN_CREATE);
+ /* watch descriptor for directory PATH_USER */
+ while (access(PATH_USER, F_OK) != 0) {
+ sleep(1);
+ }
+ wd[1] = inotify_add_watch(fd, PATH_USER, IN_ALL_EVENTS);
+ if (wd[1] < 0)
+ exit_failure_error("Failed to add wd to %s: %s", PATH_USER, strerror(errno));
+ /* setting files to be waited */
if (access(PATH_SYSTEM GRAPHICAL_TARGET_DONE, F_OK) == -1)
remains |= (1 << 0);
if (access(PATH_USER DEFAULT_TARGET_DONE, F_OK) == -1)
remains |= (1 << 3);
}
+ sd_journal_print(LOG_DEBUG, "wd(%s): %d, wd(%s): %d, Remains: %#x",
+ PATH_SYSTEM, wd[0], PATH_USER, wd[1], remains);
+
nfds = 1;
fds[0].fd = fd;
fds[0].events = POLLIN;
- current_ms = get_current_monotonic_ms();
- timeout_ms = current_ms + WAIT_TIMEOUT_MS;
-
- while (remains && current_ms < timeout_ms) {
- poll_num = poll(fds, nfds, timeout_ms - current_ms);
+ /* polling filesystem events */
+ while (remains) {
+ poll_num = poll(fds, nfds, WAIT_TIMEOUT * 1000);
if (poll_num == -1) {
- if (errno == EINTR) {
- current_ms = get_current_monotonic_ms();
+ if (errno == EINTR)
continue;
- }
- exit(EXIT_FAILURE);
+ exit_failure_error("Failed to poll.");
}
if (poll_num > 0 && fds[0].revents & POLLIN)
- handle_events(fd);
-
- current_ms = get_current_monotonic_ms();
+ handle_file_event(fd);
}
close(fd);
if (remains)
- exit(EXIT_FAILURE);
+ exit_failure_error("Failed to wait target, Remains: %#x", remains);
else
- exit(EXIT_SUCCESS);
+ exit_success();
}