summaryrefslogtreecommitdiffstats
path: root/patches/procps-3.2.7/generic/30_watch_exec_beep.dpatch
blob: 4fcd1cbbd3ae8f636468584d3d78d8eb627bf0ab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
#! /bin/sh /usr/share/dpatch/dpatch-run
## 30_watch_exec_beep.dpatch by  <csmall@debian.org>
##
## All lines beginning with `## DP:' are a description of the patch.
## DP: Adds -exec and -beep flags and has better quoting #410967
## DP: Adds -errexit flag now too #183346

@DPATCH@
diff -urNad procps-3.2.7~/watch.1 procps-3.2.7/watch.1
--- procps-3.2.7~/watch.1	2009-01-11 12:11:47.000000000 +1100
+++ procps-3.2.7/watch.1	2009-01-11 12:18:31.000000000 +1100
@@ -1,13 +1,16 @@
-.TH WATCH 1 "1999 Apr 3" " " "Linux User's Manual"
+.TH WATCH 1 "2008 Jan 8" " " "Linux User's Manual"
 .SH NAME
 watch \- execute a program periodically, showing output fullscreen
 .SH SYNOPSIS
 .na
 .B watch
-.RB [ \-dhvt ]
+.RB [ \-bdehvtx ]
 .RB [ \-n
 .IR seconds ]
+.RB [ \-\-beep ]
 .RB [ \-\-differences[=\fIcumulative\fP]]
+.RB [ \-\-errexit ]
+.RB [ \-\-exec ]
 .RB [ \-\-help ]
 .RB [ \-\-interval=\fIseconds\fP]
 .RB [ \-\-no\-title ]
@@ -17,7 +20,8 @@
 .B watch
 runs
 .I command
-repeatedly, displaying its output (the first screenfull).  This allows you to
+repeatedly, displaying its output and errors (the first screenfull).  This 
+allows you to
 watch the program output change over time.  By default, the program is run
 every 2 seconds; use 
 .B \-n
@@ -37,15 +41,33 @@
 or
 .B \-\-no\-title
 option turns off the header showing the interval, command, and current
-time at the top of the display, as well as the following blank line.
+time at the top of the display, as well as the following blank line.  The
+.I \-b
+or 
+.I \-\-beep
+option causes the command to beep if it has a non-zero exit.
 .PP
 .B watch
-will run until interrupted.
+will normally run until interrupted. If you want
+.B watch
+to exit on an error from the program running use the
+.I \-e
+or
+.I \-\-errexit
+options, which will cause 
+.B watch
+to exit if the return value from the program is non-zero.
+
 .SH NOTE
 Note that
 .I command
 is given to "sh \-c"
 which means that you may need to use extra quoting to get the desired effect.
+You can disable this with the 
+.I -x
+or 
+.I --exec
+option, which passes the command to exec(2) instead.
 .PP
 Note that POSIX option processing is used (i.e., option processing stops at
 the first non\-option argument).  This means that flags after
@@ -93,4 +115,5 @@
 .B watch
 was written by Tony Rems <rembo@unisoft.com> in 1991, with mods and
 corrections by Francois Pinard.  It was reworked and new features added by
-Mike Coleman <mkc@acm.org> in 1999.
+Mike Coleman <mkc@acm.org> in 1999.  The beep, exec, and error handling 
+features were added by Morty Abzug <morty@frakir.org> in 2008.
diff -urNad procps-3.2.7~/watch.c procps-3.2.7/watch.c
--- procps-3.2.7~/watch.c	2009-01-11 12:11:47.000000000 +1100
+++ procps-3.2.7/watch.c	2009-01-11 12:21:50.000000000 +1100
@@ -8,6 +8,7 @@
  * Mike Coleman <mkc@acm.org>.
  *
  * Changes by Albert Cahalan, 2002-2003.
+ * stderr handling, exec, and beep option added by Morty Abzug, 2008
  */
 
 #define VERSION "0.2.0"
@@ -35,13 +36,16 @@
 	{"differences", optional_argument, 0, 'd'},
 	{"help", no_argument, 0, 'h'},
 	{"interval", required_argument, 0, 'n'},
+	{"beep", no_argument, 0, 'b'},
+	{"errexit", no_argument, 0, 'e'},
+	{"exec", no_argument, 0, 'x'},
 	{"no-title", no_argument, 0, 't'},
 	{"version", no_argument, 0, 'v'},
 	{0, 0, 0, 0}
 };
 
 static char usage[] =
-    "Usage: %s [-dhntv] [--differences[=cumulative]] [--help] [--interval=<n>] [--no-title] [--version] <command>\n";
+    "Usage: %s [-bdhntvx] [--beep] [--differences[=cumulative]] [--exec] [--help] [--interval=<n>] [--no-title] [--version] <command>\n";
 
 static char *progname;
 
@@ -140,28 +144,44 @@
 	int optc;
 	int option_differences = 0,
 	    option_differences_cumulative = 0,
