(I couldn't find the patches separately in, e.g., a bug report.) Patches by Nicolas Boullis <boullis.nico...@libertysurf.fr>.
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 wmaker-dev-unsubscr...@lists.windowmaker.org.