C
fswebcam flock & src_open Patch
June 8, 2013, 9:08 p.m.

Ein Patch für fswebcam.
Es wird unter Verwendung von flock() verhindert, dass noch nicht vollständig auf Platte geschriebene Bilder auf der Webseite angezeigt werden. flock() muss ebenfalls im jeweiligen Script verwendet werden, welches die Bilddatei ausliefert (PHP, CGI etc.).
Zusätzlich wird die Webcam nur noch einmal geöffnet, sollte fswebcam im loop Modus betrieben werden.

                    December 2012 tuxwave.net
Sebastian Kricner

Implement file locking with flock() syscall.
This is to prevent delivery of broken images for live webcams.
This also needs a flock() LOCK_SH call in the script (PHP, CGI etc.) which delivers
the webcam image.

Additionally open the webcam only once when using the loop mode of fswebcam.

diff -rupN fswebcam-20110717.orig//fswebcam.c fswebcam-20110717/fswebcam.c
--- fswebcam-20110717.orig//fswebcam.c	2011-07-17 14:27:16.000000000 +0200
+++ fswebcam-20110717/fswebcam.c	2013-02-25 18:08:03.302774107 +0100
@@ -21,6 +21,7 @@
 #include <errno.h>
 #include <signal.h>
 #include <sys/types.h>
+#include <sys/file.h>
 #include <sys/stat.h>
 #include "fswebcam.h"
 #include "log.h"
