Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_fixcpp/sys/src/cmd/postscript/tcpostio/tcpostio.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#define _BSD_EXTENSION
2
#define _NET_EXTENSION
3
#define _POSIX_SOURCE
4
 
5
#include <stdio.h>
6
#include <stdlib.h>
7
#include <unistd.h>
8
#include <fcntl.h>
9
#include <string.h>
10
#include <ctype.h>
11
#include <signal.h>
12
#include <errno.h>
13
#include <select.h>
14
#include <sys/types.h>
15
#include <sys/time.h>
16
#include <sys/socket.h>
17
#include <sys/wait.h>
18
 
19
extern	int dial_debug;
20
extern	int dial(char*, char*, char*, int*);
21
 
22
 
23
/* debug = 0 for no debugging */
24
/* debug = 1 for readprinter debugging */
25
/* debug = 2 for sendprinter debugging */
26
/* debug = 3 for full debugging, its hard to read the messages */
27
 
28
int debug = 0;
29
#define READTIMEOUT	300
30
#define	RCVSELTIMEOUT	30
31
#define	SNDSELTIMEOUT	300
32
 
33
void
34
rdtmout(void) {
35
	fprintf(stderr, "read timeout occurred, check printer\n");
36
}
37
 
38
int
39
getline(int fd, char *buf, int len) {
40
	char *bp, c;
41
	int i = 0, n;
42
 
43
	bp = buf;
44
	while (alarm(READTIMEOUT),(n=read(fd, bp, 1)) == 1) {
45
		alarm(0);
46
		if (*bp == '\r') continue;
47
		i += n;
48
 
49
		c = *bp++;
50
		if (c == '\n' || c == '\004' || i >= len-1)
51
			break;
52
	}
53
	alarm(0);
54
	if (n < 0)
55
		return(n);
56
	*bp = '\0';
57
	return(i);
58
}
59
 
60
typedef struct {
61
	char	*state;			/* printer's current status */
62
	int	val;			/* value returned by getstatus() */
63
} Status;
64
 
65
/* printer states */
66
#define	INITIALIZING	0
67
#define	IDLE		1
68
#define	BUSY		2
69
#define	WAITING		3
70
#define	PRINTING	4
71
#define	PRINTERERROR	5
72
#define	ERROR		6
73
#define	FLUSHING	7
74
#define UNKNOWN		8
75
 
76
/* protocol requests and program states */
77
#define START	'S'
78
unsigned char Start[] = { START };
79
#define ID_LE		'L'
80
unsigned char Id_le[] = { ID_LE };
81
#define	REQ_STAT	'T'
82
unsigned char Req_stat[] = { REQ_STAT };
83
#define	SEND_DATA	'D'
84
unsigned char Send_data[] = { SEND_DATA };
85
#define	SENT_DATA	'A'
86
unsigned char Sent_data[] = { SENT_DATA };
87
#define	WAIT_FOR_EOJ	'W'
88
unsigned char Wait_for_eoj[] = { WAIT_FOR_EOJ };
89
#define END_OF_JOB	'E'
90
unsigned char End_of_job[] = { END_OF_JOB };
91
#define FATAL_ERROR	'F'
92
unsigned char Fatal_error[] = { FATAL_ERROR };
93
#define	WAIT_FOR_IDLE	'I'
94
unsigned char Wait_for_idle[] = { WAIT_FOR_IDLE };
95
#define	OVER_AND_OUT	'O'
96
unsigned char Over_and_out[] = { OVER_AND_OUT };
97
 
98
Status	statuslist[] = {
99
	"initializing", INITIALIZING,
100
	"idle", IDLE,
101
	"busy", BUSY,
102
	"waiting", WAITING,
103
	"printing", PRINTING,
104
	"printererror", PRINTERERROR,
105
	"Error", ERROR,
106
	"flushing", FLUSHING,
107
	NULL, UNKNOWN
108
};
109
 
110
 
111
/* find returns a pointer to the location of string str2 in string str1,
112
 * if it exists.  Otherwise, it points to the end of str1.
113
 */
