pcw / cwd.c

#include <unistd.h>
#include <signal.h>
#include <sys/inotify.h>
#include <sys/wait.h>
#include <stdio.h>
#include <ftw.h>
#include <string.h>

#define PATH_MAX    1024
#define MAX_OPENFD  4
#define MAX_WATCH   512

int evq, init;
char paths[MAX_WATCH][PATH_MAX] = {0};
int wins[MAX_WATCH] = {0};

void win(int wd)
{
	char in[1024], out[1024];

	if (wins[wd])
		return;

	sprintf(out, "%s/out", paths[wd]);
	sprintf(in,  "%s/in",  paths[wd]);

	printf("about to run urxvt -title %s -e srw cw %s %s\n", paths[wd], out, in);

	if ((wins[wd] = fork()) == 0) {
		execlp("urxvt", "urxvt", "-title", paths[wd], "-e", "srw", "cw", out, in, NULL);
		err(1, "failed on execlp cw");
	} else {
		printf("child has pid %d\n", wins[wd]);
	}
}

int add_dir(const char *fpath, const struct stat *sb, int typeflag)
{
	int wd;
	char out[PATH_MAX];
	struct stat st;

	if (!(typeflag & FTW_D))
		return;

	if ((wd = inotify_add_watch(evq, fpath, IN_CREATE | IN_MODIFY)) < 0)
		warn("failed on inotify_add_watch on %s", fpath);

	if (paths[wd][0] == '\0') {
		strcpy(paths[wd], fpath);
		printf("added %s\n", paths[wd]);
		strcpy(out, fpath);
		strcat(out, "/out");
		if (!init && stat(out, &st) == 0)
			win(wd);
	} else {
		printf("existed %s\n", paths[wd]);
	}

	return 0;
}

int find(int *haystack, int needle, int len)
{
	int i;

	for (i = 0; i < len; i++)
		if (haystack[i] == needle)
			return i;

	return -1;
}

void sigchld(int unused) {
	pid_t pid;
	int wd;

	if(signal(SIGCHLD, sigchld) == SIG_ERR)
		err("failed installing SIGCHLD handler");

	while((pid = waitpid(-1, NULL, WNOHANG)) > 0) {
		printf("killed child with pid %d ", pid);
		if ((wd = find(wins, pid, MAX_WATCH)) > -1) {
			printf("wd %d path %s\n", wd, paths[wd]);
			wins[wd] = 0;
		} else {
			printf("no wd...\n");
		}
	}
}

int main(int argc, char **argv)
{
	char buf[4096];
	int i, len;
	struct inotify_event *cur;

	sigchld(0);

	if ((evq = inotify_init()) < 0)
		err(1, "failed on inotify_init()");

	init = 1;
	ftw(argv[1], add_dir, MAX_OPENFD);
	init = 0;

	for (;;) {
		if ((len = read(evq, buf, sizeof(buf))) < 0)
			warn("failed to read from inotify event queue");
		for (cur = (struct inotify_event *)buf; (char *)cur - buf < len; cur += sizeof(struct inotify_event) + cur->len) {
			if (cur->mask & (IN_CREATE | IN_ISDIR))
				ftw(argv[1], add_dir, MAX_OPENFD);
			if (cur->mask & (IN_CREATE | IN_MODIFY) && !strcmp(cur->name, "out"))
				win(cur->wd);
		}
	}

	return 0;
}
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.