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 } 439