114
char *
115
find(char *str1, char *str2) {
116
	char *s1, *s2;
117
 
118
	for (; *str1!='\0'; str1++) {
119
		for (s1=str1,s2=str2; *s2!='\0'&&*s1==*s2; s1++,s2++) ;
120
		if ( *s2 == '\0' )
121
	    		break;
122
	}
123
 
124
	return(str1);
125
}
126
 
127
#define	MESGSIZE	16384
128
int blocksize = 1920;		/* 19200/10, with 1 sec delay between transfers
129
				 * this keeps the queues from building up.
130
				 */
131
char	mesg[MESGSIZE];			/* exactly what came back on ttyi */
132
 
133
int
134
parsmesg(char *buf) {
135
	static char sbuf[MESGSIZE];
136
	char	*s;		/* start of printer messsage in mesg[] */
137
	char	*e;		/* end of printer message in mesg[] */
138
	char	*key, *val;	/* keyword/value strings in sbuf[] */
139
	char	*p;		/* for converting to lower case etc. */
140
	int	i;		/* where *key was found in statuslist[] */
141
 
142
	if (*(s=find(buf, "%[ "))!='\0' && *(e=find(s, " ]%"))!='\0') {
143
		strcpy(sbuf, s+3);	/* don't change mesg[] */
144
		sbuf[e-(s+3)] = '\0';	/* ignore the trailing " ]%" */
145
 
146
		for (key=strtok(sbuf, " :"); key != NULL; key=strtok(NULL, " :"))  {
147
			if (strcmp(key, "Error") == 0)
148
				return(ERROR);
149
			if ((val=strtok(NULL, ";")) != NULL && strcmp(key, "status") == 0)
150
				key = val;
151
 
152
	    		for (; *key == ' '; key++) ;	/* skip any leading spaces */
153
			for (p = key; *p; p++)		/* convert to lower case */
154
				if (*p == ':')  {
155
					*p = '\0';
156
					break;
157
				} else if (isupper(*p)) *p = tolower(*p);
158
 
159
			for (i=0; statuslist[i].state != NULL; i++) {
160
				if (strcmp(statuslist[i].state, key) == 0)
161
					return(statuslist[i].val);
162
			}
163
		}
164
	}
165
	return(UNKNOWN);
166
}
167
 
168
char buf[MESGSIZE];
169
fd_set readfds, writefds, exceptfds;
170
struct timeval rcvtimeout = { RCVSELTIMEOUT, 0 };
171
struct timeval sndtimeout = { SNDSELTIMEOUT, 0 };
172
 
