#include #include #include #include #define t(stmt) if (stmt) goto fail static size_t pauser_count = 0; static size_t pausers_size = 0; static char* pausers = NULL; static int is_moc_playing(void) { return !WEXITSTATUS(system("env LANG=C mocp -i 2>/dev/null | grep 'State: PLAY' >/dev/null")); } /* In a proper implementation, message whould be copyied, and then * a new thread would be created that parsed the copy. But that is * too much for an example, especially since it would also require * a mutex to make sure two threads do not modify data at the same * time, causing chaos. */ static int callback(const char *message, void *user_data) { char *msg = NULL; size_t len = 0; if (message == 0) return 1; while ((len < 2047) && message[len]) len++; msg = malloc((len + 1) * sizeof(char)); t(msg == NULL); memcpy(msg, message, len * sizeof(char)); msg[len] = 0; /* BEGIN run as in a separate thread */ if (pauser_count || is_moc_playing()) { char *begin = strchr(msg, ' '); ssize_t pid; int requests_pause; if (begin == NULL) goto done; *begin++ = 0; pid = (ssize_t)atoll(msg); if (pid < 1) /* We need a real PID, too bad there is no convient way to detect if it dies. */ goto done; if ((strstr(begin, "force-pause ") == begin) || !strcmp(begin, "force-pause")) requests_pause = 1; else if ((strstr(begin, "unforce-pause ") == begin) || !strcmp(begin, "unforce-pause")) requests_pause = 0; else goto done; if ((size_t)pid >= pausers_size) { pausers = realloc(pausers, (size_t)(pid + 1) * sizeof(char)); t(pausers == NULL); /* Let's ignore the memory leak. */ memset(pausers + pausers_size, 0, ((size_t)(pid + 1) - pausers_size) * sizeof(char)); pausers_size = (size_t)(pid + 1); } if (pausers[pid] ^ requests_pause) { pauser_count += requests_pause ? 1 : -1; pausers[pid] = requests_pause; if (pauser_count == (size_t)requests_pause) system(requests_pause ? "mocp -P" : "mocp -U"); } } /* END run as in a separate thread */ goto done; (void) user_data; fail: perror("monitor"); return -1; done: free(msg); return 1; } int main() { bus_t bus; t(bus_open(&bus, "/tmp/example-bus", BUS_RDONLY)); t(bus_read(&bus, callback, NULL)); bus_close(&bus); free(pausers); return 0; fail: perror("monitor"); bus_close(&bus); free(pausers); return 1; }