diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-02-24 18:44:20 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-02-24 18:44:20 +0000 |
commit | 4f82bdb050024b3475f5371a0612b1fb0fc4c09f (patch) | |
tree | ba0f2f986546c7798553f76c305f052b2b190048 | |
parent | 52feee9b1fc996acb9c2857596bc5c2440644525 (diff) | |
download | busybox-w32-4f82bdb050024b3475f5371a0612b1fb0fc4c09f.tar.gz busybox-w32-4f82bdb050024b3475f5371a0612b1fb0fc4c09f.tar.bz2 busybox-w32-4f82bdb050024b3475f5371a0612b1fb0fc4c09f.zip |
lpr,lpq: rework by dronnikov AT gmail.com
-rw-r--r-- | include/applets.h | 4 | ||||
-rw-r--r-- | include/usage.h | 13 | ||||
-rw-r--r-- | printutils/Kbuild | 4 | ||||
-rw-r--r-- | printutils/lpq.c | 108 | ||||
-rw-r--r-- | printutils/lpr.c | 364 | ||||
-rw-r--r-- | printutils/lpr.h | 17 | ||||
-rw-r--r-- | printutils/parse_prt.c | 27 |
7 files changed, 211 insertions, 326 deletions
diff --git a/include/applets.h b/include/applets.h index f2de31c0b..ffd7afc67 100644 --- a/include/applets.h +++ b/include/applets.h | |||
@@ -227,8 +227,8 @@ USE_LOGIN(APPLET(login, _BB_DIR_BIN, _BB_SUID_ALWAYS)) | |||
227 | USE_LOGNAME(APPLET_NOFORK(logname, logname, _BB_DIR_USR_BIN, _BB_SUID_NEVER, logname)) | 227 | USE_LOGNAME(APPLET_NOFORK(logname, logname, _BB_DIR_USR_BIN, _BB_SUID_NEVER, logname)) |
228 | USE_LOGREAD(APPLET(logread, _BB_DIR_SBIN, _BB_SUID_NEVER)) | 228 | USE_LOGREAD(APPLET(logread, _BB_DIR_SBIN, _BB_SUID_NEVER)) |
229 | USE_LOSETUP(APPLET(losetup, _BB_DIR_SBIN, _BB_SUID_NEVER)) | 229 | USE_LOSETUP(APPLET(losetup, _BB_DIR_SBIN, _BB_SUID_NEVER)) |
230 | USE_LPQ(APPLET(lpq, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | 230 | USE_LPQ(APPLET_ODDNAME(lpq, lpqr, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lpq)) |
231 | USE_LPR(APPLET(lpr, _BB_DIR_USR_BIN, _BB_SUID_NEVER)) | 231 | USE_LPR(APPLET_ODDNAME(lpr, lpqr, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lpr)) |
232 | USE_LS(APPLET_NOEXEC(ls, ls, _BB_DIR_BIN, _BB_SUID_NEVER, ls)) | 232 | USE_LS(APPLET_NOEXEC(ls, ls, _BB_DIR_BIN, _BB_SUID_NEVER, ls)) |
233 | USE_LSATTR(APPLET(lsattr, _BB_DIR_BIN, _BB_SUID_NEVER)) | 233 | USE_LSATTR(APPLET(lsattr, _BB_DIR_BIN, _BB_SUID_NEVER)) |
234 | USE_LSMOD(APPLET(lsmod, _BB_DIR_SBIN, _BB_SUID_NEVER)) | 234 | USE_LSMOD(APPLET(lsmod, _BB_DIR_SBIN, _BB_SUID_NEVER)) |
diff --git a/include/usage.h b/include/usage.h index 11d3e3ad2..c9329b30b 100644 --- a/include/usage.h +++ b/include/usage.h | |||
@@ -2052,22 +2052,23 @@ USE_FEATURE_BRCTL_FANCY("\n" \ | |||
2052 | "losetup -f will show the first loop free loop device\n\n" | 2052 | "losetup -f will show the first loop free loop device\n\n" |
2053 | 2053 | ||
2054 | #define lpq_trivial_usage \ | 2054 | #define lpq_trivial_usage \ |
2055 | "[-P lp[@host[:port]]] [-t DELAY] [-d JOBID] [-fs]" | 2055 | "[-P queue[@host[:port]]] [-U USERNAME] [-d JOBID...] [-fs]" |
2056 | #define lpq_full_usage \ | 2056 | #define lpq_full_usage \ |
2057 | "Options:" \ | 2057 | "Options:" \ |
2058 | "\n -P lp service to connect to (else uses $PRINTER)" \ | 2058 | "\n -P lp service to connect to (else uses $PRINTER)" \ |
2059 | "\n -t Scan the queue every DELAY seconds" \ | 2059 | "\n -d Delete jobs" \ |
2060 | "\n -d Delete job" \ | ||
2061 | "\n -f Force any waiting job to be printed" \ | 2060 | "\n -f Force any waiting job to be printed" \ |
2062 | "\n -s Short display" \ | 2061 | "\n -s Short display" \ |
2063 | 2062 | ||
2064 | #define lpr_trivial_usage \ | 2063 | #define lpr_trivial_usage \ |
2065 | "-P lp[@host[:port]] -U USERNAME -J TITLE -Vmh [filenames]" | 2064 | "-P queue[@host[:port]] -U USERNAME -J TITLE -Vmh [FILE...]" |
2065 | /* -C CLASS exists too, not shown. | ||
2066 | * CLASS is supposed to be printed on banner page, if one is requested */ | ||
2066 | #define lpr_full_usage \ | 2067 | #define lpr_full_usage \ |
2067 | "Options:" \ | 2068 | "Options:" \ |
2068 | "\n -P lp service to connect to (else uses $PRINTER)"\ | 2069 | "\n -P lp service to connect to (else uses $PRINTER)"\ |
2069 | "\n -m Send mail to LOGNAME@HOSTNAME" \ | 2070 | "\n -m Send mail on completion" \ |
2070 | "\n -h Banner or header for this job" \ | 2071 | "\n -h Print banner page too" \ |
2071 | "\n -V Verbose" \ | 2072 | "\n -V Verbose" \ |
2072 | 2073 | ||
2073 | #define ls_trivial_usage \ | 2074 | #define ls_trivial_usage \ |
diff --git a/printutils/Kbuild b/printutils/Kbuild index f32272334..4f97d0d15 100644 --- a/printutils/Kbuild +++ b/printutils/Kbuild | |||
@@ -4,5 +4,5 @@ | |||
4 | 4 | ||
5 | lib-y := | 5 | lib-y := |
6 | 6 | ||
7 | lib-$(CONFIG_LPR) += lpr.o parse_prt.o | 7 | lib-$(CONFIG_LPR) += lpr.o |
8 | lib-$(CONFIG_LPQ) += lpq.o parse_prt.o | 8 | lib-$(CONFIG_LPQ) += lpr.o |
diff --git a/printutils/lpq.c b/printutils/lpq.c deleted file mode 100644 index ce9a10cb3..000000000 --- a/printutils/lpq.c +++ /dev/null | |||
@@ -1,108 +0,0 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Copyright 2008 Walter Harms (WHarms@bfs.de) | ||
4 | * | ||
5 | * Licensed under the GPL v2, see the file LICENSE in this tarball. | ||
6 | */ | ||
7 | #include "libbb.h" | ||
8 | #include "lpr.h" | ||
9 | |||
10 | /* | ||
11 | this is a *very* resticted form of lpq | ||
12 | since we do not read /etc/printcap (and never will) | ||
13 | we can only do things rfc1179 allows: | ||
14 | - show print jobs for a given queue long/short form | ||
15 | - remove a job from a given queue | ||
16 | |||
17 | -P <queue> | ||
18 | -s short | ||
19 | -d delete job | ||
20 | -f force any waiting job to be printed | ||
21 | */ | ||
22 | enum { | ||
23 | LPQ_SHORT = 1 << 0, | ||
24 | LPQ_DELETE = 1 << 1, | ||
25 | LPQ_FORCE = 1 << 2, | ||
26 | LPQ_P = 1 << 3, | ||
27 | LPQ_t = 1 << 4, | ||
28 | }; | ||
29 | |||
30 | /* | ||
31 | print everthing that comes | ||
32 | */ | ||
33 | static void get_answer(int sockfd) | ||
34 | { | ||
35 | char buf[80]; | ||
36 | int n; | ||
37 | |||
38 | buf[0] = '\n'; | ||
39 | while (1) { | ||
40 | n = safe_read(sockfd, buf, sizeof(buf)); | ||
41 | if (n <= 0) | ||
42 | break; | ||
43 | full_write(STDOUT_FILENO, buf, n); | ||
44 | buf[0] = buf[n-1]; /* last written char */ | ||
45 | } | ||
46 | |||
47 | /* Don't leave last output line unterminated */ | ||
48 | if (buf[0] != '\n') | ||
49 | full_write(STDOUT_FILENO, "\n", 1); | ||
50 | } | ||
51 | |||
52 | /* | ||
53 | is this too simple ? | ||
54 | should we support more ENV ? | ||
55 | PRINTER, LPDEST, NPRINTER, NGPRINTER | ||
56 | */ | ||
57 | int lpq_main(int argc, char *argv[]) MAIN_EXTERNALLY_VISIBLE; | ||
58 | int lpq_main(int argc, char *argv[]) | ||
59 | { | ||
60 | struct netprint netprint; | ||
61 | const char *netopt; | ||
62 | const char *delopt = "0"; | ||
63 | int sockfd = sockfd; /* for compiler */ | ||
64 | unsigned opt; | ||
65 | int delay; /* delay in [s] */ | ||
66 | |||
67 | netopt = NULL; | ||
68 | opt = getopt32(argv, "sdfP:t:", &netopt, &delopt); | ||
69 | argv += optind; | ||
70 | delay = xatoi_u(delopt); | ||
71 | parse_prt(netopt, &netprint); | ||
72 | |||
73 | /* do connect */ | ||
74 | if (opt & (LPQ_FORCE|LPQ_DELETE)) | ||
75 | sockfd = xconnect_stream(netprint.lsa); | ||
76 | |||
77 | /* force printing of every job still in queue */ | ||
78 | if (opt & LPQ_FORCE) { | ||
79 | fdprintf(sockfd, "\x1" "%s", netprint.queue); | ||
80 | get_answer(sockfd); | ||
81 | return EXIT_SUCCESS; | ||
82 | } | ||
83 | |||
84 | /* delete job (better a list of jobs). username is now LOGNAME */ | ||
85 | if (opt & LPQ_DELETE) { | ||
86 | while (*argv) { | ||
87 | fdprintf(sockfd, "\x5" "%s %s %s", | ||
88 | netprint.queue, | ||
89 | getenv("LOGNAME"), /* FIXME - may be NULL? */ | ||
90 | *argv); | ||
91 | get_answer(sockfd); | ||
92 | argv++; | ||
93 | } | ||
94 | return EXIT_SUCCESS; | ||
95 | } | ||
96 | |||
97 | do { | ||
98 | sockfd = xconnect_stream(netprint.lsa); | ||
99 | fdprintf(sockfd, "%c%s\n", (opt & LPQ_SHORT) ? 3 : 4, | ||
100 | netprint.queue); | ||
101 | |||
102 | get_answer(sockfd); | ||
103 | close(sockfd); | ||
104 | sleep(delay); | ||
105 | } while (delay != 0); | ||
106 | |||
107 | return EXIT_SUCCESS; | ||
108 | } | ||
diff --git a/printutils/lpr.c b/printutils/lpr.c index 865071011..ea0e21091 100644 --- a/printutils/lpr.c +++ b/printutils/lpr.c | |||
@@ -1,200 +1,236 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | 1 | /* vi: set sw=4 ts=4: */ |
2 | /* | 2 | /* |
3 | * Copyright 2008 Walter Harms (WHarms@bfs.de) | 3 | * bare bones version of lpr & lpq: BSD printing utilities |
4 | * | 4 | * |
5 | * Licensed under the GPL v2, see the file LICENSE in this tarball. | 5 | * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com> |
6 | * | ||
7 | * Original idea and code: | ||
8 | * Walter Harms <WHarms@bfs.de> | ||
9 | * | ||
10 | * Licensed under GPLv2, see file LICENSE in this tarball for details. | ||
11 | * | ||
12 | * See RFC 1179 for propocol description. | ||
6 | */ | 13 | */ |
7 | #include "libbb.h" | 14 | #include "libbb.h" |
8 | #include "lpr.h" | ||
9 | |||
10 | static char *mygethostname31(void) | ||
11 | { | ||
12 | char *s = xzalloc(32); | ||
13 | if (gethostname(s, 31) < 0) | ||
14 | bb_perror_msg_and_die("gethostname"); | ||
15 | /* gethostname() does not guarantee NUL-termination. xzalloc does. */ | ||
16 | return s; | ||
17 | } | ||
18 | |||
19 | static int xmkstemp(char *temp_name) | ||
20 | { | ||
21 | int fd; | ||
22 | 15 | ||
23 | fd = mkstemp(temp_name); | 16 | /* |
24 | if (fd < 0) | 17 | * LPD returns binary 0 on success. |
25 | bb_perror_msg_and_die("mkstemp"); | 18 | * Otherwise it returns error message. |
26 | return fd; | ||
27 | } | ||
28 | |||
29 | /* lpd server sends NUL byte on success. | ||
30 | * Else read the errormessage and exit. | ||
31 | */ | 19 | */ |
32 | static void get_response(int server_sock, const char *emsg) | 20 | static void get_response_or_say_and_die(const char *errmsg) |
33 | { | 21 | { |
34 | char buf = '\0'; | 22 | char buf = ' '; |
23 | |||
24 | fflush(stdout); | ||
35 | 25 | ||
36 | safe_read(server_sock, &buf, 1); | 26 | safe_read(STDOUT_FILENO, &buf, 1); |
37 | if (buf != '\0') { | 27 | if ('\0' != buf) { |
38 | bb_error_msg("%s. Server said:", emsg); | 28 | // request has failed |
39 | fputc(buf, stderr); | 29 | bb_error_msg("error while %s. Server said:", errmsg); |
30 | safe_write(STDERR_FILENO, &buf, 1); | ||
40 | logmode = 0; /* no errors from bb_copyfd_eof() */ | 31 | logmode = 0; /* no errors from bb_copyfd_eof() */ |
41 | bb_copyfd_eof(server_sock, STDERR_FILENO); | 32 | bb_copyfd_eof(STDOUT_FILENO, STDERR_FILENO); |
42 | xfunc_die(); | 33 | xfunc_die(); |
43 | } | 34 | } |
44 | } | 35 | } |
45 | 36 | ||
46 | int lpr_main(int argc, char *argv[]) MAIN_EXTERNALLY_VISIBLE; | 37 | int lpqr_main(int argc, char *argv[]) MAIN_EXTERNALLY_VISIBLE; |
47 | int lpr_main(int argc, char *argv[]) | 38 | int lpqr_main(int argc, char *argv[]) |
48 | { | 39 | { |
49 | struct netprint netprint; | ||
50 | char temp_name[] = "/tmp/lprXXXXXX"; /* for mkstemp */ | ||
51 | char *strings[5]; | ||
52 | const char *netopt; | ||
53 | const char *jobtitle; | ||
54 | const char *hostname; | ||
55 | const char *jobclass; | ||
56 | char *username; | ||
57 | int pid1000; | ||
58 | int server_sock, tmp_fd; | ||
59 | unsigned opt; | ||
60 | enum { | 40 | enum { |
61 | VERBOSE = 1 << 0, | 41 | OPT_P = 1 << 0, // -P queue[@host[:port]]. If no -P is given use $PRINTER, then "lp@localhost:515" |
62 | USE_HEADER = 1 << 1, /* -h: want banner printed */ | 42 | OPT_U = 1 << 1, // -U username |
63 | USE_MAIL = 1 << 2, /* -m: send mail back to user */ | 43 | |
64 | OPT_U = 1 << 3, /* -U username */ | 44 | LPR_V = 1 << 2, // -V: be verbose |
65 | OPT_J = 1 << 4, /* -J title: the job title for the banner page */ | 45 | LPR_h = 1 << 3, // -h: want banner printed |
66 | OPT_C = 1 << 5, /* -C class: job "class" (? supposedly printed on banner) */ | 46 | LPR_C = 1 << 4, // -C class: job "class" (? supposedly printed on banner) |
67 | OPT_P = 1 << 6, /* -P queue[@host[:port]] */ | 47 | LPR_J = 1 << 5, // -J title: the job title for the banner page |
68 | /* if no -P is given use $PRINTER, then "lp@localhost:515" */ | 48 | LPR_m = 1 << 6, // -m: send mail back to user |
49 | |||
50 | LPQ_SHORT_FMT = 1 << 2, // -s: short listing format | ||
51 | LPQ_DELETE = 1 << 3, // -d: delete job(s) | ||
52 | LPQ_FORCE = 1 << 4, // -f: force waiting job(s) to be printed | ||
69 | }; | 53 | }; |
70 | 54 | char tempfile[sizeof("/tmp/lprXXXXXX")]; | |
71 | /* Set defaults, parse options */ | 55 | const char *job_title; |
72 | hostname = mygethostname31(); | 56 | const char *printer_class = ""; // printer class, max 32 char |
73 | netopt = NULL; | 57 | const char *queue; // name of printer queue |
74 | username = getenv("LOGNAME"); | 58 | const char *server = "localhost"; // server[:port] of printer queue |
75 | if (username == NULL) | 59 | char *hostname; |
76 | username = (char*)"user"; /* TODO: getpwuid(getuid())->pw_name? */ | 60 | // N.B. IMHO getenv("USER") can be way easily spoofed! |
77 | opt = getopt32(argv, "VhmU:J:C:P:", | 61 | const char *user = bb_getpwuid(NULL, -1, getuid()); |
78 | &username, &jobtitle, &jobclass, &netopt); | 62 | unsigned job; |
63 | unsigned opts; | ||
64 | int old_stdout, fd; | ||
65 | |||
66 | // parse options | ||
67 | // TODO: set opt_complementary: s,d,f are mutually exclusive | ||
68 | opts = getopt32(argv, | ||
69 | (/*lp*/'r' == applet_name[2]) ? "P:U:VhC:J:m" : "P:U:sdf" | ||
70 | , &queue, &user | ||
71 | , &printer_class, &job_title | ||
72 | ); | ||
79 | argv += optind; | 73 | argv += optind; |
80 | parse_prt(netopt, &netprint); | 74 | |
81 | username = xstrndup(username, 31); | 75 | // if queue is not specified -> use $PRINTER |
82 | 76 | if (!(opts & OPT_P)) | |
83 | /* For stdin we need to save it to a tempfile, | 77 | queue = getenv("PRINTER"); |
84 | * otherwise we can't know the size. */ | 78 | // if queue is still not specified -> |
85 | tmp_fd = -1; | 79 | if (!queue) { |
86 | if (!*argv) { | 80 | // ... queue defaults to "lp" |
87 | if (jobtitle == NULL) | 81 | // server defaults to "localhost" |
88 | jobtitle = (char *) bb_msg_standard_input; | 82 | queue = "lp"; |
89 | 83 | // if queue is specified -> | |
90 | tmp_fd = xmkstemp(temp_name); | 84 | } else { |
91 | if (bb_copyfd_eof(STDIN_FILENO, tmp_fd) < 0) | 85 | // queue name is to the left of '@' |
92 | goto del_temp_file; | 86 | char *s = strchr(queue, '@'); |
93 | /* TODO: we actually can have deferred write errors... */ | 87 | if (s) { |
94 | close(tmp_fd); | 88 | // server name is to the right of '@' |
95 | argv--; /* back off from NULL */ | 89 | *s = '\0'; |
96 | *argv = temp_name; | 90 | server = s + 1; |
91 | } | ||
97 | } | 92 | } |
98 | 93 | ||
99 | if (opt & VERBOSE) | 94 | // do connect |
100 | puts("connect to server"); | 95 | fd = create_and_connect_stream_or_die(server, 515); |
101 | server_sock = xconnect_stream(netprint.lsa); | 96 | // play with descriptors to save space: fdprintf > printf |
97 | old_stdout = dup(STDOUT_FILENO); | ||
98 | xmove_fd(fd, STDOUT_FILENO); | ||
99 | |||
100 | // | ||
101 | // LPQ ------------------------ | ||
102 | // | ||
103 | if (/*lp*/'q' == applet_name[2]) { | ||
104 | char cmd; | ||
105 | // force printing of every job still in queue | ||
106 | if (opts & LPQ_FORCE) { | ||
107 | cmd = 1; | ||
108 | goto command; | ||
109 | // delete job(s) | ||
110 | } else if (opts & LPQ_DELETE) { | ||
111 | printf("\x5" "%s %s", queue, user); | ||
112 | while (*argv) { | ||
113 | printf(" %s", *argv++); | ||
114 | } | ||
115 | bb_putchar('\n'); | ||
116 | // dump current jobs status | ||
117 | // N.B. periodical polling should be achieved | ||
118 | // via "watch -n delay lpq" | ||
119 | // They say it's the UNIX-way :) | ||
120 | } else { | ||
121 | cmd = (opts & LPQ_SHORT_FMT) ? 3 : 4; | ||
122 | command: | ||
123 | printf("%c" "%s\n", cmd, queue); | ||
124 | bb_copyfd_eof(STDOUT_FILENO, old_stdout); | ||
125 | } | ||
102 | 126 | ||
103 | /* "Receive a printer job" command */ | 127 | return EXIT_SUCCESS; |
104 | fdprintf(server_sock, "\x2" "%s\n", netprint.queue); | 128 | } |
105 | get_response(server_sock, "set queue failed"); | ||
106 | 129 | ||
107 | pid1000 = getpid() % 1000; | 130 | // |
108 | while (*argv) { | 131 | // LPR ------------------------ |
109 | char dfa_name[sizeof("dfAnnn") + 32]; | 132 | // |
110 | struct stat st; | 133 | if (opts & LPR_V) |
111 | char **sptr; | 134 | bb_error_msg("connected to server"); |
112 | unsigned size; | ||
113 | int fd; | ||
114 | 135 | ||
115 | fd = xopen(*argv, O_RDONLY); | 136 | job = getpid() % 1000; |
137 | // TODO: when do finally we invent char *xgethostname()?!! | ||
138 | hostname = xzalloc(MAXHOSTNAMELEN+1); | ||
139 | gethostname(hostname, MAXHOSTNAMELEN); | ||
116 | 140 | ||
117 | /* "The name ... should start with ASCII "dfA", | 141 | // no files given on command line? -> use stdin |
118 | * followed by a three digit job number, followed | 142 | if (!*argv) |
119 | * by the host name which has constructed the file." */ | 143 | *--argv = (char *)"-"; |
120 | snprintf(dfa_name, sizeof(dfa_name), | 144 | |
121 | "dfA%03u%s", pid1000, hostname); | 145 | printf("\x2" "%s\n", queue); |
122 | pid1000 = (pid1000 + 1) % 1000; | 146 | get_response_or_say_and_die("setting queue"); |
123 | 147 | ||
124 | /* | 148 | // process files |
125 | * Generate control file contents | 149 | do { |
126 | */ | 150 | struct stat st; |
127 | /* H HOST, P USER, l DATA_FILE_NAME, J JOBNAME */ | 151 | char *c; |
128 | strings[0] = xasprintf("H%.32s\n" "P%.32s\n" "l%.32s\n" | 152 | char *remote_filename; |
129 | "J%.99s\n", | 153 | char *controlfile; |
130 | hostname, username, dfa_name, | 154 | |
131 | (opt & OPT_J) ? jobtitle : *argv); | 155 | // if data file is stdin, we need to dump it first |
132 | sptr = &strings[1]; | 156 | if (LONE_DASH(*argv)) { |
133 | /* C CLASS - printed on banner page (if L cmd is also given) */ | 157 | strcpy(tempfile, "/tmp/lprXXXXXX"); |
134 | if (opt & OPT_C) /* [1] */ | 158 | fd = mkstemp(tempfile); |
135 | *sptr++ = xasprintf("C%.32s\n", jobclass); | 159 | if (fd < 0) |
136 | /* M WHOM_TO_MAIL */ | 160 | bb_perror_msg_and_die("mkstemp"); |
137 | if (opt & USE_MAIL) /* [2] */ | 161 | bb_copyfd_eof(STDIN_FILENO, fd); |
138 | *sptr++ = xasprintf("M%.32s\n", username); | 162 | xlseek(fd, 0, SEEK_SET); |
139 | /* H USER - print banner page, with given user's name */ | 163 | *argv = (char*)bb_msg_standard_input; |
140 | if (opt & USE_HEADER) /* [3] */ | 164 | } else { |
141 | *sptr++ = xasprintf("L%.32s\n", username); | 165 | fd = xopen(*argv, O_RDONLY); |
142 | *sptr = NULL; /* [4] max */ | ||
143 | |||
144 | /* RFC 1179: "LPR servers MUST be able | ||
145 | * to receive the control file subcommand first | ||
146 | * and SHOULD be able to receive the data file | ||
147 | * subcommand first". | ||
148 | * Ok, we'll send control file first. */ | ||
149 | size = 0; | ||
150 | sptr = strings; | ||
151 | while (*sptr) | ||
152 | size += strlen(*sptr++); | ||
153 | if (opt & VERBOSE) | ||
154 | puts("send control file"); | ||
155 | /* 2: "Receive control file" subcommand */ | ||
156 | fdprintf(server_sock, "\x2" "%u c%s\n", size, dfa_name + 1); | ||
157 | sptr = strings; | ||
158 | while (*sptr) { | ||
159 | xwrite(server_sock, *sptr, strlen(*sptr)); | ||
160 | free(*sptr); | ||
161 | sptr++; | ||
162 | } | 166 | } |
163 | free(strings); | 167 | |
168 | /* "The name ... should start with ASCII "cfA", | ||
169 | * followed by a three digit job number, followed | ||
170 | * by the host name which has constructed the file." | ||
171 | * We supply 'c' or 'd' as needed for control/data file. */ | ||
172 | remote_filename = xasprintf("fA%03u%s", job, hostname); | ||
173 | |||
174 | // create control file | ||
175 | // TODO: all lines but 2 last are constants! How we can use this fact? | ||
176 | controlfile = xasprintf( | ||
177 | "H" "%.32s\n" "P" "%.32s\n" /* H HOST, P USER */ | ||
178 | "C" "%.32s\n" /* C CLASS - printed on banner page (if L cmd is also given) */ | ||
179 | "J" "%.99s\n" /* J JOBNAME */ | ||
180 | /* "class name for banner page and job name | ||
181 | * for banner page commands must precede L command" */ | ||
182 | "L" "%.32s\n" /* L USER - print banner page, with given user's name */ | ||
183 | "M" "%.32s\n" /* M WHOM_TO_MAIL */ | ||
184 | "l" "d%.31s\n" /* l DATA_FILE_NAME ("dfAxxx") */ | ||
185 | , hostname, user | ||
186 | , printer_class /* can be "" */ | ||
187 | , ((opts & LPR_J) ? job_title : *argv) | ||
188 | , (opts & LPR_h) ? user : "" | ||
189 | , (opts & LPR_m) ? user : "" | ||
190 | , remote_filename | ||
191 | ); | ||
192 | // delete possible "\nX\n" patterns | ||
193 | while ((c = strchr(controlfile, '\n')) != NULL && c[1] && c[2] == '\n') | ||
194 | memmove(c, c+2, strlen(c+1)); /* strlen(c+1) == strlen(c+2) + 1 */ | ||
195 | |||
196 | // send control file | ||
197 | if (opts & LPR_V) | ||
198 | bb_error_msg("sending control file"); | ||
164 | /* "Once all of the contents have | 199 | /* "Once all of the contents have |
165 | * been delivered, an octet of zero bits is sent as | 200 | * been delivered, an octet of zero bits is sent as |
166 | * an indication that the file being sent is complete. | 201 | * an indication that the file being sent is complete. |
167 | * A second level of acknowledgement processing | 202 | * A second level of acknowledgement processing |
168 | * must occur at this point." */ | 203 | * must occur at this point." */ |
169 | xwrite(server_sock, "", 1); | 204 | printf("\x2" "%u %s\n" "c%s" "%c", |
170 | get_response(server_sock, "send control file failed"); | 205 | (unsigned)strlen(controlfile), |
171 | 206 | remote_filename, controlfile, '\0'); | |
172 | /* Sending data */ | 207 | get_response_or_say_and_die("sending control file"); |
173 | st.st_size = 0; /* paranoia */ | 208 | |
209 | // send data file, with name "dfaXXX" | ||
210 | if (opts & LPR_V) | ||
211 | bb_error_msg("sending data file"); | ||
212 | st.st_size = 0; /* paranoia: fstat may theoretically fail */ | ||
174 | fstat(fd, &st); | 213 | fstat(fd, &st); |
175 | if (opt & VERBOSE) | 214 | printf("\x3" "%"OFF_FMT"u d%s\n", st.st_size, remote_filename); |
176 | puts("send data file"); | 215 | if (bb_copyfd_size(fd, STDOUT_FILENO, st.st_size) != st.st_size) { |
177 | /* 3: "Receive data file" subcommand */ | 216 | // We're screwed. We sent less bytes than we advertised. |
178 | fdprintf(server_sock, "\x3" "%"OFF_FMT"u %s\n", st.st_size, dfa_name); | 217 | bb_error_msg_and_die("local file changed size?!"); |
179 | /* TODO: if file shrank and we wrote less than st.st_size, | 218 | } |
180 | * pad output with NUL bytes? Otherwise server won't know | 219 | bb_putchar('\0'); |
181 | * that we are done. */ | 220 | get_response_or_say_and_die("sending data file"); |
182 | if (bb_copyfd_size(fd, server_sock, st.st_size) < 0) | ||
183 | xfunc_die(); | ||
184 | close(fd); | ||
185 | xwrite(server_sock, "", 1); | ||
186 | get_response(server_sock, "send file failed"); | ||
187 | 221 | ||
188 | argv++; | 222 | // delete temporary file if we dumped stdin |
189 | } | 223 | if (*argv == (char*)bb_msg_standard_input) |
224 | unlink(tempfile); | ||
190 | 225 | ||
191 | if (ENABLE_FEATURE_CLEAN_UP) | 226 | // cleanup |
192 | close(server_sock); | 227 | close(fd); |
228 | free(remote_filename); | ||
229 | free(controlfile); | ||
193 | 230 | ||
194 | if (tmp_fd >= 0) { | 231 | // next, please! |
195 | del_temp_file: | 232 | job = (job + 1) % 1000; |
196 | unlink(temp_name); | 233 | } while (*++argv); |
197 | } | ||
198 | 234 | ||
199 | return 0; | 235 | return EXIT_SUCCESS; |
200 | } | 236 | } |
diff --git a/printutils/lpr.h b/printutils/lpr.h deleted file mode 100644 index 8898b982f..000000000 --- a/printutils/lpr.h +++ /dev/null | |||
@@ -1,17 +0,0 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Copyright 2008 Walter Harms (WHarms@bfs.de) | ||
4 | * | ||
5 | * Licensed under the GPL v2, see the file LICENSE in this tarball. | ||
6 | */ | ||
7 | #ifndef _LPR_H_ | ||
8 | #define _LPR_H_ | ||
9 | |||
10 | struct netprint { | ||
11 | char *queue; | ||
12 | char *server; | ||
13 | struct len_and_sockaddr *lsa; | ||
14 | }; | ||
15 | |||
16 | void parse_prt(const char *buf, struct netprint *netprint); | ||
17 | #endif | ||
diff --git a/printutils/parse_prt.c b/printutils/parse_prt.c deleted file mode 100644 index 2de0a9215..000000000 --- a/printutils/parse_prt.c +++ /dev/null | |||
@@ -1,27 +0,0 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Copyright 2008 Walter Harms (WHarms@bfs.de) | ||
4 | * | ||
5 | * Licensed under the GPL v2, see the file LICENSE in this tarball. | ||
6 | */ | ||
7 | #include "libbb.h" | ||
8 | #include "lpr.h" | ||
9 | |||
10 | void parse_prt(const char *buf, struct netprint *netprint) | ||
11 | { | ||
12 | const char *p; | ||
13 | |||
14 | if (!buf) { | ||
15 | buf = getenv("PRINTER"); | ||
16 | if (!buf) | ||
17 | buf = "lp"; /* "...@localhost:515" is implied */ | ||
18 | } | ||
19 | p = strchrnul(buf, '@'); | ||
20 | netprint->queue = xstrndup(buf, p - buf); | ||
21 | if (!*p) /* just queue? example: "lpq -Pcopie" */ | ||
22 | p = "localhost"; | ||
23 | netprint->server = xstrdup(p); | ||
24 | |||
25 | netprint->lsa = xhost2sockaddr(netprint->server, | ||
26 | bb_lookup_port(NULL, "tcp", 515)); | ||
27 | } | ||