173
int
174
readprinter(int printerfd, int pipefd)
175
{
176
	unsigned char proto;
177
	int progstate = START;
178
	int print_wait_msg = 0;
179
	int tocount = 0;
180
	int c, printstat, lastprintstat, n, nfds;
181
 
182
 
183
	nfds = ((pipefd>printerfd)?pipefd:printerfd) + 1;
184
	printstat = 0;
185
	signal(SIGALRM, rdtmout);
186
	do {
187
 
188
reselect:
189
		/* ask sending process to request printer status */
190
		if (write(pipefd, Req_stat, 1) != 1) {
191
			fprintf(stderr, "request status failed\n");
192
			progstate = FATAL_ERROR;
193
			continue;
194
		}
195
		FD_ZERO(&readfds);	/* lets be anal */
196
		FD_SET(printerfd, &readfds);
197
		FD_SET(pipefd, &readfds);
198
		FD_ZERO(&exceptfds);
199
		FD_SET(printerfd, &exceptfds);
200
		FD_SET(pipefd, &exceptfds);
201
		n = select(nfds, &readfds, (fd_set *)0, &exceptfds, &rcvtimeout);
202
		if (debug&0x1) fprintf(stderr, "readprinter select returned %d\n", n);
203
		if (n == 0) {
204
			/* a timeout occurred */
205
			if (++tocount > 4) {
206
				fprintf(stderr, "printer appears to be offline.\nHP4m printers may be out of paper.\n");
207
				tocount = 0;
208
			}
209
			goto reselect;
210
		}
211
		if (n > 0 && FD_ISSET(printerfd, &exceptfds)) {
212
			/* printer problem */
213
			fprintf(stderr, "printer exception\n");
214
			if (write(pipefd, Fatal_error, 1) != 1) {
215
				fprintf(stderr, "'fatal error' write to pipe failed\n");
216
			}
217
			progstate = FATAL_ERROR;
218
			continue;
219
		}
220
		if (n > 0 && FD_ISSET(pipefd, &exceptfds)) {
221
			/* pipe problem */
222
			fprintf(stderr, "pipe exception\n");
223
			progstate = FATAL_ERROR;
224
			continue;
225
		}
226
		if (n > 0 && FD_ISSET(pipefd, &readfds)) {
227
			/* protocol pipe wants to be read */
228
			if (debug&0x1) fprintf(stderr, "pipe wants to be read\n");
229
			if (read(pipefd, &proto, 1) != 1) {
230
				fprintf(stderr, "read protocol pipe failed\n");
231
				progstate = FATAL_ERROR;
232
				continue;
233
			}
234
			if (debug&0x1) fprintf(stderr, "readprinter: proto=%c\n", proto);
235
			/* change state? */
236
			switch (proto) {
237
			case SENT_DATA:
238
				break;
239
			case WAIT_FOR_EOJ:
240
				if (!print_wait_msg) {
241
					print_wait_msg = 1;
242
					fprintf(stderr, "waiting for end of job\n");
243
				}
244
				progstate = proto;
245
				break;
246
			default:
247
				fprintf(stderr, "received unknown protocol request <%c> from sendfile\n", proto);
248
				break;
249
			}
250
			n--;
251
		}
252
		if (n > 0 && FD_ISSET(printerfd, &readfds)) {
253
			/* printer wants to be read */
254
			if (debug&0x1) fprintf(stderr, "printer wants to be read\n");
255
			if ((c=getline(printerfd, buf, MESGSIZE)) < 0) {
256
				fprintf(stderr, "read printer failed\n");
257
				progstate = FATAL_ERROR;
258
				continue;
259
			}
260
			if (debug&0x1) fprintf(stderr, "%s\n", buf);
261
			if (c==1 && *buf == '\004') {
262
				if (progstate == WAIT_FOR_EOJ) {
263
					if (debug&0x1) fprintf(stderr, "progstate=%c, ", progstate);
264
					fprintf(stderr, "%%[ status: endofjob ]%%\n");
265
/*					progstate = WAIT_FOR_IDLE; */
266
					progstate = OVER_AND_OUT;
267
					if (write(pipefd, Over_and_out, 1) != 1) {
268
						fprintf(stderr, "'fatal error' write to pipe failed\n");
269
					}
270
					continue;
271
				} else {
272
					if (printstat == ERROR) {
273
						progstate = FATAL_ERROR;
274
						continue;
275
					}
276
					if (progstate != START && progstate != WAIT_FOR_IDLE)
277
						fprintf(stderr, "warning: EOF received; program status is '%c'\n", progstate);
278
 
279
				}
280
				continue;
281
			}
282
 
283
			/* figure out if it was a status line */
284
			lastprintstat = printstat;
285
			printstat = parsmesg(buf);
286
			if (printstat == UNKNOWN || printstat == ERROR
287
			    || lastprintstat != printstat) {
288
				/* print whatever it is that was read */
289
				fprintf(stderr, buf);
290
				fflush(stderr);
291
				if (printstat == UNKNOWN) {
292
					printstat = lastprintstat;
293
					continue;
294
				}
295
			}
296
			switch (printstat) {
297
			case UNKNOWN:
298
				continue;	/* shouldn't get here */
299
			case FLUSHING:
300
			case ERROR:
301
				progstate = FATAL_ERROR;
302
				/* ask sending process to die */
303
				if (write(pipefd, Fatal_error, 1) != 1) {
304
					fprintf(stderr, "Fatal_error mesg write to pipe failed\n");
305
				}
306
				continue;
307
			case INITIALIZING:
308
			case PRINTERERROR:
309
				sleep(1);
310
				break;
311
			case IDLE:
312
				if (progstate == WAIT_FOR_IDLE) {
313
					progstate = OVER_AND_OUT;
314
					if (write(pipefd, Over_and_out, 1) != 1) {
315
						fprintf(stderr, "'fatal error' write to pipe failed\n");
316
					}
317
					continue;
318
				}
319
				progstate = SEND_DATA;
320
 
321
				goto dowait;
322
			case BUSY:
323
			case WAITING:
324
			default:
325
				sleep(1);
326
dowait:
327
				switch (progstate) {
328
				case WAIT_FOR_IDLE:
329
				case WAIT_FOR_EOJ:
330
				case START:
331
					sleep(5);
332
					break;
333
 
334
				case SEND_DATA:
335
					if (write(pipefd, Send_data, 1) != 1) {
336
						fprintf(stderr, "send data write to pipe failed\n");
337
						progstate = FATAL_ERROR;
338
						continue;
339
					}
340
					break;
341
				default:
342
					fprintf(stderr, "unexpected program state %c\n", progstate);
343
					exit(1);
344
				}
345
				break;
346
			}
347
			n--;
348
		}
349
		if (n > 0) {
350
			fprintf(stderr, "more fds selected than requested!\n");
351
			exit(1);
352
		};
353
	} while ((progstate != FATAL_ERROR) && (progstate != OVER_AND_OUT));
354
 
355
	if (progstate == FATAL_ERROR)
356
		return(1);
357
	else
358
		return(0);
359
}
360
 
