]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/lp/lpdsend.c
kernel: keep segment locked for data2txt
[plan9front.git] / sys / src / cmd / lp / lpdsend.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 #include <signal.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <sys/param.h>
10
11 #define REDIALTIMEOUT   15
12 #ifdef PLAN9
13 #include <Plan9libnet.h>
14 #endif
15
16 enum {
17         TIMEOUT = 30*60,
18         SBSIZE = 8192,
19 };
20
21 char tmpfilename[L_tmpnam+1];
22 unsigned char sendbuf[SBSIZE];
23
24 int alarmstate = 0;
25 int debugflag = 0;
26 int killflag = 0;
27 int statflag = 0;
28
29 void
30 cleanup(void)
31 {
32         unlink(tmpfilename);
33 }
34
35 void
36 debug(char *str)
37 {
38         if (debugflag)
39                 fprintf(stderr, "%s", str);
40 }
41
42 void
43 alarmhandler(int sig)
44 {
45         fprintf(stderr, "timeout occurred, check printer.\n");
46         exit(2);
47 }
48
49 /* send a message after each WARNPC percent of data sent */
50 #define WARNPC  5
51
52 int
53 copyfile(int in, int out, long tosend)
54 {
55         int n;
56         int sent = 0;
57         int percent = 0;
58
59         if (debugflag)
60                 fprintf(stderr, "lpdsend: copyfile(%d,%d,%ld)\n",
61                         in, out, tosend);
62         while ((n=read(in, sendbuf, SBSIZE)) > 0) {
63                 if (debugflag)
64                         fprintf(stderr, "lpdsend: copyfile read %d bytes from %d\n",
65                                 n, in);
66                 alarm(TIMEOUT);
67                 alarmstate = 1;
68                 if (write(out, sendbuf, n) != n) {
69                         alarm(0);
70                         fprintf(stderr, "write to fd %d failed\n", out);
71                         return(0);
72                 }
73                 alarm(0);
74                 if (debugflag)
75                         fprintf(stderr, "lpdsend: copyfile wrote %d bytes to %d\n",
76                                 n, out);
77                 sent += n;
78                 if (tosend && sent*100/tosend >= percent+WARNPC) {
79                         percent += WARNPC;
80                         fprintf(stderr, ": %5.2f%% sent\n", sent*100.0/tosend);
81                 }
82         }
83         if (debugflag)
84                 fprintf(stderr, "lpdsend: copyfile read %d bytes from %d\n",
85                         n, in);
86         return(!n);
87 }
88
89 char  strbuf[120];
90 char hostname[MAXHOSTNAMELEN], *username, *printername, *killarg;
91 char *inputname;
92 char filetype = 'o';    /* 'o' is for PostScript */
93 int seqno = 0;
94 char *seqfilename;
95
96 void
97 killjob(int printerfd)
98 {
99         int strlength;
100
101         if (printername==0) {
102                 fprintf(stderr, "no printer name\n");
103                 exit(1);
104         }
105         if (username==0) {
106                 fprintf(stderr, "no user name given\n");
107                 exit(1);
108         }
109         if (killarg==0) {
110                 fprintf(stderr, "no job to kill\n");
111                 exit(1);
112         }
113         sprintf(strbuf, "%c%s %s %s\n", '\5', printername, username, killarg);
114         strlength = strlen(strbuf);
115         if (write(printerfd, strbuf, strlength) != strlength) {
116                 fprintf(stderr, "write(printer) error\n");
117                 exit(1);
118         }
119         copyfile(printerfd, 2, 0L);
120 }
121
122 void
123 checkqueue(int printerfd)
124 {
125         int n, strlength;
126         unsigned char sendbuf[1];
127
128         sprintf(strbuf, "%c%s\n", '\4', printername);
129         strlength = strlen(strbuf);
130         if (write(printerfd, strbuf, strlength) != strlength) {
131                 fprintf(stderr, "write(printer) error\n");
132                 exit(1);
133         }
134         copyfile(printerfd, 2, 0L);
135 /*
136         while ((n=read(printerfd, sendbuf, 1)) > 0) {
137                 write(2, sendbuf, n);
138         }
139 */
140 }
141
142 void
143 getack(int printerfd, int as)
144 {
145         char resp;
146         int rv;
147
148         alarm(TIMEOUT);
149         alarmstate = as;
150         if ((rv = read(printerfd, &resp, 1)) != 1 || resp != '\0') {
151                 fprintf(stderr, "getack failed: read returned %d, "
152                         "read value (if any) %d, alarmstate=%d\n",
153                         rv, resp, alarmstate);
154                 exit(1);
155         }
156         alarm(0);
157 }
158
159 /* send control file */
160 void
161 sendctrl(int printerfd)
162 {
163         char cntrlstrbuf[256];
164         int strlength, cntrlen;
165
166         sprintf(cntrlstrbuf, "H%s\nP%s\n%cdfA%3.3d%s\n", hostname, username, filetype, seqno, hostname);
167         cntrlen = strlen(cntrlstrbuf);
168         sprintf(strbuf, "%c%d cfA%3.3d%s\n", '\2', cntrlen, seqno, hostname);
169         strlength = strlen(strbuf);
170         if (write(printerfd, strbuf, strlength) != strlength) {
171                 fprintf(stderr, "write(printer) error\n");
172                 exit(1);
173         }
174         getack(printerfd, 3);
175         if (write(printerfd, cntrlstrbuf, cntrlen) != cntrlen) {
176                 fprintf(stderr, "write(printer) error\n");
177                 exit(1);
178         }
179         if (write(printerfd, "\0", 1) != 1) {
180                 fprintf(stderr, "write(printer) error\n");
181                 exit(1);
182         }
183         getack(printerfd, 4);
184 }
185
186 /* send data file */
187 void
188 senddata(int inputfd, int printerfd, long size)
189 {
190         int strlength;
191
192         sprintf(strbuf, "%c%d dfA%3.3d%s\n", '\3', size, seqno, hostname);
193         strlength = strlen(strbuf);
194         if (write(printerfd, strbuf, strlength) != strlength) {
195                 fprintf(stderr, "write(printer) error\n");
196                 exit(1);
197         }
198         getack(printerfd, 5);
199         if (!copyfile(inputfd, printerfd, size)) {
200                 fprintf(stderr, "failed to send file to printer\n");
201                 exit(1);
202         }
203         if (write(printerfd, "\0", 1) != 1) {
204                 fprintf(stderr, "write(printer) error\n");
205                 exit(1);
206         }
207         fprintf(stderr, "%d bytes sent, status: waiting for end of job\n", size);
208         getack(printerfd, 6);
209 }
210
211 void
212 sendjob(int inputfd, int printerfd)
213 {
214         struct stat statbuf;
215         int strlength;
216
217         if (fstat(inputfd, &statbuf) < 0) {
218                 fprintf(stderr, "fstat(%s) failed\n", inputname);
219                 exit(1);
220         }
221         sprintf(strbuf, "%c%s\n", '\2', printername);
222         strlength = strlen(strbuf);
223         if (write(printerfd, strbuf, strlength) != strlength) {
224                 fprintf(stderr, "write(printer) error\n");
225                 exit(1);
226         }
227         getack(printerfd, 2);
228         debug("send data\n");
229         senddata(inputfd, printerfd, statbuf.st_size);
230         debug("send control info\n");
231         sendctrl(printerfd);
232         fprintf(stderr, "%ld bytes sent, status: end of job\n", statbuf.st_size);
233 }
234
235 /*
236  *  make an address, add the defaults
237  */
238 char *
239 netmkaddr(char *linear, char *defnet, char *defsrv)
240 {
241         static char addr[512];
242         char *cp;
243
244         /*
245          *  dump network name
246          */
247         cp = strchr(linear, '!');
248         if(cp == 0){
249                 if(defnet==0){
250                         if(defsrv)
251                                 snprintf(addr, sizeof addr, "net!%s!%s", linear, defsrv);
252                         else
253                                 snprintf(addr, sizeof addr, "net!%s", linear);
254                 }
255                 else {
256                         if(defsrv)
257                                 snprintf(addr, sizeof addr, "%s!%s!%s", defnet, linear, defsrv);
258                         else
259                                 snprintf(addr, sizeof addr, "%s!%s", defnet, linear);
260                 }
261                 return addr;
262         }
263
264         /*
265          *  if there is already a service, use it
266          */
267         cp = strchr(cp+1, '!');
268         if(cp)
269                 return linear;
270
271         /*
272          *  add default service
273          */
274         if(defsrv == 0)
275                 return linear;
276         sprintf(addr, "%s!%s", linear, defsrv);
277
278         return addr;
279 }
280
281 main(int argc, char *argv[])
282 {
283         int c, usgflg = 0, inputfd, printerfd, sendport;
284         char *desthostname, *hnend;
285         char portstr[4];
286
287         if (signal(SIGALRM, alarmhandler) == SIG_ERR) {
288                 fprintf(stderr, "failed to set alarm handler\n");
289                 exit(1);
290         }
291         while ((c = getopt(argc, argv, "Dd:k:qs:t:H:P:")) != -1)
292                 switch (c) {
293                 case 'D':
294                         debugflag = 1;
295                         debug("debugging on\n");
296                         break;
297                 case 'd':
298                         printername = optarg;
299                         break;
300                 case 'k':
301                         if (statflag) {
302                                 fprintf(stderr, "cannot have both -k and -q flags\n");
303                                 exit(1);
304                         }       
305                         killflag = 1;
306                         killarg = optarg;
307                         break;
308                 case 'q':
309                         if (killflag) {
310                                 fprintf(stderr, "cannot have both -q and -k flags\n");
311                                 exit(1);
312                         }       
313                         statflag = 1;
314                         break;
315                 case 's':
316                         seqno = strtol(optarg, NULL, 10);
317                         if (seqno < 0 || seqno > 999)
318                                 seqno = 0;
319                         break;
320                 case 't':
321                         switch (filetype) {
322                         case 'c':
323                         case 'd':
324                         case 'f':
325                         case 'g':
326                         case 'l':
327                         case 'n':
328                         case 'o':
329                         case 'p':
330                         case 'r':
331                         case 't':
332                         case 'v':
333                         case 'z':
334                                 filetype = optarg[0];
335                                 break;
336                         default:
337                                 usgflg++;
338                                 break;
339                         }
340                         break;
341                 case 'H':
342                         strncpy(hostname, optarg, MAXHOSTNAMELEN);
343                         break;
344                 case 'P':
345                         username = optarg;
346                         break;
347                 default:
348                 case '?':
349                         fprintf(stderr, "unknown option %c\n", c);
350                         usgflg++;
351                 }
352         if (argc < 2) usgflg++;
353         if (optind < argc) {
354                 desthostname = argv[optind++];
355         } else
356                 usgflg++;
357         if (usgflg) {
358                 fprintf(stderr, "usage: to send a job - %s -d printer -H hostname -P username [-s seqno] [-t[cdfgklnoprtvz]] desthost [filename]\n", argv[0]);
359                 fprintf(stderr, "     to check status - %s -d printer -q desthost\n", argv[0]);
360                 fprintf(stderr, "       to kill a job - %s -d printer -P username -k jobname desthost\n", argv[0]);
361                 exit(1);
362         }
363
364 /* make sure the file to send is here and ready
365  * otherwise the TCP connection times out.
366  */
367         if (!statflag && !killflag) {
368                 if (optind < argc) {
369                         inputname = argv[optind++];
370                         debug("open("); debug(inputname); debug(")\n");
371                         inputfd = open(inputname, O_RDONLY);
372                         if (inputfd < 0) {
373                                 fprintf(stderr, "open(%s) failed\n", inputname);
374                                 exit(1);
375                         }
376                 } else {
377                         inputname = "stdin";
378                         tmpnam(tmpfilename);
379                         debug("using stdin\n");
380                         if ((inputfd = open(tmpfilename, O_RDWR|O_CREAT, 0600)) < 0) {
381                                 fprintf(stderr, "open(%s) failed\n", tmpfilename);
382                                 exit(1);
383                         }
384                         atexit(cleanup);
385                         debug("copy input to temp file ");
386                         debug(tmpfilename);
387                         debug("\n");
388                         if (!copyfile(0, inputfd, 0L)) {
389                                 fprintf(stderr, "failed to copy file to temporary file\n");
390                                 exit(1);
391                         }
392                         if (lseek(inputfd, 0L, 0) < 0) {
393                                 fprintf(stderr, "failed to seek back to the beginning of the temporary file\n");
394                                 exit(1);
395                         }
396                 }
397         }
398
399         sprintf(strbuf, "%s", netmkaddr(desthostname, "tcp", "printer"));
400         fprintf(stderr, "connecting to %s\n", strbuf);
401         for (sendport=721; sendport<=731; sendport++) {
402                 sprintf(portstr, "%3.3d", sendport);
403                 fprintf(stderr, " trying from port %s...", portstr);
404                 debug(" dial("); debug(strbuf); debug(", "); debug(portstr); debug(", 0, 0) ...");
405                 printerfd = dial(strbuf, portstr, 0, 0);
406                 if (printerfd >= 0) {
407                         fprintf(stderr, "connected\n");
408                         break;
409                 }
410                 fprintf(stderr, "failed\n");
411                 sleep(REDIALTIMEOUT);
412         }
413         if (printerfd < 0) {
414                 fprintf(stderr, "Cannot open a valid port!\n");
415                 fprintf(stderr, "-  All source ports [721-731] may be busy.\n");
416                 fprintf(stderr, "-  Is recipient ready and online?\n");
417                 fprintf(stderr, "-  If all else fails, cycle the power!\n");
418                 exit(1);
419         }
420 /*      hostname[8] = '\0'; */
421 #ifndef PLAN9
422         if (gethostname(hostname, sizeof(hostname)) < 0) {
423                 perror("gethostname");
424                 exit(1);
425         }
426 #endif
427 /*      if ((hnend = strchr(hostname, '.')) != NULL)
428                 *hnend = '\0';
429  */
430         if (statflag) {
431                 checkqueue(printerfd);
432         } else if (killflag) {
433                 killjob(printerfd);
434         } else {
435                 sendjob(inputfd, printerfd);
436         }
437         exit(0);
438 }