lpdsend.c 9.4 KB

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