361
int
362
sendfile(int infd, int printerfd, int pipefd)
363
{
364
	unsigned char proto;
365
	int progstate = START;
366
	int i, n, nfds;
367
	int bytesread,  bytesent = 0;
368
 
369
	nfds = ((pipefd>printerfd)?pipefd:printerfd) + 1;
370
 
371
	if (write(printerfd, "\004", 1)!=1) {
372
		perror("sendfile:write:");
373
		progstate = FATAL_ERROR;
374
	}
375
	do {
376
		FD_ZERO(&readfds);	/* lets be anal */
377
		FD_SET(pipefd, &readfds);
378
		n = select(nfds, &readfds, (fd_set *)0, (fd_set *)0, &sndtimeout);
379
		if (debug&02) fprintf(stderr, "sendfile select returned %d\n", n);
380
		if (n > 0 && FD_ISSET(pipefd, &readfds)) {
381
			/* protocol pipe wants to be read */
382
			if (read(pipefd, &proto, 1) != 1) {
383
				fprintf(stderr, "read protocol pipe failed\n");
384
				return(1);
385
			}
386
			/* change state? */
387
			if (debug&02) fprintf(stderr, "sendfile command - <%c>\n", proto);
388
			switch (proto) {
389
			case OVER_AND_OUT:
390
			case END_OF_JOB:
391
				progstate = proto;
392
				break;
393
			case SEND_DATA:
394
				bytesread = 0;
395
				do {
396
					i = read(infd, &buf[bytesread], blocksize-bytesread);
397
					if (debug&02) fprintf(stderr, "read %d bytes\n", i);
398
					if (i > 0)
399
						bytesread += i;
400
				} while((i > 0) && (bytesread < blocksize));
401
				if (i < 0) {
402
					fprintf(stderr, "input file read error\n");
403
					progstate = FATAL_ERROR;
404
					break;	/* from switch */
405
				}
406
				if (bytesread > 0) {
407
					if (debug&02) fprintf(stderr, "writing %d bytes\n", bytesread);
408
					if (write(printerfd, buf, bytesread)!=bytesread) {
409
						perror("sendfile:write:");
410
						progstate = FATAL_ERROR;
411
					} else if (write(pipefd, Sent_data, 1)!=1) {
412
						perror("sendfile:write:");
413
						progstate = FATAL_ERROR;
414
					} else {
415
						bytesent += bytesread;
416
					}
417
					fprintf(stderr, "%d sent\n", bytesent);
418
					fflush(stderr);
419
 
420
				/* we have reached the end of the input file */
421
				}
422
				if (i == 0) {
423
					if (progstate != WAIT_FOR_EOJ) {
424
						if (write(printerfd, "\004", 1)!=1) {
425
							perror("sendfile:write:");
426
							progstate = FATAL_ERROR;
427
						} else if (write(pipefd, Wait_for_eoj, 1)!=1) {
428
							perror("sendfile:write:");
429
							progstate = FATAL_ERROR;
430
						} else {
431
							progstate = WAIT_FOR_EOJ;
432
						}
433
					}
434
				}
435
				break;
436
			case REQ_STAT:
437
				if (write(printerfd, "\024", 1)!=1) {
438
					fprintf(stderr, "write to printer failed\n");
439
					progstate = FATAL_ERROR;
440
				}
441
				if (debug&02) fprintf(stderr, "^T");
442
				break;
443
			case FATAL_ERROR:
444
				progstate = FATAL_ERROR;
445
			}
446
		} else if (n < 0) {
447
			perror("sendfile:select:");
448
			progstate = FATAL_ERROR;
449
		} else if (n == 0) {
450
			sleep(1);
451
			fprintf(stderr, "sendfile timeout\n");
452
			progstate = FATAL_ERROR;
453
		}
454
	} while ((progstate != FATAL_ERROR) && (progstate != OVER_AND_OUT));
455
	if (write(printerfd, "\004", 1)!=1) {
456
		perror("sendfile:write:");
457
		progstate = FATAL_ERROR;
458
	}
459
 
460
	if (debug&02) fprintf(stderr, "%d bytes sent\n", bytesent);
461
	if (progstate == FATAL_ERROR)
462
		return(1);
463
	else
464
		return(0);
465
}
466
 
