pcw / pcw.c

Evan Gates 30b5010 
Evan Gates 1bced3b 
Evan Gates a0b7245 
Evan Gates 40154d1 


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


Evan Gates 18cc4f5 
Evan Gates 994ab1b 
Evan Gates 30b5010 

Evan Gates 994ab1b 


Evan Gates 43beadb 
Evan Gates 994ab1b 

Evan Gates 30b5010 
Evan Gates e3d5d96 





Evan Gates 994ab1b 



Evan Gates 30b5010 

Evan Gates 994ab1b 

Evan Gates 30b5010 



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

Evan Gates 30b5010 
Evan Gates 994ab1b 









Evan Gates 748c4bb 

Evan Gates 994ab1b 

Evan Gates 30b5010 



Evan Gates d1eb0e8 

Evan Gates 30b5010 
Evan Gates 994ab1b 
Evan Gates 30b5010 
Evan Gates 994ab1b 



Evan Gates 30b5010 
Evan Gates 994ab1b 
Evan Gates e3d5d96 







Evan Gates d1eb0e8 




Evan Gates 30b5010 
Evan Gates e3d5d96 


Evan Gates b051045 

Evan Gates e3d5d96 







Evan Gates 55a44e5 
Evan Gates e3d5d96 



Evan Gates b051045 



Evan Gates e3d5d96 

Evan Gates 30b5010 

Evan Gates 2a1b7f6 
Evan Gates d1eb0e8 
Evan Gates 30b5010 

Evan Gates 994ab1b 
Evan Gates 30b5010 
Evan Gates d1eb0e8 









Evan Gates 30b5010 

Evan Gates d1eb0e8 


Evan Gates cbd6462 

Evan Gates 30b5010 



Evan Gates a0b7245 


Evan Gates 30b5010 


Evan Gates cbd6462 
Evan Gates 30b5010 

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


Evan Gates 2a1b7f6 
Evan Gates 30b5010 
Evan Gates cbd6462 
Evan Gates 2792a82 
Evan Gates 994ab1b 






Evan Gates 30b5010 




Evan Gates 633719c 
#include <err.h>
#include <errno.h>
#include <fcntl.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>

// fairly arbitray values...feel free to change
#define PATH_MAX    256
#define MAX_OPENFD  4

struct watch {
	int wd;
	pid_t pid;
	char *path;
	struct watch *next;
};

static int  add_dir(const char *fpath, const struct stat *sb, int typeflag);
static void sigchld(int unused);
static void sigusr(int unused);
static void usage(void);
static void win(struct watch *w);

static struct watch *watches = NULL;
static int evq;
static char *nick = "";

int add_dir(const char *fpath, const struct stat *sb, int typeflag)
{
	int wd;
	struct watch *w;

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

	for (w = watches; w; w = w->next)
		if (w->wd == wd)
			return 0;

	if ((w = calloc(1, sizeof(struct watch))) == NULL)
		err(1, "error on calloc");

	w->next = watches;
	watches = w;

	w->wd   = wd;
	w->path = strdup(fpath);

	win(w);

	return 0;
}

void sigchld(int unused)
{
	pid_t pid;
	struct watch *w;

	while ((pid = waitpid(-1, NULL, WNOHANG)) > 0)
		for (w = watches; w; w = w->next)
			if (w->pid == pid)
				w->pid = 0;
}

void sigusr(int unused)
{
	struct watch *w;

	for (w = watches; w; w = w->next)
		win(w);
}

void usage(void)
{
	fprintf(stderr, "Usage: pcw [-n nick] [-v] dir\n");
	exit(1);
}

void win(struct watch *w)
{
	int fd = 0;
	char out[PATH_MAX], in[PATH_MAX];
	char *cmd[] = { "pcw_win.sh", w->path, out, in, nick, NULL };

	if (w->pid)
		return;

	sprintf(out, "%s/out", w->path);
	sprintf(in,  "%s/in",  w->path);

	// open() to see if ii has the fifo open for reading
	if (access(out, F_OK) < 0 || access(in, F_OK) < 0 || (fd = open(in, O_WRONLY | O_NONBLOCK)) < 0)
		return;

	close(fd);

	if ((w->pid = fork()) == 0) {
		execvp(cmd[0], cmd);
		err(1, "failed on execvp %s", cmd[0]);
	}
}

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

	for (i = 1; i < argc; i++) {
		if (argv[i][0] != '-')
			break;
		if (argv[i][2] != '\0')
			usage();
		switch (argv[i][1]) {
			case 'n' : nick = argv[++i]; break;
			case 'v' : printf("pcw-"VERSION" © Evan Gates\n"); exit(1);
			default  : usage();
		}
	}

	if (i >= argc)
		usage();

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

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

	if (signal(SIGUSR1, sigusr) == SIG_ERR)
		err(1, "failed installing SIGUSR1 handler");

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

	ftw(argv[i], add_dir, MAX_OPENFD);

	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[i], add_dir, MAX_OPENFD);
			if (cur->mask & (IN_CREATE | IN_MODIFY) && (!strcmp(cur->name, "out") || !strcmp(cur->name, "in"))) {
				for (w = watches; w; w = w->next) {
					if (w->wd == cur->wd) {
						win(w);
						break;
					}
				}
			}
		}
	}

	return 0;
}

/* vim: set ts=4 sw=4 noexpandtab: */
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.