lpsend.c (6202B)
1 #ifdef plan9 2 3 #include <u.h> 4 #include <libc.h> 5 #define stderr 2 6 7 #define RDNETIMEOUT 60000 8 #define WRNETIMEOUT 60000 9 10 #else 11 12 /* not for plan 9 */ 13 #include <stdio.h> 14 #include <errno.h> 15 #include <time.h> 16 #include <fcntl.h> 17 #include <signal.h> 18 19 #define create creat 20 #define seek lseek 21 #define fprint fprintf 22 #define sprint sprintf 23 #define exits exit 24 25 #define ORDWR O_RDWR 26 #define OTRUNC O_TRUNC 27 #define ORCLOSE 0 28 29 #define RDNETIMEOUT 60 30 #define WRNETIMEOUT 60 31 32 #endif 33 34 #define MIN(a,b) ((a<b)?a:b) 35 36 #define ACK(a) write(a, "", 1) 37 #define NAK(a) write(a, "\001", 1) 38 39 #define LPDAEMONLOG "/tmp/lpdaemonl" 40 41 #define LNBFSZ 4096 42 char lnbuf[LNBFSZ]; 43 int dbgstate = 0; 44 char *dbgstrings[] = { 45 "", 46 "rcvack1", 47 "send", 48 "rcvack2", 49 "response", 50 "done" 51 }; 52 53 #ifdef plan9 54 55 void 56 error(int level, char *s1, ...) 57 { 58 va_list ap; 59 long thetime; 60 char *chartime; 61 char *args[8]; 62 int argno = 0; 63 64 if (level == 0) { 65 time(&thetime); 66 chartime = ctime(thetime); 67 fprint(stderr, "%.15s ", &(chartime[4])); 68 } 69 va_start(ap, s1); 70 while(args[argno++] = va_arg(ap, char*)); 71 va_end(ap); 72 fprint(stderr, s1, *args); 73 return; 74 } 75 76 int 77 alarmhandler(void *foo, char *note) { 78 USED(foo); 79 if(strcmp(note, "alarm")==0) { 80 fprint(stderr, "alarm at %d - %s\n", dbgstate, dbgstrings[dbgstate]); 81 return(1); 82 } else return(0); 83 } 84 85 #else 86 87 void 88 error(int level, char *s1, ...) 89 { 90 time_t thetime; 91 char *chartime; 92 93 if (level == 0) { 94 time(&thetime); 95 chartime = ctime(&thetime); 96 fprintf(stderr, "%.15s ", &(chartime[4])); 97 } 98 fprintf(stderr, s1, (&s1+1)); 99 return; 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 int tindx = 0; 184 char tmpf[20]; 185 int tmpfd; 186 187 sprint(tmpf, "/var/tmp/lp%d.%d", getpid(), tindx++); 188 if((tmpfd=create(tmpf, 189 190 #ifdef plan9 191 192 ORDWR|OTRUNC, 193 194 #endif 195 196 0666)) < 0) { 197 error(0, "cannot create temp file %s\n", tmpf); 198 exits("cannot create temp file"); 199 } 200 close(tmpfd); 201 if((tmpfd=open(tmpf, ORDWR 202 203 #ifdef plan9 204 205 |ORCLOSE|OTRUNC 206 207 #endif 208 209 )) < 0) { 210 error(0, "cannot open temp file %s\n", tmpf); 211 exits("cannot open temp file"); 212 } 213 return(tmpfd); 214 } 215 216 int 217 recvACK(int netfd) 218 { 219 int rv; 220 221 *jobbuf = '\0'; 222 alarm(RDNETIMEOUT); 223 if (read(netfd, jobbuf, 1)!=1 || *jobbuf!='\0') { 224 error(0, "failed to receive ACK, "); 225 if (*jobbuf == '\0') 226 error(1, "read failed\n"); 227 else 228 error(1, "received <0x%x> instead\n", *jobbuf); 229 rv = 0; 230 } else rv = 1; 231 alarm(0); 232 return(rv); 233 } 234 235 void 236 main(int argc, char *argv[]) 237 { 238 char *devdir; 239 int i, rv, netfd, bsize; 240 int datafd; 241 242 #ifndef plan9 243 244 void (*oldhandler)(); 245 246 #endif 247 248 devdir = nil; 249 /* make connection */ 250 if (argc != 2) { 251 fprint(stderr, "usage: %s network!destination!service\n", argv[0]); 252 exits("incorrect number of arguments"); 253 } 254 255 /* read options line from stdin into lnbuf */ 256 i = readline(0); 257 258 /* read stdin into tempfile to get size */ 259 datafd = tempfile(); 260 bsize = prereadfile(datafd); 261 262 /* network connection is opened after data is in to avoid timeout */ 263 if ((netfd=dial(argv[1], 0, 0, 0)) < 0) { 264 fprint(stderr, "dialing %s\n", devdir); 265 perror("dial"); 266 exits("can't dial"); 267 } 268 269 /* write out the options we read above */ 270 if (write(netfd, lnbuf, i) != i) { 271 error(0, "write error while sending options\n"); 272 exits("write error while sending options"); 273 } 274 275 /* send the size of the file to be sent */ 276 sprint(lnbuf, "%d\n", bsize); 277 i = strlen(lnbuf); 278 if ((rv=write(netfd, lnbuf, i)) != i) { 279 perror("write error while sending size"); 280 error(0, "write returned %d\n", rv); 281 exits("write error while sending size"); 282 } 283 284 if (seek(datafd, 0L, 0) < 0) { 285 error(0, "error seeking temp file\n"); 286 exits("seek error"); 287 } 288 /* mirror performance in readfile() in lpdaemon */ 289 290 #ifdef plan9 291 292 atnotify(alarmhandler, 1); 293 294 #else 295 296 oldhandler = signal(SIGALRM, alarmhandler); 297 298 #endif 299 300 dbgstate = 1; 301 if(!recvACK(netfd)) { 302 error(0, "failed to receive ACK before sending data\n"); 303 exits("recv ack1 failed"); 304 } 305 dbgstate = 2; 306 if ((i=pass(datafd, netfd, bsize)) != 0) { 307 NAK(netfd); 308 error(0, "failed to send %d bytes\n", i); 309 exits("send data failed"); 310 } 311 ACK(netfd); 312 dbgstate = 3; 313 if(!recvACK(netfd)) { 314 error(0, "failed to receive ACK after sending data\n"); 315 exits("recv ack2 failed"); 316 } 317 318 /* get response, as from lp -q */ 319 dbgstate = 4; 320 while((rv=read(netfd, jobbuf, RDSIZE)) > 0) { 321 if((write(1, jobbuf, rv)) != rv) { 322 error(0, "write error while sending to stdout\n"); 323 exits("write error while sending to stdout"); 324 } 325 } 326 dbgstate = 5; 327 328 #ifdef plan9 329 330 atnotify(alarmhandler, 0); 331 /* close down network connections and go away */ 332 exits(""); 333 334 #else 335 336 signal(SIGALRM, oldhandler); 337 exit(0); 338 339 #endif 340 341 }