Source

pcw / pcw.c

Full commit
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 a0b7245 
Evan Gates 468111c 
Evan Gates 18cc4f5 
Evan Gates 994ab1b 
Evan Gates 30b5010 

Evan Gates 994ab1b 





Evan Gates 30b5010 
Evan Gates 994ab1b 




Evan Gates 30b5010 
Evan Gates 994ab1b 
Evan Gates 9c22727 
Evan Gates a0b7245 
Evan Gates 994ab1b 
Evan Gates 30b5010 
Evan Gates 994ab1b 
Evan Gates 30b5010 

Evan Gates 994ab1b 

Evan Gates 30b5010 
Evan Gates 994ab1b 








Evan Gates 9c22727 

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 30b5010 



Evan Gates 994ab1b 

Evan Gates 30b5010 
Evan Gates 994ab1b 

Evan Gates a0b7245 

Evan Gates d1eb0e8 

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



Evan Gates 30b5010 
Evan Gates 994ab1b 
Evan Gates d1eb0e8 




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 994ab1b 







Evan Gates 30b5010 



#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>

#include "config.h" // for CMD

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

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

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

void win(struct watch *w)
{
	int fd = 0;
	char out[PATH_MAX], in[PATH_MAX], path[PATH_MAX], channel[32];
	char *cmd[] = CMD; // from config.h
	struct stat st;

	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 (stat(out, &st) < 0 || stat(in, &st) < 0 || (fd = open(in, O_WRONLY | O_NONBLOCK)) < 0)
		return;

	close(fd);
	strcpy(path, w->path); // stupid basename messing with my strings
	snprintf(channel, sizeof(channel), "%s> ", basename(path));

	if ((w->pid = 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;
	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;
	strcpy(w->path, fpath);

	win(w);

	return 0;
}

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

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

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 usage(void)
{
	fprintf(stderr, "Usage: pcw [-n nick] [-v] dir\n");
	exit(1);
}

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")) {
				for (w = watches; w; w = w->next) {
					if (w->wd == cur->wd) {
						win(w);
						break;
					}
				}
			}
		}
	}

	return 0;
}