+			option_exec = 0,
+			option_beep = 0,
+        option_errexit = 0,
 	    option_help = 0, option_version = 0;
 	double interval = 2;
 	char *command;
+	char **command_argv;
 	int command_length = 0;	/* not including final \0 */
+	int pipefd[2];
+	int status;
+	pid_t child;
 
 	setlocale(LC_ALL, "");
 	progname = argv[0];
 
-	while ((optc = getopt_long(argc, argv, "+d::hn:vt", longopts, (int *) 0))
+	while ((optc = getopt_long(argc, argv, "+bed::hn:vtx", longopts, (int *) 0))
 	       != EOF) {
 		switch (optc) {
+		case 'b':
+			option_beep = 1;
+			break;
 		case 'd':
 			option_differences = 1;
 			if (optarg)
 				option_differences_cumulative = 1;
 			break;
+        case 'e':
+            option_errexit = 1;
+            break;
 		case 'h':
 			option_help = 1;
 			break;
 		case 't':
 			show_title = 0;
 			break;
+		case 'x':
+		  option_exec = 1;
+			break;
 		case 'n':
 			{
 				char *str;
@@ -191,18 +211,23 @@
 
 	if (option_help) {
 		fprintf(stderr, usage, progname);
+		fputs("  -b, --beep\t\t\t\tbeep if the command has a non-zero exit\n", stderr);
 		fputs("  -d, --differences[=cumulative]\thighlight changes between updates\n", stderr);
 		fputs("\t\t(cumulative means highlighting is cumulative)\n", stderr);
+		fputs("  -e, --errexit\t\t\t\texit watch if the command has a non-zero exit\n", stderr);
 		fputs("  -h, --help\t\t\t\tprint a summary of the options\n", stderr);
 		fputs("  -n, --interval=<seconds>\t\tseconds to wait between updates\n", stderr);
 		fputs("  -v, --version\t\t\t\tprint the version number\n", stderr);
 		fputs("  -t, --no-title\t\t\tturns off showing the header\n", stderr);
+		fputs("  -x, --exec\t\t\t\tpass command to exec instead of sh\n", stderr);
 		exit(0);
 	}
 
 	if (optind >= argc)
 		do_usage();
 
+	command_argv=&(argv[optind]); /* save for later */
+
 	command = strdup(argv[optind++]);
 	command_length = strlen(command);
 	for (; optind < argc; optind++) {
@@ -261,11 +286,57 @@
 			free(header);
 		}
 
-		if (!(p = popen(command, "r"))) {
-			perror("popen");
+		/* allocate pipes */
+		if (pipe(pipefd)<0) {
+		  perror("pipe");
+			do_exit(7);
+	  }
+
+		/* flush stdout and stderr, since we're about to do fd stuff */
+		fflush(stdout);
+		fflush(stderr);
+
+		/* fork to prepare to run command */
+		child=fork();
+
+		if (child<0) { /* fork error */
+		  perror("fork");
 			do_exit(2);
+		} else if (child==0) { /* in child */
+			close (pipefd[0]); /* child doesn't need read side of pipe */
+			close (1); /* prepare to replace stdout with pipe */
+			if (dup2 (pipefd[1], 1)<0) { /* replace stdout with write side of pipe */
+			  perror("dup2");
+				exit(3);
+			}
+			dup2(1, 2); /* stderr should default to stdout */
+
+			if (option_exec) { /* pass command to exec instead of system */
+			  if (execvp(command_argv[0], command_argv)==-1) {
+				  perror("exec");
+				  exit(4);
+				}
+			} else {
+		    status=system(command); /* watch manpage promises sh quoting */
+
+			  /* propagate command exit status as child exit status */
+			  if (!WIFEXITED(status)) { /* child exits nonzero if command does */
+			    exit(1);
+			  } else {
+			    exit(WEXITSTATUS(status));
+		    }
+			}
+
+		}
+
+		/* otherwise, we're in parent */
+		close(pipefd[1]); /* close write side of pipe */
+		if ((p=fdopen(pipefd[0], "r"))==NULL) {
+		  perror("fdopen");
+			do_exit(5);
 		}
 
+
 		for (y = show_title; y < height; y++) {
 			int eolseen = 0, tabpending = 0;
 			for (x = 0; x < width; x++) {
@@ -313,7 +384,19 @@
 			oldeolseen = eolseen;
 		}
 
-		pclose(p);
+		fclose(p);
+
+		/* harvest child process and get status, propagated from command */
+		if (waitpid(child, &status, 0)<0) {
+		  perror("waitpid");
+			do_exit(8);
+		};
+
+		/* if child process exited in error, beep if option_beep is set */
+		if ((!WIFEXITED(status) || WEXITSTATUS(status))) {
+          if (option_beep) beep();
+          if (option_errexit) do_exit(8);
+		}
 
 		first_screen = 0;
 		refresh();