Source

pcw / pcw.c

Full commit
Evan Gates 30b5010 
Evan Gates 1bced3b 
Evan Gates 40154d1 


Evan Gates 30b5010 
Evan Gates 40154d1 
Evan Gates 30b5010 
Evan Gates 40154d1 
Evan Gates 30b5010 


Evan Gates 468111c 

Evan Gates 18cc4f5 
Evan Gates 30b5010 
Evan Gates 3d3a994 

Evan Gates 30b5010 



Evan Gates 18cc4f5 
Evan Gates 30b5010 



Evan Gates 9c22727 
Evan Gates 468111c 
Evan Gates 30b5010 
Evan Gates e5172fa 
Evan Gates 30b5010 

Evan Gates 18cc4f5 
Evan Gates 3d3a994 
Evan Gates 30b5010 



Evan Gates 9c22727 

Evan Gates 30b5010 











Evan Gates 2a1b7f6 
Evan Gates 30b5010 
Evan Gates 2a1b7f6 

Evan Gates 30b5010 


Evan Gates 71fc988 
Evan Gates 30b5010 






















Evan Gates e5172fa 
Evan Gates 30b5010 





Evan Gates 2a1b7f6 
Evan Gates 9c22727 
Evan Gates 30b5010 


Evan Gates 9c22727 



Evan Gates 30b5010 

Evan Gates 9c22727 

Evan Gates 30b5010 







Evan Gates 9c22727 
Evan Gates 30b5010 


Evan Gates 1bced3b 
Evan Gates 30b5010 
Evan Gates 2a1b7f6 
Evan Gates 71fc988 


Evan Gates 2a1b7f6 
Evan Gates 30b5010 
Evan Gates 9c22727 
Evan Gates 30b5010 





#include <err.h>
#include <errno.h>
#include <ftw.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <sys/inotify.h>
#include <sys/wait.h>

#include "config.h"

// fairly arbitray values...feel free to change
#define PATH_MAX    1024
#define CMD_MAX     1024
#define MAX_ARGS    64
#define MAX_OPENFD  4
#define MAX_WATCH   512

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

void win(int wd)
{
	char out[PATH_MAX], in[PATH_MAX], path[PATH_MAX], channel[32];
	char *cmd[] = CMD;

	if (wins[wd])
		return;

	strcpy(path, paths[wd]); // stupid basename messing with my strings
	sprintf(channel, "%s> ", basename(path));
	sprintf(out, "%s/out", paths[wd]);
	sprintf(in,  "%s/in",  paths[wd]);

	if ((wins[wd] = fork()) == 0) {
		execvp(cmd[0], cmd);
		err(1, "failed on execvp %s", cmd[0]);
	}
}

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 0;

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

	if (paths[wd][0] == '\0') {
		strcpy(paths[wd], fpath);
		sprintf(out, "%s/out", fpath);
		if (!init && stat(out, &st) == 0)
			win(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;

	while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) {
		if ((wd = find(wins, pid, MAX_WATCH)) > -1)
			wins[wd] = 0;
	}
}

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

	if (argc != 2 || !strcmp(argv[1], "-v")) {
		fprintf(stderr, "Usage: pcw [-v] dir\n");
		fprintf(stderr, "pcw-"VERSION" © Evan Gates\n");
		exit(1);
	}

	if (stat(argv[1], &st) < 0 || !S_ISDIR(st.st_mode))
		errx(1, "%s does not exist or is not a directory", argv[1]);

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

	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 && errno != EINTR)
			warn("failed to read from inotify event queue");

		for (cur = (struct inotify_event *)buf;
			 (char *)cur - buf < len;
			 cur = (struct inotify_event *)((char *)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;
}