[PATCH 07/16] wmtv: Remaining changes from debian package versions 0.6.5-8 through 13.

Doug Torrance <[email protected]>
Newsgroups gmane.compw.window-managers.windowmaker.devel
Message-ID <[email protected]>
(I couldn't find the patches separately in, e.g., a bug report.)

Patches by Nicolas Boullis <[email protected]>.

Corresponding entries from debian/changelog:

0.6.5-8
=======
  * Drop privileges to access files, and then regain privileges.
    (Closes: #120825)
  * A new user's configuration file is automatically created when needed.
  * Cleaned up a few possible buffer overflows.

0.6.5-9
=======
  * The program does not need any more to be setuid root.
    (Closes: #120832)

0.6.5-10
========
  * Trying to change channel while the TV is off does nothing, and does
    not segfault anymore.
  * Corrected strange behavior when the mouse was moved out of a pressed
    button.

0.6.5-11
========
  * Corrected a bug introduced in version 0.6.5-9, causing the program to
    segfault while reverting from fullscreen back to normal mode.
    (Closes: #128409)

0.6.5-12
========
  * Catch SIGCHLD signals to remove zombies. (Closes: #129435)

0.6.5-13
========
  * Added missing #include in wmtv.c.
  * Automatically restarts the TV when the external application finishes.
  * In fullscreen mode, the left and right arrow keys now behave as
    specified in the README file and in the manpage. (Closes: #133301)
  * Added the ability to pass some parameters to the external
    application.
---
 wmtv/src/wmtv.c | 240 ++++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 190 insertions(+), 50 deletions(-)

diff --git a/wmtv/src/wmtv.c b/wmtv/src/wmtv.c
index fd482eb..8a06cfe 100644
--- a/wmtv/src/wmtv.c
+++ b/wmtv/src/wmtv.c
@@ -29,6 +29,7 @@
 #include <fcntl.h>
 #include <time.h>
 #include <errno.h>
+#include <signal.h>
 #include <sys/ioctl.h>
 #include <sys/mman.h>
 #include <sys/types.h>
@@ -82,6 +83,9 @@
 #define COMPOSITE   1
 #define SVIDEO		2
 
+#ifndef GLOBALCONFFILE
+#define GLOBALCONFFILE "/etc/wmtvrc"
+#endif
 
 /* Global Variables */
 int tfd;
@@ -111,6 +115,8 @@ int dcret;
 int tml;
 int fswidth = 0;
 int fsheight = 0;
+pid_t child_pid = -1;
+int restart = FALSE;
 
 unsigned long ccrfreq;
 unsigned long rfreq;
@@ -127,6 +133,9 @@ long ftune[MAXCHAN];
 char *progname;
 char *dev = "/dev/video";
 
+char *sysConfFile = GLOBALCONFFILE;
+char *usrConfFile;
+
 int  wmtv_mask_width = 64;
 int  wmtv_mask_height = 64;
 char wmtv_mask_bits[64*64];
@@ -195,21 +204,89 @@ void GrabImage(void);
 
 void ParseRCFile(const char *, rckeys *);
 void ParseRCFile2(const char *);
-void WriteRCFile(const char *);
+void WriteRCFile(const char *, rckeys *);
 void InitConfig(void);
 void InitPalette(void);
 
 void Usage(void);
 void Version(void);
 
+void
+sigchld_handler(int i)
+{
+	pid_t pid;
+	pid = waitpid((pid_t)-1, NULL, WNOHANG);
+	while (pid>(pid_t)0) {
+		if (pid == child_pid) {
+			child_pid = -1;
+			restart = TRUE;
+		}
+		pid = waitpid((pid_t)-1, NULL, WNOHANG);
+	}
+}
+
+void
+init_signal()
+{
+	struct sigaction sa;
+
+	sa.sa_handler = &sigchld_handler;
+	sigemptyset(&sa.sa_mask);
+	sa.sa_flags = SA_RESTART;
+	sigaction(SIGCHLD, &sa, NULL);
+}
+
+char *
+expand_format(char *format, char *letters, char **expansions)
+{
+	char *string;
+	unsigned int string_pos = 0;
+	unsigned int size;
+	size = strlen(format)+1;
+	string = (char *)malloc(size*sizeof(char));
+	for (; *format != '\0'; format++) {
+		if (*format == '%') {
+			format++;
+			if (*format != '%') {
+				unsigned int i;
+				for (i = 0; letters[i] != '\0'; i++) {
+					if (letters[i] == *format)
+						break;
+				}
+				if (letters[i] != '\0') {
+					unsigned int expansion_size;
+					expansion_size = strlen(expansions[i]);
+					while (string_pos+expansion_size+1 > size) {
+						size *= 2;
+						string = realloc(string, size*sizeof(char));
+					}
+					memcpy(string+string_pos, expansions[i], expansion_size);
+					string_pos += expansion_size;
+					continue;
+				}
+				else {
+					format--;
+				}
+			}
+		}
+		while (string_pos+1+1 > size) {
+			size *= 2;
+			string = realloc(string, size*sizeof(char));
+		}
+		string[string_pos] = *format;
+		string_pos++;
+	}
+	string[string_pos] = '\0';
+	return string;
+}
 
 /* main function */
 int
 main(int argc, char *argv[])
 {
-	int i, c, opind;
+	int c, opind;
+	int pressed_button = -1;
 	/* pid_t pid; */
-	char cfile[128];
 	static struct option long_options[] = {
 		{"display", 1, 0, 'd'},
 		{"geometry", 1, 0, 'g'},
@@ -222,8 +299,18 @@ main(int argc, char *argv[])
 
 	progname = strdup(argv[0]);
 
-	strncpy(cfile, (char *)getenv("HOME"), sizeof(char)*128);
-	strcat(cfile, "/.wmtvrc");
+	{
+		char *home = getenv("HOME");
+
+		if (home == NULL) {
+			fprintf(stderr, "wmtv: $HOME should be set.\n");
+			exit(1);
+		}
+
+		usrConfFile = (char *)malloc(sizeof(char)*(strlen(home)+8+1));
+		strcpy(usrConfFile, home);
+		strcat(usrConfFile, "/.wmtvrc");
+	}
 
 	while (1) {
 		opind = 0;
@@ -277,9 +364,21 @@ main(int argc, char *argv[])
 	AddMouseRegion (SCANRB, 35, 48, 47, 59); 	/* Right Preset/Scan Button */
 	AddMouseRegion (FULLSB, 5, 5, 59, 44);		/* Toggle FullScreen */
 
+	init_signal();
+
 	/* wmtv main loop */
 	while (1)
 	{
+		if (restart) {
+			TVOn();
+			if (ntfb_status == SETOFF) {
+				ntfb_status = SETON;
+				RedrawWindow();
+				XFlush(display);
+			}
+			restart = FALSE;
+			continue;
+		}
 		while (XPending(display))
 		{
 			XNextEvent(display, &Event);
@@ -302,8 +401,8 @@ main(int argc, char *argv[])
 						RetScreen();
 					}
 					else {
-					i = CheckMouseRegion (Event.xbutton.x, Event.xbutton.y);
-					switch (i) {
+					pressed_button = CheckMouseRegion (Event.xbutton.x, Event.xbutton.y);
+					switch (pressed_button) {
 						case NTFB:
 							ButtonDown(NTFB);
 							t_lc = Event.xbutton.time;
@@ -325,7 +424,7 @@ main(int argc, char *argv[])
 										break;
 								}
 							}
-							else
+							else if (ntfb_status == SETON)
 									ChanDown();
 							break;
 						case SCANRB:
@@ -344,7 +443,7 @@ main(int argc, char *argv[])
 										break;
 								}
 							}
-							else
+							else if (ntfb_status == SETON)
 									ChanUp();
 							break;
 						case FULLSB:
@@ -371,8 +470,7 @@ main(int argc, char *argv[])
 					}
 					break;
 				case ButtonRelease:
-					i = CheckMouseRegion (Event.xbutton.x, Event.xbutton.y);
-					switch (i) {
+					switch (pressed_button) {
 						case NTFB:
 							ButtonUp(NTFB);
 								if (but_pressed) {
@@ -383,9 +481,11 @@ main(int argc, char *argv[])
 								}
 
 								if (ntfb_status == SETOFF) {
+									if (child_pid == -1) {
 										ntfb_status = SETON;
 										TVOn();
 								}
+								}
 								else if (ntfb_status == SETON) {
 										if (!btime) {
 										ntfb_status = SETUNE;
@@ -403,7 +503,7 @@ main(int argc, char *argv[])
 										if (!btime) {
 											ftune[cchannel] = (rfreq - ccrfreq);
 											/* fprintf(stderr, "wmtv: finetune offset = %ld\n", ftune[cchannel]); */
-											WriteRCFile(cfile);
+											WriteRCFile(usrConfFile, wmtv_keys);
 											ntfb_status = SETON;
 											DrawPresetChan(cchannel);
 										}
@@ -437,19 +537,39 @@ main(int argc, char *argv[])
 											{
 												if ((ntfb_status == SETON) || (ntfb_status == SETUNE)) {
 													if (exe) {
+														pid_t pid;
+														char *command;
+														char *letters = "#nf";
+														char *(expansions[3]);
 														ntfb_status = SETOFF;
 														TVOff();
+														expansions[0] = malloc(3*sizeof(char));
+														snprintf(expansions[0], 3, "%d", cchannel+1);
+														expansions[1] = comment[cchannel];
+														expansions[2] = malloc(15*sizeof(char));
+														snprintf(expansions[2], 15, "%ld", rfreq);
+														command = expand_format(exe, letters, expansions);
 														/* system(exe); */
-														if (fork() == (pid_t) 0) {
+														child_pid = fork();
+														if (child_pid == (pid_t) 0) {
 														char *argv[4];
-														setuid(getuid()); /* Drop the privileges */
 														argv[0] = "sh";
 														argv[1] = "-c";
-														argv[2] = exe;
+															argv[2] = command;
 														argv[3] = NULL;
 														execv("/bin/sh", argv);
 														exit(-1);
 														}
+														free(expansions[0]);
+														free(expansions[2]);
+														free(command);
+														pid = waitpid(child_pid, NULL, WNOHANG);
+														if (pid != 0) {
+															child_pid = -1;
+															restart = TRUE;
+														}
+														/* printf("Returned pid:\n"); */
+
 #if 0
 														pid = fork();
 
@@ -554,12 +674,10 @@ main(int argc, char *argv[])
 									ChanDown();
 									break;
 								case XK_Right:
-									if (isource == TELEVISION)
-									FineTuneUp();
+									VolumeUp();
 									break;
 								case XK_Left:
-									if (isource == TELEVISION)
-									FineTuneDown();
+									VolumeDown();
 									break;
 								case XK_m:
 									if (!mute) {
@@ -642,7 +760,6 @@ TVOn(void)
 	int rx, ry;
 	char *p;
 
-
 	XWindowAttributes winattr;
 
 	if (!XGetWindowAttributes (display, iconwin, &winattr)) {
@@ -656,6 +773,18 @@ TVOn(void)
 		fprintf(stderr, "wmtv: error translating coordinates\n");
 	}
 
+	/* This part was taken from xawtv's source code */
+	switch (system("v4l-conf -q")) {
+	case -1: /* can't run */
+		fprintf(stderr,"could'nt start v4l-conf\n");
+		break;
+	case 0: /* ok */
+		break;
+	default: /* non-zero return */
+		fprintf(stderr,"v4l-conf had some trouble, "
+				"trying to continue anyway\n");
+	}
+	/* End of "stolen" part */
 	InitConfig();
 	GetFrameBuffer();
 	InitPalette();
@@ -716,7 +845,7 @@ TVOn(void)
 
 		if (vaud.flags & VIDEO_AUDIO_MUTE) {
 			vaud.flags &= ~VIDEO_AUDIO_MUTE; 	/* Unmute */
-			vaud.volume = (0xFFFF/2)+1;
+			vaud.volume = 0xFFFF;
 		}
 
 	if (isource == TELEVISION) {
@@ -787,9 +916,11 @@ void
 VolumeUp(void)
 {
 	if(vchn.flags & VIDEO_VC_AUDIO) {
-		if (vaud.volume <= 0xFFFF) {
+		if ((vaud.flags & VIDEO_AUDIO_VOLUME) == 0)
+			fprintf(stderr, "Warning: v4l device does not support volume control.\n");
+		else if (vaud.volume <= 0xEEEE) {
 			vaud.audio = tvsource;
-			vaud.volume += (0xFFFF/10);
+			vaud.volume += 0x1111;
 			if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
 				perror("ioctl VIDIOCSAUDIO");
 		}
@@ -802,9 +933,11 @@ void
 VolumeDown(void)
 {
 	if (vchn.flags & VIDEO_VC_AUDIO) {
-		if (vaud.volume > 0) {
+		if ((vaud.flags & VIDEO_AUDIO_VOLUME) == 0)
+			fprintf(stderr, "Warning: v4l device does not support volume control.\n");
+		else if (vaud.volume >= 0x1111) {
 			vaud.audio = tvsource;
-			vaud.volume -= (0xFFFF/10);
+			vaud.volume -= 0x1111;
 			if (ioctl(tfd, VIDIOCSAUDIO, &vaud) < 0)
 				perror("ioctl VIDIOCSAUDIO");
 		}
@@ -1038,8 +1171,16 @@ ParseRCFile2(const char *filename)
 			if (menu) {
 				ftune[i]=0;
 				if(sscanf(temp, " %s %n(%ld) %n", name, &len, &ftune[i], &len)>=1) {
+					char *pos;
 					cname[i]=strdup(name);
-					comment[i]=temp[len]?strdup(temp+len):"\n";
+					comment[i]=temp[len]?strdup(temp+len):"";
+					/* Remove the end-of-line symbol */
+					for (pos = comment[i]; *pos != '\0'; pos++) {
+						if (*pos == '\n') {
+							*pos = '\0';
+							break;
+						}
+					}
 				}
 				if(++i>=MAXCHAN)
 					break;
@@ -1056,28 +1197,27 @@ ParseRCFile2(const char *filename)
 
 /* WriteRCFile function */
 void
-WriteRCFile(const char *filename)
+WriteRCFile(const char *filename, rckeys *keys)
 {
 	long i;
-	char temp[128];
 	FILE *fp;
+	int key;
 
-	if ((fp = fopen(filename, "r+")) == NULL) {
+	if ((fp = fopen(filename, "w")) == NULL) {
 		fprintf(stderr, "wmtv: %s\n", strerror(errno));
 		return;
 	}
 
-	while (fgets(temp, 128, fp)) {
-		if (*temp != '\n' && strchr(temp, '[')) {
-			fseek(fp, 0L, SEEK_CUR);	/* required between read and write */
+	for (key=0; keys[key].label; key++)
+		if (*keys[key].var)
+			fprintf(fp, "%s = %s\n", keys[key].label, *keys[key].var);
+
+	fprintf(fp, "\n[channel]\n");
+
 			for (i = 0; i <= maxpst; i++)
-				fprintf(fp, "%s (%ld)\t%s", cname[i], ftune[i], comment[i]);
-			break;
-		}
-	}
-	i=ftell(fp);
+		fprintf(fp, "%s (%ld)\t%s\n", cname[i], ftune[i], comment[i]);
+
 	fclose(fp);
-	truncate(filename, i);
 }
 
 
@@ -1128,17 +1268,13 @@ void
 InitConfig(void)
 {
 	int i;
-	char temp[128];
 
-	strncpy(temp, (char *)getenv("HOME"), (sizeof(char)*128));
-	strcat(temp, "/.wmtvrc");
-	ParseRCFile(temp, wmtv_keys);
-	ParseRCFile2(temp);
+	ParseRCFile(usrConfFile, wmtv_keys);
+	ParseRCFile2(usrConfFile);
 
 	if (norcfile) {
-		strcpy(temp, "/etc/wmtvrc");
-		ParseRCFile(temp, wmtv_keys);
-		ParseRCFile2(temp);
+		ParseRCFile(sysConfFile, wmtv_keys);
+		ParseRCFile2(sysConfFile);
 
 		if (norcfile) {
 			fprintf(stderr, "wmtv: error - config file not found\n");
@@ -1272,17 +1408,20 @@ InitConfig(void)
 void
 GetFrameBuffer(void)
 {
+#if 0
 	void *baseaddr = NULL;
 	int evbr, erbr, flr = 0;
 	int bankr, memr, depth;
 	int i, n;
-	int bytesperline, bytesperpixel;
+	int bytesperline, bitsperpixel;
 	XPixmapFormatValues *pf;
+#endif
 
 	if (!XGetWindowAttributes(display, DefaultRootWindow(display), &Winattr)) {
 		fprintf(stderr, "wmtv: error getting winattr of root\n");
 	}
 
+#if 0
 	depth = Winattr.depth;
 
 	if (XF86DGAQueryExtension(display, &evbr, &erbr)) {
@@ -1306,13 +1445,13 @@ GetFrameBuffer(void)
 			}
 	}
 
-	bytesperpixel = (depth+7) & 0xf8;
-	bytesperline *= bytesperpixel;
+	bitsperpixel = (depth+7) & 0xf8;
+	bytesperline *= bitsperpixel/8;
 
 	vfb.base = baseaddr;
 	vfb.height = Winattr.height;
 	vfb.width  = Winattr.width;
-	vfb.depth  = bytesperpixel;
+	vfb.depth  = bitsperpixel;
 	vfb.bytesperline = bytesperline;
 
 	if (Winattr.depth == 15)
@@ -1321,6 +1460,7 @@ GetFrameBuffer(void)
 	if (ioctl(tfd, VIDIOCSFBUF, &vfb) < 0) {
 		perror("ioctl VIDIOCSFBUF");
 	}
+#endif
 }
 
 
-- 
2.5.0


-- 
To unsubscribe, send mail to [email protected].
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.