]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/lp/lpsend.c
kbdfs: simplfy
[plan9front.git] / sys / src / cmd / lp / lpsend.c
1 #ifdef plan9
2
3 #include <u.h>
4 #include <libc.h>
5
6 enum {
7         stderr = 2,
8         RDNETIMEOUT = 30*60*1000,
9         WRNETIMEOUT = RDNETIMEOUT,
10 };
11 #else
12
13 /* not for plan 9 */
14 #include <stdio.h>
15 #include <errno.h>
16 #include <time.h>
17 #include <fcntl.h>
18 #include <signal.h>
19
20 #define create  creat
21 #define seek    lseek
22 #define fprint  fprintf
23 #define sprint  sprintf
24 #define exits   exit
25
26 #define ORDWR   O_RDWR
27 #define OTRUNC  O_TRUNC
28 #define ORCLOSE 0
29
30 #define RDNETIMEOUT     60
31 #define WRNETIMEOUT     60
32
33 #endif
34
35 #define MIN(a,b)        ((a<b)?a:b)
36
37 #define ACK(a)  write(a, "", 1)
38 #define NAK(a)  write(a, "\001", 1)
39
40 #define LPDAEMONLOG     "/tmp/lpdaemonl"
41
42 #define LNBFSZ  4096
43 char lnbuf[LNBFSZ];
44 int dbgstate = 0;
45 char *dbgstrings[] = {
46         "",
47         "rcvack1",
48         "send",
49         "rcvack2",
50         "response",
51         "done"
52 };
53
54 #ifdef plan9
55
56 void
57 error(int level, char *s1, ...)
58 {
59         va_list ap;
60         long thetime;
61         char *chartime;
62         char *args[8];
63         int argno = 0;
64
65         if (level == 0) {
66                 time(&thetime);
67                 chartime = ctime(thetime);
68                 fprint(stderr, "%.15s ", &(chartime[4]));
69         }
70         va_start(ap, s1);
71         while(args[argno++] = va_arg(ap, char*))
72                 ;
73         va_end(ap);
74         fprint(stderr, s1, *args);
75 }
76
77 int
78 alarmhandler(void *foo, char *note) {
79         USED(foo);
80         if(strcmp(note, "alarm")==0) {
81                 fprint(stderr, "alarm at %d - %s\n", dbgstate, dbgstrings[dbgstate]);
82                 return(1);
83         } else return(0);
84 }
85
86 #else
87
88 void
89 error(int level, char *s1, ...)
90 {
91         time_t thetime;
92         char *chartime;
93
94         if (level == 0) {
95                 time(&thetime);
96                 chartime = ctime(&thetime);
97                 fprintf(stderr, "%.15s ", &(chartime[4]));
98         }
99         fprintf(stderr, s1, &s1 + 1);
100 }
101
102 void
103 alarmhandler() {
104         fprintf(stderr, "alarm at %d - %s\n", dbgstate, dbgstrings[dbgstate]);
105 }
106
107 #endif
108
109 /* get a line from inpfd using nonbuffered input.  The line is truncated if it is too
110  * long for the buffer.  The result is left in lnbuf and the number of characters
111  * read in is returned.
112  */
113 int
114 readline(int inpfd)
115 {
116         register char *ap;
117         register int i;
118
119         ap = lnbuf;
120         i = 0;
121         do {
122                 if (read(inpfd, ap, 1) != 1) {
123                         error(0, "read error in readline, fd=%d\n", inpfd);
124                         break;
125                 }
126         } while ((++i < LNBFSZ - 2) && *ap++ != '\n');
127         if (i == LNBFSZ - 2) {
128                 *ap = '\n';
129                 i++;
130         }
131         *ap = '\0';
132         return(i);
133 }
134
135 #define RDSIZE 512
136 char jobbuf[RDSIZE];
137
138 int
139 pass(int inpfd, int outfd, int bsize)
140 {
141         int bcnt = 0;
142         int rv = 0;
143
144         for(bcnt=bsize; bcnt > 0; bcnt -= rv) {
145                 alarm(WRNETIMEOUT);     /* to break hanging */
146                 if((rv=read(inpfd, jobbuf, MIN(bcnt,RDSIZE))) < 0) {
147                         error(0, "read error during pass, %d remaining\n", bcnt);
148                         break;
149                 } else if((write(outfd, jobbuf, rv)) != rv) {
150                         error(0, "write error during pass, %d remaining\n", bcnt);
151                         break;
152                 }
153         }
154         alarm(0);
155         return(bcnt);
156 }
157         
158 /* get whatever stdin has and put it into the temporary file.
159  * return the file size.
160  */
161 int
162 prereadfile(int inpfd)
163 {
164         int rv, bsize;
165
166         bsize = 0;
167         do {
168                 if((rv=read(0, jobbuf, RDSIZE))<0) {
169                         error(0, "read error while making temp file\n");
170                         exits("read error while making temp file");
171                 } else if((write(inpfd, jobbuf, rv)) != rv) {
172                         error(0, "write error while making temp file\n");
173                         exits("write error while making temp file");
174                 }
175                 bsize += rv;
176         } while (rv!=0);
177         return(bsize);
178 }
179
180 int
181 tempfile(void)
182 {
183         static tindx = 0;
184         char tmpf[20];
185         int tmpfd;
186
187         sprint(tmpf, "/tmp/lp%d.%d", getpid(), tindx++);
188         if((tmpfd=create(tmpf,
189 #ifdef plan9
190                 ORDWR|OTRUNC,
191 #endif
192             0666)) < 0) {
193                 error(0, "cannot create temp file %s\n", tmpf);
194                 exits("cannot create temp file");
195         }
196         close(tmpfd);
197         if((tmpfd=open(tmpf, ORDWR
198 #ifdef plan9
199                 |ORCLOSE|OTRUNC
200 #endif
201             )) < 0) {
202                 error(0, "cannot open temp file %s\n", tmpf);
203                 exits("cannot open temp file");
204         }
205         return(tmpfd);
206 }
207
208 int
209 recvACK(int netfd)
210 {
211         int rv;
212
213         *jobbuf = '\0';
214         alarm(RDNETIMEOUT);
215         if (read(netfd, jobbuf, 1)!=1 || *jobbuf!='\0') {
216                 error(0, "failed to receive ACK, ");
217                 if (*jobbuf == '\0')
218                         error(1, "read failed\n");
219                 else
220                         error(1, "received <0x%x> instead\n", *jobbuf);
221                 rv = 0;
222         } else rv = 1;
223         alarm(0);
224         return(rv);
225 }
226
227 void
228 main(int argc, char *argv[])
229 {
230         char *devdir;
231         int i, rv, netfd, bsize, datafd;
232 #ifndef plan9
233         void (*oldhandler)();
234 #endif
235
236         /* make connection */
237         if (argc != 2) {
238                 fprint(stderr, "usage: %s network!destination!service\n",
239                         argv[0]);
240                 exits("usage");
241         }
242
243         /* read options line from stdin into lnbuf */
244         i = readline(0);
245
246         /* read stdin into tempfile to get size */
247         datafd = tempfile();
248         bsize = prereadfile(datafd);
249
250         /* network connection is opened after data is in to avoid timeout */
251         if ((netfd = dial(argv[1], 0, 0, 0)) < 0) {
252                 fprint(stderr, "dialing ");
253                 perror(argv[1]);
254                 exits("can't dial");
255         }
256
257         /* write out the options we read above */
258         if (write(netfd, lnbuf, i) != i) {
259                 error(0, "write error while sending options\n");
260                 exits("write error sending options");
261         }
262
263         /* send the size of the file to be sent */
264         sprint(lnbuf, "%d\n", bsize);
265         i = strlen(lnbuf);
266         if ((rv=write(netfd, lnbuf, i)) != i) {
267                 perror("write error while sending size");
268                 error(0, "write returned %d\n", rv);
269                 exits("write error sending size");
270         }
271
272         if (seek(datafd, 0L, 0) < 0) {
273                 error(0, "error seeking temp file\n");
274                 exits("seek error");
275         }
276         /* mirror performance in readfile() in lpdaemon */
277
278 #ifdef plan9
279         atnotify(alarmhandler, 1);
280 #else
281         oldhandler = signal(SIGALRM, alarmhandler);
282 #endif
283
284         dbgstate = 1;
285         if(!recvACK(netfd)) {
286                 error(0, "failed to receive ACK before sending data\n");
287                 exits("recv ack1 failed");
288         }
289         dbgstate = 2;
290         if ((i=pass(datafd, netfd, bsize)) != 0) {
291                 NAK(netfd);
292                 error(0, "failed to send %d bytes\n", i);
293                 exits("send data failed");
294         }
295         ACK(netfd);
296         dbgstate = 3;
297         if(!recvACK(netfd)) {
298                 error(0, "failed to receive ACK after sending data\n");
299                 exits("recv ack2 failed");
300         }
301
302         /* get response, as from lp -q */
303         dbgstate = 4;
304         while((rv=read(netfd, jobbuf, RDSIZE)) > 0) {
305                 if((write(1, jobbuf, rv)) != rv) {
306                         error(0, "write error while sending to stdout\n");
307                         exits("write error while sending to stdout");
308                 }
309         }
310         dbgstate = 5;
311
312 #ifdef plan9
313         atnotify(alarmhandler, 0);
314         /* close down network connections and go away */
315         exits("");
316 #else
317         signal(SIGALRM, oldhandler);
318         exit(0);
319 #endif
320 }