diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-02-22 22:24:48 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-02-22 22:24:48 +0000 |
commit | 68444b9f0c74e94d219fa40bb4109b4aa2fdd43b (patch) | |
tree | 34b1c0d65ac46498b81df8badd85f9daa0baed33 /printutils/lpr.c | |
parent | 6aa74fcf5bc5f6b209b578754fc098714bc8485d (diff) | |
download | busybox-w32-68444b9f0c74e94d219fa40bb4109b4aa2fdd43b.tar.gz busybox-w32-68444b9f0c74e94d219fa40bb4109b4aa2fdd43b.tar.bz2 busybox-w32-68444b9f0c74e94d219fa40bb4109b4aa2fdd43b.zip |
lpr and lpq applets by Walter Harms.
text data bss dec hex filename
392 0 0 392 188 lpq.o
1378 0 0 1378 562 lpr.o
142 0 0 142 8e parse_prt.o
Diffstat (limited to 'printutils/lpr.c')
-rw-r--r-- | printutils/lpr.c | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/printutils/lpr.c b/printutils/lpr.c new file mode 100644 index 000000000..b8c77bfc3 --- /dev/null +++ b/printutils/lpr.c | |||
@@ -0,0 +1,200 @@ | |||
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 | 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 | |||
23 | fd = mkstemp(temp_name); | ||
24 | if (fd < 0) | ||
25 | bb_perror_msg_and_die("mkstemp"); | ||
26 | return fd; | ||
27 | } | ||
28 | |||
29 | /* lpd server sends NUL byte on success. | ||
30 | * Else read the errormessage and exit. | ||
31 | */ | ||
32 | static void get_response(int server_sock, const char *emsg) | ||
33 | { | ||
34 | char buf = '\0'; | ||
35 | |||
36 | safe_read(server_sock, &buf, 1); | ||
37 | if (buf != '\0') { | ||
38 | bb_error_msg("%s. Server said:", emsg); | ||
39 | fputc(buf, stderr); | ||
40 | logmode = 0; /* no errors from bb_copyfd_eof() */ | ||
41 | bb_copyfd_eof(server_sock, STDERR_FILENO); | ||
42 | xfunc_die(); | ||
43 | } | ||
44 | } | ||
45 | |||
46 | int lpr_main(int argc, char *argv[]) MAIN_EXTERNALLY_VISIBLE; | ||
47 | int lpr_main(int argc, char *argv[]) | ||
48 | { | ||
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 *logname; | ||
57 | int pid1000; | ||
58 | int server_sock, tmp_fd; | ||
59 | unsigned opt; | ||
60 | enum { | ||
61 | VERBOSE = 1 << 0, | ||
62 | USE_HEADER = 1 << 1, /* -h banner or header for this job */ | ||
63 | USE_MAIL = 1 << 2, /* send mail to user@hostname */ | ||
64 | OPT_U = 1 << 3, /* -U <username> */ | ||
65 | OPT_J = 1 << 4, /* -J <title> is the jobtitle for the banner page */ | ||
66 | OPT_C = 1 << 5, /* -C <class> job classification */ | ||
67 | OPT_P = 1 << 6, /* -P <queue[@host[:port]]> */ | ||
68 | /* if no -P is given use $PRINTER, then "lp@localhost:515" */ | ||
69 | }; | ||
70 | |||
71 | /* Set defaults, parse options */ | ||
72 | hostname = mygethostname31(); | ||
73 | netopt = NULL; | ||
74 | logname = getenv("LOGNAME"); | ||
75 | if (logname == NULL) | ||
76 | logname = (char*)"user"; /* TODO: getpwuid(getuid())->pw_name? */ | ||
77 | opt = getopt32(argv, "VhmU:J:C:P:", | ||
78 | &logname, &jobtitle, &jobclass, &netopt); | ||
79 | argv += optind; | ||
80 | parse_prt(netopt, &netprint); | ||
81 | logname = xstrndup(logname, 31); | ||
82 | |||
83 | /* For stdin we need to save it to a tempfile, | ||
84 | * otherwise we can't know the size. */ | ||
85 | tmp_fd = -1; | ||
86 | if (!*argv) { | ||
87 | if (jobtitle == NULL) | ||
88 | jobtitle = (char *) bb_msg_standard_input; | ||
89 | |||
90 | tmp_fd = xmkstemp(temp_name); | ||
91 | if (bb_copyfd_eof(STDIN_FILENO, tmp_fd) < 0) | ||
92 | goto del_temp_file; | ||
93 | /* TODO: we actually can have deferred write errors... */ | ||
94 | close(tmp_fd); | ||
95 | argv--; /* back off from NULL */ | ||
96 | *argv = temp_name; | ||
97 | } | ||
98 | |||
99 | if (opt & VERBOSE) | ||
100 | puts("connect to server"); | ||
101 | server_sock = xconnect_stream(netprint.lsa); | ||
102 | |||
103 | /* "Receive a printer job" command */ | ||
104 | fdprintf(server_sock, "\x2" "%s\n", netprint.queue); | ||
105 | get_response(server_sock, "set queue failed"); | ||
106 | |||
107 | pid1000 = getpid() % 1000; | ||
108 | while (*argv) { | ||
109 | char dfa_name[sizeof("dfAnnn") + 32]; | ||
110 | struct stat st; | ||
111 | char **sptr; | ||
112 | unsigned size; | ||
113 | int fd; | ||
114 | |||
115 | fd = xopen(*argv, O_RDONLY); | ||
116 | |||
117 | /* "The name ... should start with ASCII "dfA", | ||
118 | * followed by a three digit job number, followed | ||
119 | * by the host name which has constructed the file." */ | ||
120 | snprintf(dfa_name, sizeof(dfa_name), | ||
121 | "dfA%03u%s", pid1000, hostname); | ||
122 | pid1000 = (pid1000 + 1) % 1000; | ||
123 | |||
124 | /* | ||
125 | * Generate control file contents | ||
126 | */ | ||
127 | /* H HOST, P USER, l DATA_FILE_NAME, J JOBNAME */ | ||
128 | strings[0] = xasprintf("H%.32s\n" "P%.32s\n" "l%.32s\n" | ||
129 | "J%.99s\n", | ||
130 | hostname, logname, dfa_name, | ||
131 | !(opt & OPT_J) ? *argv : jobtitle); | ||
132 | sptr = &strings[1]; | ||
133 | /* C CLASS - printed on banner page (if L cmd is also given) */ | ||
134 | if (opt & OPT_J) /* [1] */ | ||
135 | *sptr++ = xasprintf("C%.32s\n", jobclass); | ||
136 | /* M WHOM_TO_MAIL */ | ||
137 | if (opt & USE_MAIL) /* [2] */ | ||
138 | *sptr++ = xasprintf("M%.32s\n", logname); | ||
139 | /* H USER - print banner page, with given user's name */ | ||
140 | if (opt & USE_HEADER) /* [3] */ | ||
141 | *sptr++ = xasprintf("L%.32s\n", logname); | ||
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 | } | ||
163 | free(strings); | ||
164 | /* "Once all of the contents have | ||
165 | * been delivered, an octet of zero bits is sent as | ||
166 | * an indication that the file being sent is complete. | ||
167 | * A second level of acknowledgement processing | ||
168 | * must occur at this point." */ | ||
169 | xwrite(server_sock, "", 1); | ||
170 | get_response(server_sock, "send control file failed"); | ||
171 | |||
172 | /* Sending data */ | ||
173 | st.st_size = 0; /* paranoia */ | ||
174 | fstat(fd, &st); | ||
175 | if (opt & VERBOSE) | ||
176 | puts("send data file"); | ||
177 | /* 3: "Receive data file" subcommand */ | ||
178 | fdprintf(server_sock, "\x3" "%"OFF_FMT"u %s\n", st.st_size, dfa_name); | ||
179 | /* TODO: if file shrank and we wrote less than st.st_size, | ||
180 | * pad output with NUL bytes? Otherwise server won't know | ||
181 | * that we are done. */ | ||
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 | |||
188 | argv++; | ||
189 | } | ||
190 | |||
191 | if (ENABLE_FEATURE_CLEAN_UP) | ||
192 | close(server_sock); | ||
193 | |||
194 | if (tmp_fd >= 0) { | ||
195 | del_temp_file: | ||
196 | unlink(temp_name); | ||
197 | } | ||
198 | |||
199 | return 0; | ||
200 | } | ||