467
void main(int argc, char *argv[]) {
468
	int c, usgflg=0, infd, printerfd;
469
	int cpid, sprv;
470
	int pipefd[2];
471
	char *dialstr;
472
	unsigned long rprv;
473
 
474
	dialstr = 0;
475
 
476
	while ((c = getopt(argc, argv, "b:d:")) != -1)
477
		switch (c) {
478
		case 'b':
479
			blocksize = atoi(optarg)/10;
480
			if (blocksize > MESGSIZE || blocksize < 1)
481
				blocksize = MESGSIZE;
482
			break;
483
		case 'd':
484
			debug = atoi(optarg);
485
			dial_debug = debug;
486
			break;
487
		case '?':
488
			fprintf(stderr, "unknown option %c\n", c);
489
			usgflg++;
490
			break;
491
		}
492
	if (optind < argc)
493
		dialstr = argv[optind++];
494
	else
495
		usgflg++;
496
	if (usgflg) {
497
		fprintf(stderr, "usage: %s [-b baudrate] net!host!service [infile]\n",
498
			argv[0]);
499
		exit (2);
500
	}
501
	if (optind < argc) {
502
		infd = open(argv[optind], 0);
503
		if (infd < 0) {
504
			fprintf(stderr, "cannot open %s\n", argv[optind]);
505
			exit(1);
506
		}
507
		optind++;
508
	} else
509
		infd = 0;
510
 
511
	if (debug & 02)
512
		fprintf(stderr, "blocksize=%d\n", blocksize);
513
	if (debug)
514
		fprintf(stderr, "dialing address=%s\n", dialstr);
515
	printerfd = dial(dialstr, 0, 0, 0);
516
	if (printerfd < 0)
517
		exit(1);
518
 
519
	fprintf(stderr, "printer startup\n");
520
 
521
	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipefd) < 0) {
522
		perror("socketpair");
523
		exit(1);
524
	}
525
	switch(cpid = fork()){
526
	case -1:
527
		perror("fork error");
528
		exit(1);
529
	case 0:				/* child - to printer */
530
		close(pipefd[1]);
531
		sprv = sendfile(infd, printerfd, pipefd[0]);
532
		if (debug)
533
			fprintf(stderr, "to remote - exiting\n");
534
		exit(sprv);
535
	default:			/* parent - from printer */
536
		close(pipefd[0]);
537
		rprv = readprinter(printerfd, pipefd[1]);
538
		if (debug)
539
			fprintf(stderr, "from remote - exiting\n");
540
		while(wait(&sprv) != cpid)
541
			;
542
		exit(rprv|sprv);
543
	}
544
}