@@ -482,8 +483,15 @@ int fswc_output(fswebcam_config_t *confi
 	fswc_draw_overlay(config, config->overlay, im);
 	
 	/* Write to a file if a filename was given, otherwise stdout. */
-	if(strncmp(name, "-", 2)) f = fopen(filename, "wb");
-	else f = stdout;
+	if(strncmp(name, "-", 2))
+	{
+		f = fopen(filename, "wb");
+		flock(fileno(f), LOCK_EX);
+	}
+	else
+	{
+		f = stdout;
+	}
 	
 	if(!f)
 	{
@@ -506,7 +514,12 @@ int fswc_output(fswebcam_config_t *confi
 		break;
 	}
 	
-	if(f != stdout) fclose(f);
+	if(f != stdout)
+	{
+		fflush(f);
+		flock(fileno(f), LOCK_UN);
+		fclose(f);
+	}
 	
 	gdImageDestroy(im);
 	
@@ -557,29 +570,41 @@ int fswc_grab(fswebcam_config_t *config)
 	avgbmp_t *abitmap, *pbitmap;
 	gdImage *image, *original;
 	uint8_t modified;
-	src_t src;
+
+	static src_t src;
+    static uint8_t src_assigned = 0;
 	
 	/* Record the start time. */
 	config->start = time(NULL);
 	
 	/* Set source options... */
-	memset(&src, 0, sizeof(src));
-	src.input      = config->input;
-	src.tuner      = config->tuner;
-	src.frequency  = config->frequency;
-	src.delay      = config->delay;
-	src.timeout    = 10; /* seconds */
-	src.use_read   = config->use_read;
-	src.list       = config->list;
-	src.palette    = config->palette;
-	src.width      = config->width;
-	src.height     = config->height;
-	src.fps        = config->fps;
-	src.option     = config->option;
-	
-	HEAD("--- Opening %s...", config->device);
-	
-	if(src_open(&src, config->device) == -1) return(-1);
+    if(!src_assigned)
+    {
+        memset(&src, 0, sizeof(src));
+        src.input      = config->input;
+        src.tuner      = config->tuner;
+        src.frequency  = config->frequency;
+        src.delay      = config->delay;
+        src.timeout    = 10; /* seconds */
+        src.use_read   = config->use_read;
+        src.list       = config->list;
+        src.palette    = config->palette;
+        src.width      = config->width;
+        src.height     = config->height;
+        src.fps        = config->fps;
+        src.option     = config->option;
+    }
+	
+	
+    if(!src_assigned)
+    {
+        HEAD("--- Opening %s...", config->device);
+        if(src_open(&src, config->device) == -1)
+        {
+            return(-1);
+        }
+        src_assigned = 1;
+    }
 	
 	/* The source may have adjusted the width and height we passed
 	 * to it. Update the main config to match. */
@@ -684,7 +709,10 @@ int fswc_grab(fswebcam_config_t *config)
 	}
 	
 	/* We are now finished with the capture card. */
-	src_close(&src);
+    if(!config->loop || !frame)
+    {
+        src_close(&src);
+    }
 	
 	/* Fail if no frames where captured. */
 	if(!frame)

                    
        
Download
Multi File Monitor
Nov. 12, 2012, 4:30 a.m.

Ein C Programm mit ncurses, welches mehrere Logfiles gleichzeitig anzeigt.
Mit Aktivitätsüberwachung.

                    /*
 * 	Multi File Monitor
 * 	Sebastian Kricner
 * 	tuxwave.net 
 * 	February 2011
 *
 * 	Description:
 * 	This is a monitor for usual textfiles like logfiles.
 * 	It monitors multiple files using ncurses and inotify.
 * 	Use down+up arrows for selecting files and q for quitting.
 *
 * 	Compiling:
 * 	gcc multifilemon.c -o multifilemon -lncurses -lpthread
 *
 * 	Why this?
 * 	It was for coding practice.
 * 	This program can still be optimized and extended :)
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <fcntl.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include <curses.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>

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

static void usage(char *name);
static void init_windows(void);
static void interaction(void);

static void *filewatch(void* arg);
static void *logfilewatch(void *arg);

void sigint_handler(int sig);
void sigwinch_handler(int sig);

char **arguments;
int *argcount, curfile,  threads_created;
WINDOW *filewindow, *sub_filewindow, *logwindow, *sub_logwindow, *infowindow, *sub_infowindow;
pthread_t logfilewatch_thread, filewatch_thread; 

sem_t locker;

int main(int argc, char **argv, char **envp)
{
	int count;
	struct stat statbuf;

	argcount = &argc;	
	arguments = argv;

	curfile = 1;
	threads_created = 0;

	if(argc == 1)
	{
		usage(argv[0]);
	}
	for(count = 1; count < argc; count++)
	{
		if(stat(argv[count], &statbuf) == 0)
		{
			if(!S_ISREG(statbuf.st_mode))
			{
				fprintf(stderr, "Error: No valid file: %s\n", argv[count]);
				usage(argv[0]);
			}
		}
		else
		{
			fprintf(stderr, "Error: No valid file: %s\n", argv[count]);
			usage(argv[0]);
		}
	}
	initscr();
	if(!has_colors() || !isatty(fileno(stdout)))
	{   
		endwin();
		fprintf(stderr, "Error - no color support available\n");
		exit(EXIT_FAILURE);
	} 
	if(start_color() != OK) 
	{   
		endwin();    
		fprintf(stderr, "Could not initialize colors\n");
		exit(EXIT_FAILURE);
	} 
	clear();
	cbreak();
	noecho();
	nonl();
	keypad(stdscr, 1);
	curs_set(0);
	use_default_colors();
	init_pair(1, COLOR_RED, -1);
	init_windows();
	exit(EXIT_SUCCESS);
}

void sigwinch_handler(int sig)
{
	endwin();
	fprintf(stderr, "This application does not support sigwinch-resizing, sorry\n");
	exit(EXIT_SUCCESS);
	return;
}

void sigint_handler(int sig)
{
	pthread_cancel(filewatch_thread);
 	pthread_cancel(logfilewatch_thread);
	endwin();
	exit(EXIT_SUCCESS);
	return;
}

static void usage(char *name)
{
	printf("Usage:\n"
	"%s [files...]\n", name);
	exit(EXIT_FAILURE);
}

static void init_windows(void)
{
	int count, max_y, max_x;
	getmaxyx(stdscr, max_y, max_x);

	filewindow = newwin(max_y-3, max_x/3, 0, 0);
	sub_filewindow = subwin(filewindow, max_y-5, (max_x/3)-2, 1, 1);
	scrollok(sub_filewindow, 1);

	logwindow = newwin(max_y-3, (max_x-(max_x/3)-1), 0, (max_x/3)+1);
	sub_logwindow = subwin(logwindow, max_y-5, max_x-(max_x/3)-3, 1, (max_x/3)+2);
	scrollok(sub_logwindow, 1);

	infowindow = newwin(3, max_x, max_y-3, 0);
	sub_infowindow = subwin(infowindow, 1, max_x-2, max_y-2, 1);

	box(filewindow, 0, 0);
	box(logwindow, 0, 0);
	box(infowindow, 0, 0);

	for(count = 1;count < *argcount;count++)
	{
		wprintw(sub_filewindow, "%s\n", *(arguments+count));
	}

	wprintw(sub_infowindow, "%s", *(arguments+1));

	refresh();
	wrefresh(filewindow);
	wrefresh(logwindow);
	wrefresh(infowindow);
	if(threads_created == 0)
	{
		interaction();
	}
	return;
}

static void interaction(void)
{
	int key;
	sem_init(&locker, 0, 0);

	pthread_create(&filewatch_thread,NULL,filewatch,NULL); 
	pthread_create(&logfilewatch_thread,NULL,logfilewatch,*(arguments+1)); 
	threads_created = 1;
	
	struct sigaction act[2];
	sigfillset(&act[0].sa_mask);
	sigdelset(&act[0].sa_mask, SIGWINCH);
	act[0].sa_handler = sigwinch_handler;
	sigaction(SIGWINCH, &act[0], 0);

	sigfillset(&act[1].sa_mask);
	sigdelset(&act[1].sa_mask, SIGINT);
	act[1].sa_handler = sigint_handler;
	sigaction(SIGINT, &act[1], 0);

	while(1)
	{
		key = getch();
		switch(key)
		{
			case KEY_UP:
					if(curfile > 1)
					{
						if(pthread_cancel(logfilewatch_thread))
						{
							endwin();
							fprintf(stderr, "pthread error\n");
							exit(EXIT_FAILURE);
						}
						curfile--;
						pthread_create(&logfilewatch_thread,NULL,logfilewatch,*(arguments+curfile)); 
					}
			break;
			case KEY_DOWN:
					if(curfile < *argcount-1)
					{
						if(pthread_cancel(logfilewatch_thread))
						{
							endwin();
							fprintf(stderr, "pthread error\n");
							exit(EXIT_FAILURE);
						}
						curfile++;
						pthread_create(&logfilewatch_thread,NULL,logfilewatch,*(arguments+curfile)); 
					}
			break;
			case 'q':
					pthread_cancel(filewatch_thread);
					pthread_cancel(logfilewatch_thread);
					endwin();
					exit(EXIT_SUCCESS);
			break;
		}
	}
	return;
}

static void *filewatch(void* arg)
{
	int inotify_fd, count, icount, len, cur_y, cur_x;
	char inobuf[1024 * (sizeof(struct inotify_event)+16)];

	int res;
	res = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
	if(res != 0)
	{
		wclear(sub_filewindow);
		wprintw(sub_filewindow, "pthread error");
		touchwin(filewindow);
		wrefresh(filewindow);
		pthread_exit(0);
	}
	res = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
	if(res != 0)
        {   
		wclear(sub_filewindow);
		wprintw(sub_filewindow, "pthread error");
		touchwin(filewindow);
		wrefresh(filewindow);
                pthread_exit(0);
        }

	if((inotify_fd = inotify_init()) < 0)
	{
		wclear(sub_filewindow);
		wprintw(sub_filewindow, "inotify error");
		touchwin(filewindow);
		wrefresh(filewindow);
		pthread_exit(0);
	}
	for(count = 1;count < *argcount; count++)
	{
		if((inotify_add_watch(inotify_fd, *(arguments+count), IN_MODIFY)) == -1)
		{
			wclear(sub_filewindow);
			wprintw(sub_filewindow, "inotify error");
			touchwin(filewindow);
			wrefresh(filewindow);
			close(inotify_fd);
			pthread_exit(0);
		}
	}
	while((len = read(inotify_fd, inobuf, sizeof(struct inotify_event))))
	{
		while(icount < len)
		{
			struct inotify_event *event = (struct inotify_event *) &inobuf[icount];
			wclear(sub_filewindow);
			for(count = 1;count < *argcount;count++)
			{
				if(event->wd == count)
				{
					wattrset(sub_filewindow, COLOR_PAIR(1));
					wprintw(sub_filewindow, "%s\n", *(arguments+count));
					wattroff(sub_filewindow, COLOR_PAIR(1));
					if(curfile == count)
					{
						sem_post(&locker);
					}
				}
				else
				{
					wprintw(sub_filewindow, "%s\n", *(arguments+count));
				}
			}
			icount += sizeof(struct inotify_event) + event->len;
		}
		touchwin(filewindow);
		wrefresh(filewindow);
		icount=0;
	}
	pthread_exit(0);
}

static void *logfilewatch(void *arg)
{
	char *file = (char *) arg;
	int logfile, state, character;
	int res;
	res = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
	if(res != 0)
	{
		wclear(sub_logwindow);
		wprintw(sub_logwindow, "pthread error");
		touchwin(logwindow);
		wrefresh(logwindow);
		pthread_exit(0);
	}
	res = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
	if(res != 0)
        {   
		wclear(sub_logwindow);
		wprintw(sub_logwindow, "pthread error");
		touchwin(logwindow);
		wrefresh(logwindow);
                pthread_exit(0);
        }
	wclear(sub_logwindow);
	touchwin(logwindow);
	wrefresh(logwindow);
	wclear(sub_infowindow);
	wprintw(sub_infowindow, "%s", file);
	touchwin(infowindow);
	wrefresh(infowindow);
	logfile = open(file, O_RDONLY);
	if(logfile == -1)
	{
		wprintw(sub_logwindow, "Could not open %s", file);
		touchwin(logwindow);
		wrefresh(logwindow);
		pthread_exit(0);
	}
	lseek(logfile, -1024, SEEK_END);
	while((state = read(logfile, &character, 1)) != -1)
	{
		if(state == 0)
		{
			sem_wait(&locker);
			continue;
		}
		if((char) character == '\n')
		{
			wprintw(sub_logwindow, "%c", character);
			touchwin(logwindow);
			wrefresh(logwindow);
		}
		else
		{
			wprintw(sub_logwindow, "%c", character);
			touchwin(logwindow);
		}
	}
	close(logfile);
	pthread_exit(0);
}

                    
        
Download