Source

pcw-bsd / pcw.c

Full commit
#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/param.h>

#ifdef __linux__
#define HAVE_INOTIFY
#include <sys/inotify.h>
#include <sys/wait.h>
#endif

#ifdef BSD
#define HAVE_KQUEUE
#endif

#ifndef HAVE_INOTIFY
#ifndef HAVE_KQUEUE
#error "Either inotify or kqueue is required for pcw to function"
#endif
#endif

#include "config.h"

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

typedef struct watch_t watch_t;
struct watch_t {
	int pid;
	char *path;
	watch_t *next;
#ifdef HAVE_INOTIFY
	int wd;
#endif
};

watch_t *watch = NULL;

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

/*
void spawn_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]);
	}
} */

void spawn_win(watch_t *w)
{
	
}

#ifdef HAVE_INOTIFY
int add_dir_inotify(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)
			spawn_win(wd);
	}*/

	char out[PATH_MAX];
	struct stat st;
	watch_t *w;
	int wd;

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

	for(w = watch; w; w = w->next) {
		if (w->wd == wd) {
			if(!w->path) {
				w->path = strdup(fpath);
				snprintf(out,sizeof(out),"%s/out",fpath);
				if(!init && stat(out, &st) == 0)
					spawn_win(w);
			}
			break;
		}
		if (w->next == NULL) {
			w->next = malloc(sizeof(watch_t));
			w->next->wd = wd;
		}
	}
	return 0;
}
#endif

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

#ifdef HAVE_INOTIFY
void run_inotify(char *dir)
{
	char buf[4096];
	int len;
	struct inotify_event *cur;
	watch *w;

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

	init = 1;
	ftw(dir, add_dir_inotify, 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(dir, add_dir_inotify, MAX_OPENFD);
			if (cur->mask & (IN_CREATE | IN_MODIFY) && !strcmp(cur->name, "out"))
				spawn_win(cur->wd);
		}
	}
}
#endif

#ifdef HAVE_KQUEUE
void run_kqueue()
{
}
#endif

int main(int argc, char **argv)
{
	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");

	return 0;
}