diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-03-24 21:19:51 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-03-24 21:19:51 +0000 |
commit | f39653e3060427b4a48f70e486d7c71729bffd96 (patch) | |
tree | 11c96bbf12b91814d584edae45cc9e41f6639eb9 | |
parent | cee01cfb2eebdf7893acf343b00c21dd49ba4746 (diff) | |
download | busybox-w32-f39653e3060427b4a48f70e486d7c71729bffd96.tar.gz busybox-w32-f39653e3060427b4a48f70e486d7c71729bffd96.tar.bz2 busybox-w32-f39653e3060427b4a48f70e486d7c71729bffd96.zip |
lpd: debugging by Vladimir: he found vda's breakage (trashed s[0])!
-rw-r--r-- | printutils/lpd.c | 94 |
1 files changed, 52 insertions, 42 deletions
diff --git a/printutils/lpd.c b/printutils/lpd.c index 4008e4396..f4c902c79 100644 --- a/printutils/lpd.c +++ b/printutils/lpd.c | |||
@@ -9,10 +9,11 @@ | |||
9 | 9 | ||
10 | /* | 10 | /* |
11 | * A typical usage of BB lpd looks as follows: | 11 | * A typical usage of BB lpd looks as follows: |
12 | * # tcpsvd -E 0 515 lpd SPOOLDIR [HELPER-PROG [ARGS...]] | 12 | * # tcpsvd -E 0 515 lpd [SPOOLDIR] [HELPER-PROG [ARGS...]] |
13 | * | 13 | * |
14 | * This means a network listener is started on port 515 (default for LP protocol). | 14 | * This starts TCP listener on port 515 (default for LP protocol). |
15 | * When a client connection is made (via lpr) lpd first change its working directory to SPOOLDIR. | 15 | * When a client connection is made (via lpr) lpd first changes its |
16 | * working directory to SPOOLDIR (current dir is the default). | ||
16 | * | 17 | * |
17 | * SPOOLDIR is the spool directory which contains printing queues | 18 | * SPOOLDIR is the spool directory which contains printing queues |
18 | * and should have the following structure: | 19 | * and should have the following structure: |
@@ -23,44 +24,50 @@ | |||
23 | * <queueN> | 24 | * <queueN> |
24 | * | 25 | * |
25 | * <queueX> can be of two types: | 26 | * <queueX> can be of two types: |
26 | * A. a printer character device or an ordinary file a link to such; | 27 | * A. a printer character device, an ordinary file or a link to such; |
27 | * B. a directory. | 28 | * B. a directory. |
28 | * | 29 | * |
29 | * In case A lpd just dumps the data it receives from client (lpr) to the | 30 | * In case A lpd just dumps the data it receives from client (lpr) to the |
30 | * end of queue file/device. This is non-spooling mode. | 31 | * end of queue file/device. This is non-spooling mode. |
31 | * | 32 | * |
32 | * In case B lpd enters spooling mode. It reliably saves client data along with control info | 33 | * In case B lpd enters spooling mode. It reliably saves client data along |
33 | * in two unique files under the queue directory. These files are named dfAXXXHHHH and cfAXXXHHHH, | 34 | * with control info in two unique files under the queue directory. These |
34 | * where XXX is the job number and HHHH is the client hostname. Unless a printing helper application | 35 | * files are named dfAXXXHHHH and cfAXXXHHHH, where XXX is the job number |
36 | * and HHHH is the client hostname. Unless a printing helper application | ||
35 | * is specified lpd is done at this point. | 37 | * is specified lpd is done at this point. |
36 | * | 38 | * |
37 | * NB: file names are produced by peer! They actually may be anything at all! | 39 | * NB: file names are produced by peer! They actually may be anything at all. |
38 | * lpd only sanitizes them (by removing most non-alphanumerics). | 40 | * lpd only sanitizes them (by removing most non-alphanumerics). |
39 | * | 41 | * |
40 | * If HELPER-PROG (with optional arguments) is specified then lpd continues to process client data: | 42 | * If HELPER-PROG (with optional arguments) is specified then lpd continues |
41 | * 1. it reads and parses control file (cfA...). The parse process results in setting environment | 43 | * to process client data: |
42 | * variables whose values were passed in control file; when parsing is complete, lpd deletes | 44 | * 1. it reads and parses control file (cfA...). The parse process |
43 | * control file. | 45 | * results in setting environment variables whose values were passed |
44 | * 2. it spawns specified helper application. It is then the helper application who is responsible | 46 | * in control file; when parsing is complete, lpd deletes control file. |
45 | * for both actual printing and deleting processed data file. | 47 | * 2. it spawns specified helper application. It is then |
48 | * the helper application who is responsible for both actual printing | ||
49 | * and deleting of processed data file. | ||
46 | * | 50 | * |
47 | * A good lpr passes control files which when parsed provide the following variables: | 51 | * A good lpr passes control files which when parsed provides the following |
52 | * variables: | ||
48 | * $H = host which issues the job | 53 | * $H = host which issues the job |
49 | * $P = user who prints | 54 | * $P = user who prints |
50 | * $C = class of printing (what is printed on banner page) | 55 | * $C = class of printing (what is printed on banner page) |
51 | * $J = the name of the job | 56 | * $J = the name of the job |
52 | * $L = print banner page | 57 | * $L = print banner page |
53 | * $M = the user to whom a mail should be sent if a problem occurs | 58 | * $M = the user to whom a mail should be sent if a problem occurs |
59 | * | ||
60 | * We specifically filter out and NOT provide: | ||
54 | * $l = name of datafile ("dfAxxx") - file whose content are to be printed | 61 | * $l = name of datafile ("dfAxxx") - file whose content are to be printed |
55 | * | 62 | * |
56 | * lpd also provides $DATAFILE environment variable - the ACTUAL name | 63 | * lpd provides $DATAFILE instead - the ACTUAL name |
57 | * of the datafile under which it was saved. | 64 | * of the datafile under which it was saved. |
58 | * $l is not reliable (you are at mercy of remote peer), DON'T USE IT. | 65 | * $l would be not reliable (you would be at mercy of remote peer). |
59 | * | 66 | * |
60 | * Thus, a typical helper can be something like this: | 67 | * Thus, a typical helper can be something like this: |
61 | * #!/bin/sh | 68 | * #!/bin/sh |
62 | * cat "$l" >/dev/lp0 | 69 | * cat ./"$DATAFILE" >/dev/lp0 |
63 | * mv -f "$l" save/ | 70 | * mv -f ./"$DATAFILE" save/ |
64 | */ | 71 | */ |
65 | 72 | ||
66 | #include "libbb.h" | 73 | #include "libbb.h" |
@@ -87,6 +94,8 @@ static void exec_helper(char **filenames, char **argv) | |||
87 | char *p, *q; | 94 | char *p, *q; |
88 | char var[2]; | 95 | char var[2]; |
89 | 96 | ||
97 | var[1] = '\0'; | ||
98 | |||
90 | // read and delete ctrlfile | 99 | // read and delete ctrlfile |
91 | q = xmalloc_open_read_close(filenames[0], NULL); | 100 | q = xmalloc_open_read_close(filenames[0], NULL); |
92 | unlink(filenames[0]); | 101 | unlink(filenames[0]); |
@@ -97,11 +106,13 @@ static void exec_helper(char **filenames, char **argv) | |||
97 | && isalpha(*q) | 106 | && isalpha(*q) |
98 | ) { | 107 | ) { |
99 | *p++ = '\0'; | 108 | *p++ = '\0'; |
100 | // here q is a line of <SYM><VALUE> | 109 | // q is a line of <SYM><VALUE>, |
101 | // let us set environment string <SYM>=<VALUE> | 110 | // we are setting environment string <SYM>=<VALUE>. |
102 | var[0] = *q++; | 111 | // Ignoring "l<datafile>", exporting others: |
103 | var[1] = '\0'; | 112 | if (*q != 'l') { |
104 | xsetenv(var, q); | 113 | var[0] = *q++; |
114 | xsetenv(var, q); | ||
115 | } | ||
105 | // next line, plz! | 116 | // next line, plz! |
106 | q = p; | 117 | q = p; |
107 | } | 118 | } |
@@ -110,7 +121,7 @@ static void exec_helper(char **filenames, char **argv) | |||
110 | // (no daemonization is done) | 121 | // (no daemonization is done) |
111 | bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO | DAEMON_ONLY_SANITIZE, NULL); | 122 | bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO | DAEMON_ONLY_SANITIZE, NULL); |
112 | BB_EXECVP(*argv, argv); | 123 | BB_EXECVP(*argv, argv); |
113 | exit(0); | 124 | exit(127); // it IS error if helper cannot be executed! |
114 | } | 125 | } |
115 | 126 | ||
116 | static char *xmalloc_read_stdin(void) | 127 | static char *xmalloc_read_stdin(void) |
@@ -124,7 +135,6 @@ int lpd_main(int argc, char *argv[]) MAIN_EXTERNALLY_VISIBLE; | |||
124 | int lpd_main(int argc ATTRIBUTE_UNUSED, char *argv[]) | 135 | int lpd_main(int argc ATTRIBUTE_UNUSED, char *argv[]) |
125 | { | 136 | { |
126 | int spooling = spooling; // for compiler | 137 | int spooling = spooling; // for compiler |
127 | int seen; | ||
128 | char *s, *queue; | 138 | char *s, *queue; |
129 | char *filenames[2]; | 139 | char *filenames[2]; |
130 | 140 | ||
@@ -135,8 +145,8 @@ int lpd_main(int argc ATTRIBUTE_UNUSED, char *argv[]) | |||
135 | // error messages of xfuncs will be sent over network | 145 | // error messages of xfuncs will be sent over network |
136 | xdup2(STDOUT_FILENO, STDERR_FILENO); | 146 | xdup2(STDOUT_FILENO, STDERR_FILENO); |
137 | 147 | ||
138 | filenames[0] = NULL; // ctrlfile name | 148 | // nullify ctrl/data filenames |
139 | filenames[1] = NULL; // datafile name | 149 | memset(filenames, 0, sizeof(filenames)); |
140 | 150 | ||
141 | // read command | 151 | // read command |
142 | s = queue = xmalloc_read_stdin(); | 152 | s = queue = xmalloc_read_stdin(); |
@@ -157,8 +167,7 @@ int lpd_main(int argc ATTRIBUTE_UNUSED, char *argv[]) | |||
157 | 167 | ||
158 | // queue is a directory -> chdir to it and enter spooling mode | 168 | // queue is a directory -> chdir to it and enter spooling mode |
159 | spooling = chdir(queue) + 1; // 0: cannot chdir, 1: done | 169 | spooling = chdir(queue) + 1; // 0: cannot chdir, 1: done |
160 | seen = 0; | 170 | // we don't free(s), we might need "queue" var later |
161 | // we don't free(queue), we might need it later | ||
162 | 171 | ||
163 | while (1) { | 172 | while (1) { |
164 | char *fname; | 173 | char *fname; |
@@ -175,7 +184,7 @@ int lpd_main(int argc ATTRIBUTE_UNUSED, char *argv[]) | |||
175 | // N.B. we bail out on any error | 184 | // N.B. we bail out on any error |
176 | s = xmalloc_read_stdin(); | 185 | s = xmalloc_read_stdin(); |
177 | if (!s) { // (probably) EOF | 186 | if (!s) { // (probably) EOF |
178 | if (spooling /* && 6 != spooling - always true */) { | 187 | if (spooling /* && 7 != spooling - always true */) { |
179 | // we didn't see both ctrlfile & datafile! | 188 | // we didn't see both ctrlfile & datafile! |
180 | goto err_exit; | 189 | goto err_exit; |
181 | } | 190 | } |
@@ -187,11 +196,10 @@ int lpd_main(int argc ATTRIBUTE_UNUSED, char *argv[]) | |||
187 | // we understand only "control file" or "data file" cmds | 196 | // we understand only "control file" or "data file" cmds |
188 | if (2 != s[0] && 3 != s[0]) | 197 | if (2 != s[0] && 3 != s[0]) |
189 | goto unsupported_cmd; | 198 | goto unsupported_cmd; |
190 | if (seen & (s[0] - 1)) { | 199 | if (spooling & (1 << (s[0]-1))) { |
191 | printf("Duplicated subcommand\n"); | 200 | printf("Duplicated subcommand\n"); |
192 | goto err_exit; | 201 | goto err_exit; |
193 | } | 202 | } |
194 | seen &= (s[0] - 1); // bit 1: ctrlfile; bit 2: datafile | ||
195 | // get filename | 203 | // get filename |
196 | *strchrnul(s, '\n') = '\0'; | 204 | *strchrnul(s, '\n') = '\0'; |
197 | fname = strchr(s, ' '); | 205 | fname = strchr(s, ' '); |
@@ -243,9 +251,10 @@ int lpd_main(int argc ATTRIBUTE_UNUSED, char *argv[]) | |||
243 | goto err_exit; | 251 | goto err_exit; |
244 | } | 252 | } |
245 | // get ACK and see whether it is NUL (ok) | 253 | // get ACK and see whether it is NUL (ok) |
246 | if (safe_read(STDIN_FILENO, s, 1) != 1 || s[0] != 0) { | 254 | // (and don't trash s[0]!) |
255 | if (safe_read(STDIN_FILENO, &s[1], 1) != 1 || s[1] != 0) { | ||
247 | // don't send error msg to peer - it obviously | 256 | // don't send error msg to peer - it obviously |
248 | // don't follow the protocol, so probably | 257 | // doesn't follow the protocol, so probably |
249 | // it can't understand us either | 258 | // it can't understand us either |
250 | goto err_exit; | 259 | goto err_exit; |
251 | } | 260 | } |
@@ -254,14 +263,15 @@ int lpd_main(int argc ATTRIBUTE_UNUSED, char *argv[]) | |||
254 | // chmod completely downloaded file as "readable+writable" | 263 | // chmod completely downloaded file as "readable+writable" |
255 | fchmod(fd, 0600); | 264 | fchmod(fd, 0600); |
256 | // accumulate dump state | 265 | // accumulate dump state |
257 | // N.B. after all files are dumped spooling should be 1+2+3==6 | 266 | // N.B. after all files are dumped spooling should be 1+2+4==7 |
258 | spooling += s[0]; | 267 | spooling |= (1 << (s[0]-1)); // bit 1: ctrlfile; bit 2: datafile |
259 | } | 268 | } |
269 | |||
260 | free(s); | 270 | free(s); |
261 | close(fd); // NB: can do close(-1). Who cares? | 271 | close(fd); // NB: can do close(-1). Who cares? |
262 | 272 | ||
263 | // spawn spool helper and exit if all files are dumped | 273 | // spawn spool helper and exit if all files are dumped |
264 | if (6 == spooling && *argv) { | 274 | if (7 == spooling && *argv) { |
265 | // signal OK | 275 | // signal OK |
266 | safe_write(STDOUT_FILENO, "", 1); | 276 | safe_write(STDOUT_FILENO, "", 1); |
267 | // does not return (exits 0) | 277 | // does not return (exits 0) |
@@ -272,10 +282,10 @@ int lpd_main(int argc ATTRIBUTE_UNUSED, char *argv[]) | |||
272 | err_exit: | 282 | err_exit: |
273 | // don't keep corrupted files | 283 | // don't keep corrupted files |
274 | if (spooling) { | 284 | if (spooling) { |
275 | if (filenames[0]) | 285 | #define i spooling |
276 | unlink(filenames[0]); | 286 | for (i = 2; --i >= 0; ) |
277 | if (filenames[1]) | 287 | if (filenames[i]) |
278 | unlink(filenames[1]); | 288 | unlink(filenames[i]); |
279 | } | 289 | } |
280 | return EXIT_FAILURE; | 290 | return EXIT_FAILURE; |
281 | } | 291 | } |