]> git.ipfire.org Git - thirdparty/cups.git/blob - backend/scsi-linux.c
Merge changes from CUPS 1.5svn-r8950.
[thirdparty/cups.git] / backend / scsi-linux.c
1 /*
2 * "$Id: scsi-linux.c 6834 2007-08-22 18:29:25Z mike $"
3 *
4 * Linux SCSI printer support for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 2007-2009 by Apple Inc.
7 * Copyright 2003-2005 by Easy Software Products, all rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or
10 * without modification, are permitted provided that the
11 * following conditions are met:
12 *
13 * 1. Redistributions of source code must retain the above
14 * copyright notice, this list of conditions and the
15 * following disclaimer.
16 *
17 * 2. Redistributions in binary form must reproduce the
18 * above copyright notice, this list of conditions and
19 * the following disclaimer in the documentation and/or
20 * other materials provided with the distribution.
21 *
22 * 3. All advertising materials mentioning features or use
23 * of this software must display the following
24 * acknowledgement:
25 *
26 * This product includes software developed by Easy
27 * Software Products.
28 *
29 * 4. The name of Easy Software Products may not be used to
30 * endorse or promote products derived from this software
31 * without specific prior written permission.
32 *
33 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS
34 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
35 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
36 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
37 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS
38 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
39 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
40 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
41 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
43 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
44 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
45 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
46 * DAMAGE.
47 *
48 * Contents:
49 *
50 * list_devices() - List the available SCSI printer devices.
51 * print_device() - Print a file to a SCSI device.
52 */
53
54 /*
55 * Include necessary headers.
56 */
57
58 #include <scsi/sg.h>
59 #include <cups/i18n.h>
60
61
62 /*
63 * We currently only support the Linux 2.4 generic SCSI interface.
64 */
65
66 #ifndef SG_DXFER_TO_DEV
67 /*
68 * Dummy functions that do nothing on unsupported platforms...
69 */
70 void list_devices(void) {}
71 int print_device(const char *resource, int fd, int copies) { return (1); }
72 #else
73
74
75 /*
76 * 'list_devices()' - List the available SCSI printer devices.
77 */
78
79 void
80 list_devices(void)
81 {
82 printf("direct scsi \"Unknown\" \"%s\"\n",
83 _cupsLangString(cupsLangDefault(), _("SCSI Printer")));
84 }
85
86
87 /*
88 * 'print_device()' - Print a file to a SCSI device.
89 */
90
91 int /* O - Print status */
92 print_device(const char *resource, /* I - SCSI device */
93 int fd, /* I - File to print */
94 int copies) /* I - Number of copies to print */
95 {
96 int scsi_fd; /* SCSI file descriptor */
97 char buffer[8192]; /* Data buffer */
98 int bytes; /* Number of bytes */
99 int try; /* Current try */
100 sg_io_hdr_t scsi_req; /* SCSI request */
101 unsigned char scsi_cmd[6], /* SCSI command data */
102 scsi_sense[32]; /* SCSI sense data */
103 # if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET)
104 struct sigaction action; /* Actions for POSIX signals */
105 # endif /* HAVE_SIGACTION && !HAVE_SIGSET */
106
107
108 /*
109 * Make sure we have a valid resource name...
110 */
111
112 if (strncmp(resource, "/dev/sg", 7) != 0)
113 {
114 _cupsLangPrintf(stderr, _("ERROR: Bad SCSI device file \"%s\"\n"),
115 resource);
116 return (CUPS_BACKEND_STOP);
117 }
118
119 /*
120 * Open the SCSI device file...
121 */
122
123 fputs("STATE: +connecting-to-device\n", stderr);
124
125 do
126 {
127 if ((scsi_fd = open(resource, O_RDWR | O_EXCL)) == -1)
128 {
129 if (getenv("CLASS") != NULL)
130 {
131 /*
132 * If the CLASS environment variable is set, the job was submitted
133 * to a class and not to a specific queue. In this case, we want
134 * to abort immediately so that the job can be requeued on the next
135 * available printer in the class.
136 */
137
138 _cupsLangPuts(stderr,
139 _("INFO: Unable to contact printer, queuing on next "
140 "printer in class...\n"));
141
142 /*
143 * Sleep 5 seconds to keep the job from requeuing too rapidly...
144 */
145
146 sleep(5);
147
148 return (CUPS_BACKEND_FAILED);
149 }
150
151 if (errno != EAGAIN && errno != EBUSY)
152 {
153 _cupsLangPrintf(stderr,
154 _("ERROR: Unable to open device file \"%s\": %s\n"),
155 resource, strerror(errno));
156 return (CUPS_BACKEND_FAILED);
157 }
158 else
159 {
160 _cupsLangPuts(stderr,
161 _("INFO: Printer busy; will retry in 30 seconds...\n"));
162 sleep(30);
163 }
164 }
165 }
166 while (scsi_fd == -1);
167
168 fputs("STATE: -connecting-to-device\n", stderr);
169
170 /*
171 * Now that we are "connected" to the port, ignore SIGTERM so that we
172 * can finish out any page data the driver sends (e.g. to eject the
173 * current page... Only ignore SIGTERM if we are printing data from
174 * stdin (otherwise you can't cancel raw jobs...)
175 */
176
177 if (fd != 0)
178 {
179 # ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */
180 sigset(SIGTERM, SIG_IGN);
181 # elif defined(HAVE_SIGACTION)
182 memset(&action, 0, sizeof(action));
183
184 sigemptyset(&action.sa_mask);
185 action.sa_handler = SIG_IGN;
186 sigaction(SIGTERM, &action, NULL);
187 # else
188 signal(SIGTERM, SIG_IGN);
189 # endif /* HAVE_SIGSET */
190 }
191
192 /*
193 * Copy the print file to the device...
194 */
195
196 while (copies > 0)
197 {
198 if (fd != 0)
199 lseek(fd, 0, SEEK_SET);
200
201 while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
202 {
203 memset(&scsi_req, 0, sizeof(scsi_req));
204
205 scsi_req.interface_id = 'S';
206 scsi_req.dxfer_direction = SG_DXFER_TO_DEV;
207 scsi_req.cmd_len = 6;
208 scsi_req.mx_sb_len = sizeof(scsi_sense);
209 scsi_req.iovec_count = 0;
210 scsi_req.dxfer_len = bytes;
211 scsi_req.dxferp = buffer;
212 scsi_req.cmdp = scsi_cmd;
213 scsi_req.sbp = scsi_sense;
214 scsi_req.timeout = 60 * 1000;
215
216 scsi_cmd[0] = 0x0a; /* Group 0 print command */
217 scsi_cmd[1] = 0x00;
218 scsi_cmd[2] = bytes / 65536;
219 scsi_cmd[3] = bytes / 256;
220 scsi_cmd[4] = bytes;
221 scsi_cmd[5] = 0x00;
222
223 for (try = 0; try < 10; try ++)
224 if (ioctl(scsi_fd, SG_IO, &scsi_req) < 0 ||
225 scsi_req.status != 0)
226 {
227 _cupsLangPrintf(stderr,
228 _("WARNING: SCSI command timed out (%d); "
229 "retrying...\n"), scsi_req.status);
230 sleep(try + 1);
231 }
232 else
233 break;
234
235 if (try >= 10)
236 {
237 _cupsLangPrintf(stderr, _("ERROR: Unable to send print data (%d)\n"),
238 scsi_req.status);
239 close(scsi_fd);
240 return (CUPS_BACKEND_FAILED);
241 }
242 }
243
244 copies --;
245 }
246
247 /*
248 * Close the device and return...
249 */
250
251 close(fd);
252
253 return (CUPS_BACKEND_OK);
254 }
255 #endif /* !SG_DXFER_TO_DEV */
256
257
258 /*
259 * End of "$Id: scsi-linux.c 6834 2007-08-22 18:29:25Z mike $".
260 */