1 /* sane - Scanner Access Now Easy.
2 Copyright (C) 1996, 1997 David Mosberger-Tang
3 This file is part of the SANE package.
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
17
18 As a special exception, the authors of SANE give permission for
19 additional uses of the libraries contained in this release of SANE.
20
21 The exception is that, if you link a SANE library with other files
22 to produce an executable, this does not by itself cause the
23 resulting executable to be covered by the GNU General Public
24 License. Your use of that executable is in no way restricted on
25 account of linking the SANE library code into it.
26
27 This exception does not, however, invalidate any other reasons why
28 the executable file might be covered by the GNU General Public
29 License.
30
31 If you submit changes to SANE to the maintainers to be included in
32 a subsequent release, you agree by submitting the changes that
33 those changes may be distributed with this exception intact.
34
35 If you write modifications of your own for SANE, it is your choice
36 whether to permit this exception to apply to your modifications.
37 If you do not wish that, delete this exception notice.
38
39 This file implements a dynamic linking based SANE meta backend. It
40 allows managing an arbitrary number of SANE backends by using
41 dynamic linking to load backends on demand. */
42
43 /* Please increase version number with every change
44 (don't forget to update dll.desc) */
45 #define DLL_VERSION "1.0.13"
46
47 #ifdef _AIX
48 # include "lalloca.h" /* MUST come first for AIX! */
49 #endif
50
51 #ifdef __BEOS__
52 #include <kernel/OS.h>
53 #include <storage/FindDirectory.h>
54 #include <kernel/image.h>
55 #include <posix/dirent.h>
56 #endif
57
58 #include "../include/sane/config.h"
59 #include "lalloca.h"
60
61 #include <errno.h>
62 #include <limits.h>
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <string.h>
66
67 #if defined(HAVE_DLOPEN) && defined(HAVE_DLFCN_H)
68 # include <dlfcn.h>
69
70 /* This works around a pedantic GCC compiler warning. The ISO C
71 standard says that the behaviour of converting an object pointer
72 like the void * returned by dlsym() to a function pointer like
73 void *(*)() is implementation defined. POSIX though guarantees
74 that this works fine.
75
76 Workaround based on http://stackoverflow.com/a/36385690. Turns
77 off pedantic warnings for the duration of the definition only.
78 */
79 # pragma GCC diagnostic push
80 # pragma GCC diagnostic ignored "-Wpedantic"
81 typedef void *(*func_ptr)(void);
82
83 func_ptr
posix_dlsym(void *handle, const char *func)84 posix_dlsym (void *handle, const char *func)
85 {
86 return dlsym (handle, func);
87 }
88 # pragma GCC diagnostic pop
89
90 /* Similar to the above, GCC also warns about conversion between
91 pointers to functions. The ISO C standard says that invoking a
92 converted pointer to a function whose type is not compatible with
93 the pointed-to type, the behavior is undefined. Although GCC is
94 correct to warn about this, the dll backend has been using these
95 conversions without issues for a very long time already.
96
97 Rather than push/pop around every use, which would get very ugly
98 real fast, ignore this particular warning for the remainder of
99 the file.
100 */
101 # pragma GCC diagnostic ignored "-Wpragmas" /* backward compatibility */
102 # pragma GCC diagnostic ignored "-Wcast-function-type"
103
104 /* Older versions of dlopen() don't define RTLD_NOW and RTLD_LAZY.
105 They all seem to use a mode of 1 to indicate RTLD_NOW and some do
106 not support RTLD_LAZY at all. Hence, unless defined, we define
107 both macros as 1 to play it safe. */
108 # ifndef RTLD_NOW
109 # define RTLD_NOW 1
110 # endif
111 # ifndef RTLD_LAZY
112 # define RTLD_LAZY 1
113 # endif
114 # define HAVE_DLL
115 #endif
116
117 /* HP/UX DLL support */
118 #if defined (HAVE_SHL_LOAD) && defined(HAVE_DL_H)
119 # include <dl.h>
120 # define HAVE_DLL
121 #endif
122
123 /* Mac OS X/Darwin support */
124 #if defined (HAVE_NSLINKMODULE) && defined(HAVE_MACH_O_DYLD_H)
125 # include <mach-o/dyld.h>
126 # define HAVE_DLL
127 #endif
128
129 #include <sys/types.h>
130 #include <sys/stat.h>
131 #include <dirent.h>
132
133 #include "../include/sane/sane.h"
134 #include "../include/sane/sanei.h"
135
136 #define BACKEND_NAME dll
137 #include "../include/sane/sanei_backend.h"
138
139 #ifndef PATH_MAX
140 # define PATH_MAX 1024
141 #endif
142
143 #ifndef NAME_MAX
144 # define NAME_MAX FILENAME_MAX
145 #endif
146
147 #if defined(_WIN32) || defined(HAVE_OS2_H)
148 # define DIR_SEP ";"
149 #else
150 # define DIR_SEP ":"
151 #endif
152
153
154 #include "../include/sane/sanei_config.h"
155 #define DLL_CONFIG_FILE "dll.conf"
156 #define DLL_ALIASES_FILE "dll.aliases"
157
158 #include "../include/sane/sanei_usb.h"
159
160 enum SANE_Ops
161 {
162 OP_INIT = 0,
163 OP_EXIT,
164 OP_GET_DEVS,
165 OP_OPEN,
166 OP_CLOSE,
167 OP_GET_OPTION_DESC,
168 OP_CTL_OPTION,
169 OP_GET_PARAMS,
170 OP_START,
171 OP_READ,
172 OP_CANCEL,
173 OP_SET_IO_MODE,
174 OP_GET_SELECT_FD,
175 NUM_OPS
176 };
177
178 typedef SANE_Status (*op_init_t) (SANE_Int *, SANE_Auth_Callback);
179 typedef void (*op_exit_t) (void);
180 typedef SANE_Status (*op_get_devs_t) (const SANE_Device ***, SANE_Bool);
181 typedef SANE_Status (*op_open_t) (SANE_String_Const, SANE_Handle *);
182 typedef void (*op_close_t) (SANE_Handle);
183 typedef const SANE_Option_Descriptor * (*op_get_option_desc_t) (SANE_Handle,
184 SANE_Int);
185 typedef SANE_Status (*op_ctl_option_t) (SANE_Handle, SANE_Int, SANE_Action,
186 void *, SANE_Int *);
187 typedef SANE_Status (*op_get_params_t) (SANE_Handle, SANE_Parameters *);
188 typedef SANE_Status (*op_start_t) (SANE_Handle);
189 typedef SANE_Status (*op_read_t) (SANE_Handle, SANE_Byte *, SANE_Int,
190 SANE_Int *);
191 typedef void (*op_cancel_t) (SANE_Handle);
192 typedef SANE_Status (*op_set_io_mode_t) (SANE_Handle, SANE_Bool);
193 typedef SANE_Status (*op_get_select_fd_t) (SANE_Handle, SANE_Int *);
194
195 struct backend
196 {
197 struct backend *next;
198 char *name;
199 u_int permanent:1; /* is the backend preloaded? */
200 u_int loaded:1; /* are the functions available? */
201 u_int inited:1; /* has the backend been initialized? */
202 void *handle; /* handle returned by dlopen() */
203 void *(*op[NUM_OPS]) (void);
204 };
205
206 #define BE_ENTRY(be,func) sane_##be##_##func
207
208 #define PRELOAD_DECL(name) \
209 extern SANE_Status BE_ENTRY(name,init) (SANE_Int *, SANE_Auth_Callback); \
210 extern void BE_ENTRY(name,exit) (void); \
211 extern SANE_Status BE_ENTRY(name,get_devices) (const SANE_Device ***, SANE_Bool); \
212 extern SANE_Status BE_ENTRY(name,open) (SANE_String_Const, SANE_Handle *); \
213 extern void BE_ENTRY(name,close) (SANE_Handle); \
214 extern const SANE_Option_Descriptor *BE_ENTRY(name,get_option_descriptor) (SANE_Handle, SANE_Int); \
215 extern SANE_Status BE_ENTRY(name,control_option) (SANE_Handle, SANE_Int, SANE_Action, void *, SANE_Int *); \
216 extern SANE_Status BE_ENTRY(name,get_parameters) (SANE_Handle, SANE_Parameters *); \
217 extern SANE_Status BE_ENTRY(name,start) (SANE_Handle); \
218 extern SANE_Status BE_ENTRY(name,read) (SANE_Handle, SANE_Byte *, SANE_Int, SANE_Int *); \
219 extern void BE_ENTRY(name,cancel) (SANE_Handle); \
220 extern SANE_Status BE_ENTRY(name,set_io_mode) (SANE_Handle, SANE_Bool); \
221 extern SANE_Status BE_ENTRY(name,get_select_fd) (SANE_Handle, SANE_Int *);
222
223 #define PRELOAD_DEFN(name) \
224 { \
225 0 /* next */, #name, \
226 1 /* permanent */, \
227 1 /* loaded */, \
228 0 /* inited */, \
229 0 /* handle */, \
230 { \
231 BE_ENTRY(name,init), \
232 BE_ENTRY(name,exit), \
233 BE_ENTRY(name,get_devices), \
234 BE_ENTRY(name,open), \
235 BE_ENTRY(name,close), \
236 BE_ENTRY(name,get_option_descriptor), \
237 BE_ENTRY(name,control_option), \
238 BE_ENTRY(name,get_parameters), \
239 BE_ENTRY(name,start), \
240 BE_ENTRY(name,read), \
241 BE_ENTRY(name,cancel), \
242 BE_ENTRY(name,set_io_mode), \
243 BE_ENTRY(name,get_select_fd) \
244 } \
245 }
246
247 #ifndef __BEOS__
248 #ifdef ENABLE_PRELOAD
249 #include "dll-preload.h"
250 #else
251 static struct backend preloaded_backends[] = {
252 { 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}
253 };
254 #endif
255 #endif
256
257 struct meta_scanner
258 {
259 struct backend *be;
260 SANE_Handle handle;
261 };
262
263 struct alias
264 {
265 struct alias *next;
266 char *oldname;
267 char *newname;
268 };
269
270 /*
271 * List of available devices, allocated by sane_get_devices, released
272 * by sane_exit()
273 */
274 static SANE_Device **devlist = NULL;
275 static int devlist_size = 0, devlist_len = 0;
276
277 static struct alias *first_alias;
278 static SANE_Auth_Callback auth_callback;
279 static struct backend *first_backend;
280
281 #ifndef __BEOS__
282 static const char *op_name[] = {
283 "init", "exit", "get_devices", "open", "close", "get_option_descriptor",
284 "control_option", "get_parameters", "start", "read", "cancel",
285 "set_io_mode", "get_select_fd"
286 };
287 #else
288 static const char *op_name[] = {
289 "sane_init", "sane_exit", "sane_get_devices", "sane_open", "sane_close", "sane_get_option_descriptor",
290 "sane_control_option", "sane_get_parameters", "sane_start", "sane_read", "sane_cancel",
291 "sane_set_io_mode", "sane_get_select_fd"
292 };
293 #endif /* __BEOS__ */
294
295 static void *
op_unsupported(void)296 op_unsupported (void)
297 {
298 DBG (1, "op_unsupported: call to unsupported backend operation\n");
299 return (void *) (long) SANE_STATUS_UNSUPPORTED;
300 }
301
302
303 static SANE_Status
add_backend(const char *name, struct backend **bep)304 add_backend (const char *name, struct backend **bep)
305 {
306 struct backend *be, *prev;
307
308 DBG (3, "add_backend: adding backend `%s'\n", name);
309
310 if (strcmp (name, "dll") == 0)
311 {
312 DBG (0, "add_backend: remove the dll-backend from your dll.conf!\n");
313 return SANE_STATUS_GOOD;
314 }
315
316 for (prev = 0, be = first_backend; be; prev = be, be = be->next)
317 if (strcmp (be->name, name) == 0)
318 {
319 DBG (1, "add_backend: `%s' is already there\n", name);
320 /* move to front so we preserve order that we'd get with
321 dynamic loading: */
322 if (prev)
323 {
324 prev->next = be->next;
325 be->next = first_backend;
326 first_backend = be;
327 }
328 if (bep)
329 *bep = be;
330 return SANE_STATUS_GOOD;
331 }
332
333 be = calloc (1, sizeof (*be));
334 if (!be)
335 return SANE_STATUS_NO_MEM;
336
337 be->name = strdup (name);
338 if (!be->name)
339 return SANE_STATUS_NO_MEM;
340 be->next = first_backend;
341 first_backend = be;
342 if (bep)
343 *bep = be;
344 return SANE_STATUS_GOOD;
345 }
346
347 #if defined(HAVE_NSLINKMODULE)
348 static const char *dyld_get_error_str ();
349
350 static const char *
dyld_get_error_strnull351 dyld_get_error_str ()
352 {
353 NSLinkEditErrors c;
354 int errorNumber;
355 const char *fileName;
356 const char *errorString;
357
358 NSLinkEditError (&c, &errorNumber, &fileName, &errorString);
359 return errorString;
360 }
361 #endif
362
363 #if defined(HAVE_SCAN_SERVICE)
has_suffix(const char *filename, const char *suffix)364 static int has_suffix(const char *filename, const char *suffix) {
365 size_t len_filename = strlen(filename);
366 size_t len_suffix = strlen(suffix);
367 return len_suffix <= len_filename && strcmp(filename + len_filename - len_suffix, suffix) == 0;
368 }
369
find_libname_by_drivername(char* libname, char* dir, char* drivername)370 static void find_libname_by_drivername(char* libname, char* dir, char* drivername)
371 {
372 DBG(1, "%s: begin", __func__);
373 if (libname == NULL || dir == NULL || drivername == NULL)
374 {
375 DBG(2, "%s: input parameter is a nullptr.\n", __func__);
376 return;
377 }
378 char driver[PATH_MAX] = {0};
379 snprintf (driver, sizeof (driver), "libsane-%s.z.so", drivername);
380 DIR *backends_dir = opendir(dir);
381 if (backends_dir == NULL) {
382 DBG(2, "open dir %s error\n", backends_dir);
383 return;
384 }
385 struct dirent *entry;
386 char full_path[PATH_MAX] = {0};
387 while ((entry = readdir(backends_dir)) != NULL) {
388 // ignore '.' and '..'
389 if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
390 memset(full_path, 0, PATH_MAX);
391 snprintf(full_path, PATH_MAX, "%s/" "%s", dir, entry->d_name);
392 DBG(2, "full_path %s\n", full_path);
393 if (has_suffix(full_path, driver)) {
394 memset(libname, 0, PATH_MAX);
395 strncpy(libname, full_path, PATH_MAX);
396 break;
397 }
398 }
399 }
400 closedir(backends_dir);
401 }
402 #endif
403
404 #ifdef __BEOS__
405 #include <FindDirectory.h>
406
407 static SANE_Status
load(struct backend *be)408 load (struct backend *be)
409 {
410 /* use BeOS kernel function to load scanner addons from ~/config/add-ons/SANE */
411 char path[PATH_MAX];
412 image_id id = -1;
413 int i, w;
414 directory_which which[3] = { B_USER_ADDONS_DIRECTORY, B_COMMON_ADDONS_DIRECTORY, B_BEOS_ADDONS_DIRECTORY };
415
416 /* look for config files in SANE/conf */
417 for (w = 0; (w < 3) && (id < 0) && (find_directory(which[w],0,true,path,PATH_MAX) == 0); w++)
418 {
419 strcat(path,"/SANE/");
420 strcat(path,be->name);
421 DBG(1, "loading backend %s\n", be->name);
422
423 /* initialize all ops to "unsupported" so we can "use" the backend
424 even if the stuff later in this function fails */
425 be->loaded = 1;
426 be->handle = 0;
427 for (i = 0; i < NUM_OPS; ++i) be->op[i] = op_unsupported;
428 DBG(2, "dlopen()ing `%s'\n", path);
429 id=load_add_on(path);
430 if (id < 0)
431 {
432 continue; /* try next path */
433 }
434 be->handle=(void *)id;
435
436 for (i = 0; i < NUM_OPS; ++i)
437 {
438 void *(*op) ();
439 op = NULL;
440 /* Look for the symbol */
441 if ((get_image_symbol(id, op_name[i],B_SYMBOL_TYPE_TEXT,(void **)&op) < 0) || !op)
442 DBG(2, "unable to find %s\n", op_name[i]);
443 else be->op[i]=op;
444 }
445 }
446 if (id < 0)
447 {
448 DBG(2, "load: couldn't find %s\n",path);
449 return SANE_STATUS_INVAL;
450 }
451 return SANE_STATUS_GOOD;
452 }
453
454 #else
455 static SANE_Status
load(struct backend *be)456 load (struct backend *be)
457 {
458 #ifdef HAVE_DLL
459 int mode = 0;
460 char *funcname, *src, *orig_src = 0, *dir, *path = 0;
461 char libname[PATH_MAX];
462 int i;
463 int src_len;
464 FILE *fp = 0;
465
466 #if defined(HAVE_DLOPEN)
467 # define PREFIX "libsane-"
468 # ifdef __hpux
469 # define POSTFIX ".sl.%u"
470 # define ALT_POSTFIX ".so.%u"
471 # elif defined (HAVE_WINDOWS_H)
472 # undef PREFIX
473 # define PREFIX "cygsane-"
474 # define POSTFIX "-%u.dll"
475 # elif defined (HAVE_OS2_H)
476 # undef PREFIX
477 # define PREFIX ""
478 # define POSTFIX ".dll"
479 # elif defined (__APPLE__) && defined (__MACH__)
480 # define POSTFIX ".%u.so"
481 # else
482 # define POSTFIX ".so.%u"
483 # endif
484 mode = getenv ("LD_BIND_NOW") ? RTLD_NOW : RTLD_LAZY;
485 #elif defined(HAVE_SHL_LOAD)
486 # define PREFIX "libsane-"
487 # define POSTFIX ".sl.%u"
488 mode = BIND_DEFERRED;
489 #elif defined(HAVE_NSLINKMODULE)
490 # define PREFIX "libsane-"
491 # define POSTFIX ".%u.so"
492 mode = NSLINKMODULE_OPTION_RETURN_ON_ERROR + NSLINKMODULE_OPTION_PRIVATE;
493 #else
494 # error "Tried to compile unsupported DLL."
495 #endif /* HAVE_DLOPEN */
496
497 /* initialize all ops to "unsupported" so we can "use" the backend
498 even if the stuff later in this function fails */
499 be->loaded = 1;
500 be->handle = 0;
501 for (i = 0; i < NUM_OPS; ++i)
502 be->op[i] = op_unsupported;
503
504 path = getenv ("LD_LIBRARY_PATH");
505 if (!path)
506 path = getenv ("SHLIB_PATH"); /* for HP-UX */
507 if (!path)
508 path = getenv ("LIBPATH"); /* for AIX */
509
510 if (path)
511 {
512 src_len = strlen (path) + strlen (DIR_SEP) + strlen(LIBDIR) + 1;
513 src = malloc (src_len);
514 if (!src)
515 {
516 DBG (1, "load: malloc failed: %s\n", strerror (errno));
517 return SANE_STATUS_NO_MEM;
518 }
519 snprintf (src, src_len, "%s%s%s", path, DIR_SEP, LIBDIR);
520 }
521 else
522 {
523 src = LIBDIR;
524 src = strdup (src);
525 if (!src)
526 {
527 DBG (1, "load: strdup failed: %s\n", strerror (errno));
528 return SANE_STATUS_NO_MEM;
529 }
530 }
531 DBG (3, "load: searching backend `%s' in `%s'\n", be->name, src);
532
533 orig_src = src;
534 dir = strsep (&src, DIR_SEP);
535
536 while (dir)
537 {
538 #ifdef HAVE_OS2_H /* only max 7.3 names work with dlopen() for DLLs on OS/2 */
539 snprintf (libname, sizeof (libname), "%s/" PREFIX "%.2s%.5s" POSTFIX,
540 dir, be->name, strlen(be->name)>7 ? (be->name)+strlen(be->name)-5 :
541 (be->name)+2, V_MAJOR);
542 #elif defined (HAVE_SCAN_SERVICE)
543 find_libname_by_drivername(libname, dir, be->name);
544 #else
545 snprintf (libname, sizeof (libname), "%s/" PREFIX "%s" POSTFIX,
546 dir, be->name, V_MAJOR);
547 #endif
548 DBG (4, "load: trying to load `%s'\n", libname);
549 fp = fopen (libname, "r");
550 if (fp)
551 break;
552 DBG (4, "load: couldn't open `%s' (%s)\n", libname, strerror (errno));
553
554 #ifdef ALT_POSTFIX
555 /* Some platforms have two ways of storing their libraries, try both
556 postfixes */
557 snprintf (libname, sizeof (libname), "%s/" PREFIX "%s" ALT_POSTFIX,
558 dir, be->name, V_MAJOR);
559 DBG (4, "load: trying to load `%s'\n", libname);
560 fp = fopen (libname, "r");
561 if (fp)
562 break;
563 DBG (4, "load: couldn't open `%s' (%s)\n", libname, strerror (errno));
564 #endif
565
566 dir = strsep (&src, DIR_SEP);
567 }
568 if (orig_src)
569 free (orig_src);
570 if (!fp)
571 {
572 DBG (1, "load: couldn't find backend `%s' (%s)\n",
573 be->name, strerror (errno));
574 return SANE_STATUS_INVAL;
575 }
576 fclose (fp);
577 DBG (3, "load: dlopen()ing `%s'\n", libname);
578
579 #ifdef HAVE_DLOPEN
580 be->handle = dlopen (libname, mode);
581 #elif defined(HAVE_SHL_LOAD)
582 be->handle = (shl_t) shl_load (libname, mode, 0L);
583 #elif defined(HAVE_NSLINKMODULE)
584 {
585 NSObjectFileImage objectfile_img = NULL;
586 if (NSCreateObjectFileImageFromFile (libname, &objectfile_img)
587 == NSObjectFileImageSuccess)
588 {
589 be->handle = NSLinkModule (objectfile_img, libname, mode);
590 NSDestroyObjectFileImage (objectfile_img);
591 }
592 }
593 #else
594 # error "Tried to compile unsupported DLL."
595 #endif /* HAVE_DLOPEN */
596 if (!be->handle)
597 {
598 #ifdef HAVE_DLOPEN
599 DBG (1, "load: dlopen() failed (%s)\n", dlerror ());
600 #elif defined(HAVE_NSLINKMODULE)
601 DBG (1, "load: dyld error (%s)\n", dyld_get_error_str ());
602 #else
603 DBG (1, "load: dlopen() failed (%s)\n", strerror (errno));
604 #endif
605 return SANE_STATUS_INVAL;
606 }
607
608 /* all is dandy---lookup and fill in backend ops: */
609 funcname = alloca (strlen (be->name) + 64);
610 for (i = 0; i < NUM_OPS; ++i)
611 {
612 void *(*op) (void);
613
614 sprintf (funcname, "_sane_%s_%s", be->name, op_name[i]);
615
616 /* First try looking up the symbol without a leading underscore. */
617 #ifdef HAVE_DLOPEN
618 op = posix_dlsym (be->handle, funcname + 1);
619 #elif defined(HAVE_SHL_LOAD)
620 shl_findsym ((shl_t *) & (be->handle), funcname + 1, TYPE_UNDEFINED,
621 &op);
622 #elif defined(HAVE_NSLINKMODULE)
623 {
624 NSSymbol *nssym = NSLookupSymbolInModule (be->handle, funcname);
625 if (!nssym)
626 {
627 DBG (15, "dyld error: %s\n", dyld_get_error_str ());
628 }
629 else
630 {
631 op = (void *(*)(void)) NSAddressOfSymbol (nssym);
632 }
633 }
634 #else
635 # error "Tried to compile unsupported DLL."
636 #endif /* HAVE_DLOPEN */
637 if (op)
638 be->op[i] = op;
639 else
640 {
641 /* Try again, with an underscore prepended. */
642 #ifdef HAVE_DLOPEN
643 op = posix_dlsym (be->handle, funcname);
644 #elif defined(HAVE_SHL_LOAD)
645 shl_findsym (be->handle, funcname, TYPE_UNDEFINED, &op);
646 #elif defined(HAVE_NSLINKMODULE)
647 {
648 NSSymbol *nssym = NSLookupSymbolInModule (be->handle, funcname);
649 if (!nssym)
650 {
651 DBG (15, "dyld error: %s\n", dyld_get_error_str ());
652 }
653 else
654 {
655 op = (void *(*)(void)) NSAddressOfSymbol (nssym);
656 }
657 }
658 #else
659 # error "Tried to compile unsupported DLL."
660 #endif /* HAVE_DLOPEN */
661 if (op)
662 be->op[i] = op;
663 }
664 if (NULL == op)
665 DBG (1, "load: unable to find %s\n", funcname);
666 }
667
668 return SANE_STATUS_GOOD;
669
670 # undef PREFIX
671 # undef POSTFIX
672 #else /* HAVE_DLL */
673 DBG (1,
674 "load: ignoring attempt to load `%s'; compiled without dl support\n",
675 be->name);
676 return SANE_STATUS_UNSUPPORTED;
677 #endif /* HAVE_DLL */
678 }
679 #endif /* __BEOS__ */
680
681 static SANE_Status
init(struct backend *be)682 init (struct backend *be)
683 {
684 SANE_Status status;
685 SANE_Int version;
686
687 if (!be->loaded)
688 {
689 status = load (be);
690 if (status != SANE_STATUS_GOOD)
691 return status;
692 }
693
694 DBG (3, "init: initializing backend `%s'\n", be->name);
695
696 status = (*(op_init_t)be->op[OP_INIT]) (&version, auth_callback);
697 if (status != SANE_STATUS_GOOD)
698 return status;
699
700 if (SANE_VERSION_MAJOR (version) != SANE_CURRENT_MAJOR)
701 {
702 DBG (1,
703 "init: backend `%s' has a wrong major version (%d instead of %d)\n",
704 be->name, SANE_VERSION_MAJOR (version), SANE_CURRENT_MAJOR);
705 return SANE_STATUS_INVAL;
706 }
707 DBG (4, "init: backend `%s' is version %d.%d.%d\n", be->name,
708 SANE_VERSION_MAJOR (version), SANE_VERSION_MINOR (version),
709 SANE_VERSION_BUILD (version));
710
711 be->inited = 1;
712
713 return SANE_STATUS_GOOD;
714 }
715
716
717 static void
add_alias(const char *line_param)718 add_alias (const char *line_param)
719 {
720 #ifndef __BEOS__
721 const char *command;
722 enum
723 { CMD_ALIAS, CMD_HIDE }
724 cmd;
725 const char *oldname, *oldend, *newname;
726 size_t oldlen, newlen;
727 struct alias *alias;
728 char *line;
729
730 command = sanei_config_skip_whitespace (line_param);
731 if (!*command)
732 return;
733
734 line = strchr (command, '#');
735 if (line)
736 *line = '\0';
737
738 line = strpbrk (command, " \t");
739 if (!line)
740 return;
741 *line++ = '\0';
742
743 if (strcmp (command, "alias") == 0)
744 cmd = CMD_ALIAS;
745 else if (strcmp (command, "hide") == 0)
746 cmd = CMD_HIDE;
747 else
748 return;
749
750 newlen = 0;
751 newname = NULL;
752 if (cmd == CMD_ALIAS)
753 {
754 char *newend;
755
756 newname = sanei_config_skip_whitespace (line);
757 if (!*newname)
758 return;
759 if (*newname == '\"')
760 {
761 ++newname;
762 newend = strchr (newname, '\"');
763 }
764 else
765 newend = strpbrk (newname, " \t");
766 if (!newend)
767 return;
768
769 newlen = newend - newname;
770 line = (char *) (newend + 1);
771 }
772
773 oldname = sanei_config_skip_whitespace (line);
774 if (!*oldname)
775 return;
776 oldend = oldname + strcspn (oldname, " \t");
777
778 oldlen = oldend - oldname;
779
780 alias = malloc (sizeof (struct alias));
781 if (alias)
782 {
783 alias->oldname = malloc (oldlen + newlen + 2);
784 if (alias->oldname)
785 {
786 strncpy (alias->oldname, oldname, oldlen);
787 alias->oldname[oldlen] = '\0';
788 if (cmd == CMD_ALIAS)
789 {
790 alias->newname = alias->oldname + oldlen + 1;
791 strncpy (alias->newname, newname, newlen);
792 alias->newname[newlen] = '\0';
793 }
794 else
795 alias->newname = NULL;
796
797 alias->next = first_alias;
798 first_alias = alias;
799 return;
800 }
801 free (alias);
802 }
803 return;
804 #endif
805 }
806
807
808 static void
read_config(const char *conffile)809 read_config (const char *conffile)
810 {
811 FILE *fp;
812 char config_line[PATH_MAX];
813 char *backend_name;
814
815 fp = sanei_config_open (conffile);
816 if (!fp)
817 {
818 DBG (1, "sane_init/read_config: Couldn't open config file (%s): %s\n",
819 conffile, strerror (errno));
820 return; /* don't insist on config file */
821 }
822
823 DBG (5, "sane_init/read_config: reading %s\n", conffile);
824 while (sanei_config_read (config_line, sizeof (config_line), fp))
825 {
826 char *comment;
827 SANE_String_Const cp;
828
829 cp = sanei_config_get_string (config_line, &backend_name);
830 /* ignore empty lines */
831 if (!backend_name || cp == config_line)
832 {
833 if (backend_name)
834 free (backend_name);
835 continue;
836 }
837 /* ignore line comments */
838 if (backend_name[0] == '#')
839 {
840 free (backend_name);
841 continue;
842 }
843 /* ignore comments after backend names */
844 comment = strchr (backend_name, '#');
845 if (comment)
846 *comment = '\0';
847 add_backend (backend_name, 0);
848 free (backend_name);
849 }
850 fclose (fp);
851 }
852
853 static void
read_dlld(void)854 read_dlld (void)
855 {
856 DIR *dlld;
857 struct dirent *dllconf;
858 struct stat st;
859 char dlldir[PATH_MAX];
860 char conffile[PATH_MAX + strlen("/") + NAME_MAX];
861 size_t len, plen;
862 const char *dir_list;
863 char *copy, *next, *dir;
864
865 dir_list = sanei_config_get_paths ();
866 if (!dir_list)
867 {
868 DBG(2, "sane_init/read_dlld: Unable to detect configuration directories\n");
869 return;
870 }
871
872 copy = strdup (dir_list);
873
874 for (next = copy; (dir = strsep (&next, DIR_SEP)) != NULL;)
875 {
876 snprintf (dlldir, sizeof (dlldir), "%s%s", dir, "/dll.d");
877
878 DBG(4, "sane_init/read_dlld: attempting to open directory `%s'\n", dlldir);
879
880 dlld = opendir (dlldir);
881 if (dlld)
882 {
883 /* length of path to parent dir of dll.d/ */
884 plen = strlen (dir) + 1;
885
886 DBG(3, "sane_init/read_dlld: using config directory `%s'\n", dlldir);
887 break;
888 }
889 }
890 free (copy);
891
892 if (dlld == NULL)
893 {
894 DBG (1, "sane_init/read_dlld: opendir failed: %s\n",
895 strerror (errno));
896 return;
897 }
898
899 while ((dllconf = readdir (dlld)) != NULL)
900 {
901 /* dotfile (or directory) */
902 if (dllconf->d_name[0] == '.')
903 continue;
904
905 len = strlen (dllconf->d_name);
906
907 /* backup files */
908 if ((dllconf->d_name[len-1] == '~')
909 || (dllconf->d_name[len-1] == '#'))
910 continue;
911
912 snprintf (conffile, sizeof(conffile), "%s/%s", dlldir, dllconf->d_name);
913
914 DBG (5, "sane_init/read_dlld: considering %s\n", conffile);
915
916 if (stat (conffile, &st) != 0)
917 continue;
918
919 if (!S_ISREG (st.st_mode))
920 continue;
921
922 /* expects a path relative to PATH_SANE_CONFIG_DIR */
923 read_config (conffile+plen);
924 }
925
926 closedir (dlld);
927
928 DBG (5, "sane_init/read_dlld: done.\n");
929 }
930
931 SANE_Status
sane_init(SANE_Int * version_code, SANE_Auth_Callback authorize)932 sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
933 {
934 #ifndef __BEOS__
935 char config_line[PATH_MAX];
936 size_t len;
937 FILE *fp;
938 int i;
939 #else
940 DIR *dir;
941 struct dirent *dirent;
942 char path[1024];
943 directory_which which[3] = { B_USER_ADDONS_DIRECTORY, B_COMMON_ADDONS_DIRECTORY, B_BEOS_ADDONS_DIRECTORY };
944 int i;
945 #endif
946
947 DBG_INIT ();
948
949 auth_callback = authorize;
950
951 DBG (1, "sane_init: SANE dll backend version %s from %s\n", DLL_VERSION,
952 PACKAGE_STRING);
953
954 #ifndef __BEOS__
955 /* chain preloaded backends together: */
956 for (i = 0; i < NELEMS (preloaded_backends); ++i)
957 {
958 if (!preloaded_backends[i].name)
959 continue;
960 DBG (3, "sane_init: adding backend `%s' (preloaded)\n", preloaded_backends[i].name);
961 preloaded_backends[i].next = first_backend;
962 first_backend = &preloaded_backends[i];
963 }
964
965 /* Return the version number of the sane-backends package to allow
966 the frontend to print them. This is done only for net and dll,
967 because these backends are usually called by the frontend. */
968 if (version_code)
969 *version_code = SANE_VERSION_CODE (SANE_DLL_V_MAJOR, SANE_DLL_V_MINOR,
970 SANE_DLL_V_BUILD);
971
972 /*
973 * Read dll.conf & dll.d
974 * Read dll.d first, so that the extras backends will be tried last
975 */
976 read_dlld ();
977 read_config (DLL_CONFIG_FILE);
978
979 fp = sanei_config_open (DLL_ALIASES_FILE);
980 if (!fp)
981 return SANE_STATUS_GOOD; /* don't insist on aliases file */
982
983 DBG (5, "sane_init: reading %s\n", DLL_ALIASES_FILE);
984 while (sanei_config_read (config_line, sizeof (config_line), fp))
985 {
986 if (config_line[0] == '#') /* ignore line comments */
987 continue;
988
989 len = strlen (config_line);
990 if (!len)
991 continue; /* ignore empty lines */
992
993 add_alias (config_line);
994 }
995 fclose (fp);
996
997 #else
998 /* no ugly config files, just get scanners from their ~/config/add-ons/SANE */
999 /* look for drivers */
1000 for (i = 0; i < 3; i++)
1001 {
1002 if (find_directory(which[i],0,true,path,1024) < B_OK)
1003 continue;
1004 strcat(path,"/SANE/");
1005 dir=opendir(path);
1006 if(!dir) continue;
1007
1008 while((dirent=readdir(dir)))
1009 {
1010 if((strcmp(dirent->d_name,".")==0) || (strcmp(dirent->d_name,"..")==0)) continue;
1011 if((strcmp(dirent->d_name,"dll")==0)) continue;
1012 add_backend(dirent->d_name,0);
1013 }
1014 closedir(dir);
1015 }
1016 #endif /* __BEOS__ */
1017
1018 return SANE_STATUS_GOOD;
1019 }
1020
1021 void
sane_exit(void)1022 sane_exit (void)
1023 {
1024 struct backend *be, *next;
1025 struct alias *alias;
1026
1027 DBG (2, "sane_exit: exiting\n");
1028
1029 for (be = first_backend; be; be = next)
1030 {
1031 next = be->next;
1032 if (be->loaded)
1033 {
1034 if (be->inited)
1035 {
1036 DBG (3, "sane_exit: calling backend `%s's exit function\n",
1037 be->name);
1038 (*(op_exit_t)be->op[OP_EXIT]) ();
1039 }
1040 #ifdef __BEOS__
1041 /* use BeOS kernel functions to unload add-ons */
1042 if(be->handle) unload_add_on((image_id)be->handle);
1043 #else
1044 #ifdef HAVE_DLL
1045
1046 #ifdef HAVE_DLOPEN
1047 if (be->handle)
1048 dlclose (be->handle);
1049 #elif defined(HAVE_SHL_LOAD)
1050 if (be->handle)
1051 shl_unload (be->handle);
1052 #elif defined(HAVE_NSLINKMODULE)
1053 if (be->handle)
1054 NSUnLinkModule (be->handle, NSUNLINKMODULE_OPTION_NONE
1055 # ifdef __ppc__
1056 | NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES
1057 # endif
1058 );
1059 #else
1060 # error "Tried to compile unsupported DLL."
1061 #endif /* HAVE_DLOPEN */
1062
1063 #endif /* HAVE_DLL */
1064 #endif /* __BEOS__ */
1065 }
1066 if (!be->permanent)
1067 {
1068 if (be->name)
1069 free ((void *) be->name);
1070 free (be);
1071 }
1072 else
1073 {
1074 be->inited = 0;
1075 }
1076 }
1077 first_backend = 0;
1078
1079 while ((alias = first_alias) != NULL)
1080 {
1081 first_alias = first_alias->next;
1082 free (alias->oldname);
1083 free (alias);
1084 }
1085
1086 if (NULL != devlist)
1087 { /* Release memory allocated by sane_get_devices(). */
1088 int i = 0;
1089 while (devlist[i])
1090 free (devlist[i++]);
1091 free (devlist);
1092
1093 devlist = NULL;
1094 devlist_size = 0;
1095 devlist_len = 0;
1096 }
1097 DBG (3, "sane_exit: finished\n");
1098 }
1099
1100 /* Note that a call to get_devices() implies that we'll have to load
1101 all backends. To avoid this, you can call sane_open() directly
1102 (assuming you know the name of the backend/device). This is
1103 appropriate for the command-line interface of SANE, for example.
1104 */
1105 SANE_Status
sane_get_devices(const SANE_Device *** device_list, SANE_Bool local_only)1106 sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
1107 {
1108 const SANE_Device **be_list;
1109 struct backend *be;
1110 SANE_Status status;
1111 char *full_name;
1112 int i, num_devs;
1113 size_t len;
1114 #define ASSERT_SPACE(n) do \
1115 { \
1116 if (devlist_len + (n) > devlist_size) \
1117 { \
1118 devlist_size += (n) + 15; \
1119 if (devlist) \
1120 devlist = realloc (devlist, devlist_size * sizeof (devlist[0])); \
1121 else \
1122 devlist = malloc (devlist_size * sizeof (devlist[0])); \
1123 if (!devlist) \
1124 return SANE_STATUS_NO_MEM; \
1125 } \
1126 } while (0)
1127
1128 DBG (3, "sane_get_devices\n");
1129
1130 if (devlist)
1131 for (i = 0; i < devlist_len; ++i)
1132 free ((void *) devlist[i]);
1133 devlist_len = 0;
1134
1135 for (be = first_backend; be; be = be->next)
1136 {
1137 if (!be->inited)
1138 if (init (be) != SANE_STATUS_GOOD)
1139 continue;
1140
1141 status = (*(op_get_devs_t)be->op[OP_GET_DEVS]) (&be_list, local_only);
1142 if (status != SANE_STATUS_GOOD || !be_list)
1143 continue;
1144
1145 /* count the number of devices for this backend: */
1146 for (num_devs = 0; be_list[num_devs]; ++num_devs);
1147
1148 ASSERT_SPACE (num_devs);
1149
1150 for (i = 0; i < num_devs; ++i)
1151 {
1152 SANE_Device *dev;
1153 char *mem;
1154 struct alias *alias;
1155
1156 for (alias = first_alias; alias != NULL; alias = alias->next)
1157 {
1158 len = strlen (be->name);
1159 if (strlen (alias->oldname) <= len)
1160 continue;
1161 if (strncmp (alias->oldname, be->name, len) == 0
1162 && alias->oldname[len] == ':'
1163 && strcmp (&alias->oldname[len + 1], be_list[i]->name) == 0)
1164 break;
1165 }
1166
1167 if (alias)
1168 {
1169 if (!alias->newname) /* hidden device */
1170 continue;
1171
1172 len = strlen (alias->newname);
1173 mem = malloc (sizeof (*dev) + len + 1);
1174 if (!mem)
1175 return SANE_STATUS_NO_MEM;
1176
1177 full_name = mem + sizeof (*dev);
1178 strcpy (full_name, alias->newname);
1179 }
1180 else
1181 {
1182 /* create a new device entry with a device name that is the
1183 sum of the backend name a colon and the backend's device
1184 name: */
1185 len = strlen (be->name) + 1 + strlen (be_list[i]->name);
1186 mem = malloc (sizeof (*dev) + len + 1);
1187 if (!mem)
1188 return SANE_STATUS_NO_MEM;
1189
1190 full_name = mem + sizeof (*dev);
1191 strcpy (full_name, be->name);
1192 strcat (full_name, ":");
1193 strcat (full_name, be_list[i]->name);
1194 }
1195
1196 dev = (SANE_Device *) mem;
1197 dev->name = full_name;
1198 dev->vendor = be_list[i]->vendor;
1199 dev->model = be_list[i]->model;
1200 dev->type = be_list[i]->type;
1201
1202 devlist[devlist_len++] = dev;
1203 }
1204 }
1205
1206 /* terminate device list with NULL entry: */
1207 ASSERT_SPACE (1);
1208 devlist[devlist_len++] = 0;
1209
1210 *device_list = (const SANE_Device **) devlist;
1211 DBG (3, "sane_get_devices: found %d devices\n", devlist_len - 1);
1212 return SANE_STATUS_GOOD;
1213 }
1214
1215 SANE_Status
sane_open(SANE_String_Const full_name, SANE_Handle * meta_handle)1216 sane_open (SANE_String_Const full_name, SANE_Handle * meta_handle)
1217 {
1218 char *be_name;
1219 const char *dev_name;
1220 struct meta_scanner *s;
1221 SANE_Handle handle;
1222 struct backend *be;
1223 SANE_Status status;
1224 struct alias *alias;
1225
1226 DBG (3, "sane_open: trying to open `%s'\n", full_name);
1227
1228 for (alias = first_alias; alias != NULL; alias = alias->next)
1229 {
1230 if (!alias->newname)
1231 continue;
1232 if (strcmp (alias->newname, full_name) == 0)
1233 {
1234 full_name = alias->oldname;
1235 break;
1236 }
1237 }
1238
1239 dev_name = strchr (full_name, ':');
1240
1241 int is_fakeusb = 0, is_fakeusbdev = 0, is_fakeusbout = 0;
1242
1243 if (dev_name)
1244 {
1245 is_fakeusb = strncmp(full_name, "fakeusb", dev_name - full_name) == 0 &&
1246 dev_name - full_name == 7;
1247 is_fakeusbdev = strncmp(full_name, "fakeusbdev", dev_name - full_name) == 0 &&
1248 dev_name - full_name == 10;
1249 is_fakeusbout = strncmp(full_name, "fakeusbout", dev_name - full_name) == 0 &&
1250 dev_name - full_name == 10;
1251 }
1252
1253 if (is_fakeusb || is_fakeusbdev)
1254 {
1255 ++dev_name; // skip colon
1256 status = sanei_usb_testing_enable_replay(dev_name, is_fakeusbdev);
1257 if (status != SANE_STATUS_GOOD)
1258 return status;
1259
1260 be_name = sanei_usb_testing_get_backend();
1261 if (be_name == NULL)
1262 {
1263 DBG (0, "%s: unknown backend for testing\n", __func__);
1264 return SANE_STATUS_ACCESS_DENIED;
1265 }
1266 }
1267 else
1268 {
1269 char* fakeusbout_path = NULL;
1270 if (is_fakeusbout)
1271 {
1272 ++dev_name; // skip colon
1273
1274 const char* path_end = strchr(dev_name, ':');
1275 if (path_end == NULL)
1276 {
1277 DBG (0, "%s: the device name does not contain path\n", __func__);
1278 return SANE_STATUS_INVAL;
1279 }
1280 fakeusbout_path = strndup(dev_name, path_end - dev_name);
1281
1282 full_name = path_end + 1; // skip colon
1283 dev_name = strchr(full_name, ':');
1284 }
1285
1286 if (dev_name)
1287 {
1288 be_name = strndup(full_name, dev_name - full_name);
1289 ++dev_name; /* skip colon */
1290 }
1291 else
1292 {
1293 /* if no colon interpret full_name as the backend name; an empty
1294 backend device name will cause us to open the first device of
1295 that backend. */
1296 be_name = strdup(full_name);
1297 dev_name = "";
1298 }
1299
1300 if (is_fakeusbout)
1301 {
1302 status = sanei_usb_testing_enable_record(fakeusbout_path, be_name);
1303 free(fakeusbout_path);
1304 if (status != SANE_STATUS_GOOD)
1305 return status;
1306 }
1307 }
1308
1309 if (!be_name)
1310 return SANE_STATUS_NO_MEM;
1311
1312 if (!be_name[0])
1313 be = first_backend;
1314 else
1315 for (be = first_backend; be; be = be->next)
1316 if (strcmp (be->name, be_name) == 0)
1317 break;
1318
1319 if (!be)
1320 {
1321 status = add_backend (be_name, &be);
1322 if (status != SANE_STATUS_GOOD)
1323 {
1324 free(be_name);
1325 return status;
1326 }
1327 }
1328 free(be_name);
1329
1330 if (!be->inited)
1331 {
1332 status = init (be);
1333 if (status != SANE_STATUS_GOOD)
1334 return status;
1335 }
1336
1337 status = (*(op_open_t)be->op[OP_OPEN]) (dev_name, &handle);
1338 if (status != SANE_STATUS_GOOD)
1339 return status;
1340
1341 s = calloc (1, sizeof (*s));
1342 if (!s)
1343 return SANE_STATUS_NO_MEM;
1344
1345 s->be = be;
1346 s->handle = handle;
1347 *meta_handle = s;
1348
1349 DBG (3, "sane_open: open successful\n");
1350 return SANE_STATUS_GOOD;
1351 }
1352
1353 void
sane_close(SANE_Handle handle)1354 sane_close (SANE_Handle handle)
1355 {
1356 struct meta_scanner *s = handle;
1357
1358 DBG (3, "sane_close(handle=%p)\n", handle);
1359 (*(op_close_t)s->be->op[OP_CLOSE]) (s->handle);
1360 free (s);
1361 }
1362
1363 const SANE_Option_Descriptor *
sane_get_option_descriptor(SANE_Handle handle, SANE_Int option)1364 sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
1365 {
1366 struct meta_scanner *s = handle;
1367
1368 DBG (3, "sane_get_option_descriptor(handle=%p,option=%d)\n", handle,
1369 option);
1370 return (*(op_get_option_desc_t)s->be->op[OP_GET_OPTION_DESC]) (s->handle, option);
1371 }
1372
1373 SANE_Status
sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void *value, SANE_Word * info)1374 sane_control_option (SANE_Handle handle, SANE_Int option,
1375 SANE_Action action, void *value, SANE_Word * info)
1376 {
1377 struct meta_scanner *s = handle;
1378
1379 DBG (3,
1380 "sane_control_option(handle=%p,option=%d,action=%d,value=%p,info=%p)\n",
1381 handle, option, action, value, (void *) info);
1382 return (*(op_ctl_option_t)s->be->op[OP_CTL_OPTION]) (s->handle, option, action, value,
1383 info);
1384 }
1385
1386 SANE_Status
sane_get_parameters(SANE_Handle handle, SANE_Parameters * params)1387 sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
1388 {
1389 struct meta_scanner *s = handle;
1390
1391 DBG (3, "sane_get_parameters(handle=%p,params=%p)\n", handle, (void *) params);
1392 return (*(op_get_params_t)s->be->op[OP_GET_PARAMS]) (s->handle, params);
1393 }
1394
1395 SANE_Status
sane_start(SANE_Handle handle)1396 sane_start (SANE_Handle handle)
1397 {
1398 struct meta_scanner *s = handle;
1399
1400 DBG (3, "sane_start(handle=%p)\n", handle);
1401 return (*(op_start_t)s->be->op[OP_START]) (s->handle);
1402 }
1403
1404 SANE_Status
sane_read(SANE_Handle handle, SANE_Byte * data, SANE_Int max_length, SANE_Int * length)1405 sane_read (SANE_Handle handle, SANE_Byte * data, SANE_Int max_length,
1406 SANE_Int * length)
1407 {
1408 struct meta_scanner *s = handle;
1409
1410 DBG (3, "sane_read(handle=%p,data=%p,maxlen=%d,lenp=%p)\n",
1411 handle, (void *) data, max_length, (void *) length);
1412 return (*(op_read_t)s->be->op[OP_READ]) (s->handle, data, max_length, length);
1413 }
1414
1415 void
sane_cancel(SANE_Handle handle)1416 sane_cancel (SANE_Handle handle)
1417 {
1418 struct meta_scanner *s = handle;
1419
1420 DBG (3, "sane_cancel(handle=%p)\n", handle);
1421 (*(op_cancel_t)s->be->op[OP_CANCEL]) (s->handle);
1422 }
1423
1424 SANE_Status
sane_set_io_mode(SANE_Handle handle, SANE_Bool non_blocking)1425 sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
1426 {
1427 struct meta_scanner *s = handle;
1428
1429 DBG (3, "sane_set_io_mode(handle=%p,nonblocking=%d)\n", handle,
1430 non_blocking);
1431 return (*(op_set_io_mode_t)s->be->op[OP_SET_IO_MODE]) (s->handle, non_blocking);
1432 }
1433
1434 SANE_Status
sane_get_select_fd(SANE_Handle handle, SANE_Int * fd)1435 sane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
1436 {
1437 struct meta_scanner *s = handle;
1438
1439 DBG (3, "sane_get_select_fd(handle=%p,fdp=%p)\n", handle, (void *) fd);
1440 return (*(op_get_select_fd_t)s->be->op[OP_GET_SELECT_FD]) (s->handle, fd);
1441 }
1442