• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_str()351 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 #ifdef __BEOS__
364 #include <FindDirectory.h>
365 
366 static SANE_Status
load(struct backend * be)367 load (struct backend *be)
368 {
369 	/* use BeOS kernel function to load scanner addons from ~/config/add-ons/SANE */
370 	char path[PATH_MAX];
371 	image_id id = -1;
372 	int i, w;
373 	directory_which which[3] = { B_USER_ADDONS_DIRECTORY, B_COMMON_ADDONS_DIRECTORY, B_BEOS_ADDONS_DIRECTORY };
374 
375 	/* look for config files in SANE/conf */
376 	for (w = 0; (w < 3) && (id < 0) && (find_directory(which[w],0,true,path,PATH_MAX) == 0); w++)
377 	{
378 		strcat(path,"/SANE/");
379 		strcat(path,be->name);
380 		DBG(1, "loading backend %s\n", be->name);
381 
382 		/* initialize all ops to "unsupported" so we can "use" the backend
383      	   even if the stuff later in this function fails */
384 		be->loaded = 1;
385 		be->handle = 0;
386 		for (i = 0; i < NUM_OPS; ++i) be->op[i] = op_unsupported;
387   		DBG(2, "dlopen()ing `%s'\n", path);
388 		id=load_add_on(path);
389 		if (id < 0)
390 		{
391 			continue; /* try next path */
392 		}
393     	be->handle=(void *)id;
394 
395 		for (i = 0; i < NUM_OPS; ++i)
396     	{
397       		void *(*op) ();
398       		op = NULL;
399 	      	/* Look for the symbol */
400 			if ((get_image_symbol(id, op_name[i],B_SYMBOL_TYPE_TEXT,(void **)&op) < 0) || !op)
401 			    DBG(2, "unable to find %s\n", op_name[i]);
402       		else be->op[i]=op;
403       	}
404     }
405 	if (id < 0)
406    	{
407 		DBG(2, "load: couldn't find %s\n",path);
408      	return SANE_STATUS_INVAL;
409    	}
410   return SANE_STATUS_GOOD;
411 }
412 
413 #else
414 static SANE_Status
load(struct backend * be)415 load (struct backend *be)
416 {
417 #ifdef HAVE_DLL
418   int mode = 0;
419   char *funcname, *src, *orig_src = 0, *dir, *path = 0;
420   char libname[PATH_MAX];
421   int i;
422   int src_len;
423   FILE *fp = 0;
424 
425 #if defined(HAVE_DLOPEN)
426 # define PREFIX "libsane-"
427 # ifdef __hpux
428 #   define POSTFIX ".sl.%u"
429 #   define ALT_POSTFIX ".so.%u"
430 # elif defined (HAVE_WINDOWS_H)
431 #   undef PREFIX
432 #   define PREFIX "cygsane-"
433 #   define POSTFIX "-%u.dll"
434 # elif defined (HAVE_OS2_H)
435 #   undef PREFIX
436 #   define PREFIX ""
437 #   define POSTFIX ".dll"
438 # elif defined (__APPLE__) && defined (__MACH__)
439 #   define POSTFIX ".%u.so"
440 # else
441 #   define POSTFIX ".so.%u"
442 # endif
443   mode = getenv ("LD_BIND_NOW") ? RTLD_NOW : RTLD_LAZY;
444 #elif defined(HAVE_SHL_LOAD)
445 # define PREFIX "libsane-"
446 # define POSTFIX ".sl.%u"
447   mode = BIND_DEFERRED;
448 #elif defined(HAVE_NSLINKMODULE)
449 # define PREFIX "libsane-"
450 # define POSTFIX ".%u.so"
451   mode = NSLINKMODULE_OPTION_RETURN_ON_ERROR + NSLINKMODULE_OPTION_PRIVATE;
452 #else
453 # error "Tried to compile unsupported DLL."
454 #endif /* HAVE_DLOPEN */
455 
456   /* initialize all ops to "unsupported" so we can "use" the backend
457      even if the stuff later in this function fails */
458   be->loaded = 1;
459   be->handle = 0;
460   for (i = 0; i < NUM_OPS; ++i)
461     be->op[i] = op_unsupported;
462 
463   path = getenv ("LD_LIBRARY_PATH");
464   if (!path)
465     path = getenv ("SHLIB_PATH");	/* for HP-UX */
466   if (!path)
467     path = getenv ("LIBPATH");	/* for AIX */
468 
469   if (path)
470     {
471       src_len = strlen (path) + strlen (DIR_SEP) + strlen(LIBDIR) + 1;
472       src = malloc (src_len);
473       if (!src)
474 	{
475 	  DBG (1, "load: malloc failed: %s\n", strerror (errno));
476 	  return SANE_STATUS_NO_MEM;
477 	}
478       snprintf (src, src_len, "%s%s%s", path, DIR_SEP, LIBDIR);
479     }
480   else
481     {
482       src = LIBDIR;
483       src = strdup (src);
484       if (!src)
485 	{
486 	  DBG (1, "load: strdup failed: %s\n", strerror (errno));
487 	  return SANE_STATUS_NO_MEM;
488 	}
489     }
490   DBG (3, "load: searching backend `%s' in `%s'\n", be->name, src);
491 
492   orig_src = src;
493   dir = strsep (&src, DIR_SEP);
494 
495   while (dir)
496     {
497 #ifdef HAVE_OS2_H   /* only max 7.3 names work with dlopen() for DLLs on OS/2 */
498       snprintf (libname, sizeof (libname), "%s/" PREFIX "%.2s%.5s" POSTFIX,
499 		dir, be->name, strlen(be->name)>7 ? (be->name)+strlen(be->name)-5 :
500                                             (be->name)+2, V_MAJOR);
501 #else
502       snprintf (libname, sizeof (libname), "%s/" PREFIX "%s" POSTFIX,
503 		dir, be->name, V_MAJOR);
504 #endif
505       DBG (4, "load: trying to load `%s'\n", libname);
506       fp = fopen (libname, "r");
507       if (fp)
508 	break;
509       DBG (4, "load: couldn't open `%s' (%s)\n", libname, strerror (errno));
510 
511 #ifdef ALT_POSTFIX
512       /* Some platforms have two ways of storing their libraries, try both
513 	 postfixes */
514       snprintf (libname, sizeof (libname), "%s/" PREFIX "%s" ALT_POSTFIX,
515 		dir, be->name, V_MAJOR);
516       DBG (4, "load: trying to load `%s'\n", libname);
517       fp = fopen (libname, "r");
518       if (fp)
519 	break;
520       DBG (4, "load: couldn't open `%s' (%s)\n", libname, strerror (errno));
521 #endif
522 
523       dir = strsep (&src, DIR_SEP);
524     }
525   if (orig_src)
526     free (orig_src);
527   if (!fp)
528     {
529       DBG (1, "load: couldn't find backend `%s' (%s)\n",
530 	   be->name, strerror (errno));
531       return SANE_STATUS_INVAL;
532     }
533   fclose (fp);
534   DBG (3, "load: dlopen()ing `%s'\n", libname);
535 
536 #ifdef HAVE_DLOPEN
537   be->handle = dlopen (libname, mode);
538 #elif defined(HAVE_SHL_LOAD)
539   be->handle = (shl_t) shl_load (libname, mode, 0L);
540 #elif defined(HAVE_NSLINKMODULE)
541   {
542     NSObjectFileImage objectfile_img = NULL;
543     if (NSCreateObjectFileImageFromFile (libname, &objectfile_img)
544 	== NSObjectFileImageSuccess)
545       {
546 	be->handle = NSLinkModule (objectfile_img, libname, mode);
547 	NSDestroyObjectFileImage (objectfile_img);
548       }
549   }
550 #else
551 # error "Tried to compile unsupported DLL."
552 #endif /* HAVE_DLOPEN */
553   if (!be->handle)
554     {
555 #ifdef HAVE_DLOPEN
556       DBG (1, "load: dlopen() failed (%s)\n", dlerror ());
557 #elif defined(HAVE_NSLINKMODULE)
558       DBG (1, "load: dyld error (%s)\n", dyld_get_error_str ());
559 #else
560       DBG (1, "load: dlopen() failed (%s)\n", strerror (errno));
561 #endif
562       return SANE_STATUS_INVAL;
563     }
564 
565   /* all is dandy---lookup and fill in backend ops: */
566   funcname = alloca (strlen (be->name) + 64);
567   for (i = 0; i < NUM_OPS; ++i)
568     {
569       void *(*op) (void);
570 
571       sprintf (funcname, "_sane_%s_%s", be->name, op_name[i]);
572 
573       /* First try looking up the symbol without a leading underscore. */
574 #ifdef HAVE_DLOPEN
575       op = posix_dlsym (be->handle, funcname + 1);
576 #elif defined(HAVE_SHL_LOAD)
577       shl_findsym ((shl_t *) & (be->handle), funcname + 1, TYPE_UNDEFINED,
578 		   &op);
579 #elif defined(HAVE_NSLINKMODULE)
580       {
581 	NSSymbol *nssym = NSLookupSymbolInModule (be->handle, funcname);
582 	if (!nssym)
583 	  {
584 	    DBG (15, "dyld error: %s\n", dyld_get_error_str ());
585 	  }
586 	else
587 	  {
588 	    op = (void *(*)(void)) NSAddressOfSymbol (nssym);
589 	  }
590       }
591 #else
592 # error "Tried to compile unsupported DLL."
593 #endif /* HAVE_DLOPEN */
594       if (op)
595 	be->op[i] = op;
596       else
597 	{
598 	  /* Try again, with an underscore prepended. */
599 #ifdef HAVE_DLOPEN
600 	  op = posix_dlsym (be->handle, funcname);
601 #elif defined(HAVE_SHL_LOAD)
602 	  shl_findsym (be->handle, funcname, TYPE_UNDEFINED, &op);
603 #elif defined(HAVE_NSLINKMODULE)
604 	  {
605 	    NSSymbol *nssym = NSLookupSymbolInModule (be->handle, funcname);
606 	    if (!nssym)
607 	      {
608 		DBG (15, "dyld error: %s\n", dyld_get_error_str ());
609 	      }
610 	    else
611 	      {
612 		op = (void *(*)(void)) NSAddressOfSymbol (nssym);
613 	      }
614 	  }
615 #else
616 # error "Tried to compile unsupported DLL."
617 #endif /* HAVE_DLOPEN */
618 	  if (op)
619 	    be->op[i] = op;
620 	}
621       if (NULL == op)
622 	DBG (1, "load: unable to find %s\n", funcname);
623     }
624 
625   return SANE_STATUS_GOOD;
626 
627 # undef PREFIX
628 # undef POSTFIX
629 #else /* HAVE_DLL */
630   DBG (1,
631        "load: ignoring attempt to load `%s'; compiled without dl support\n",
632        be->name);
633   return SANE_STATUS_UNSUPPORTED;
634 #endif /* HAVE_DLL */
635 }
636 #endif /* __BEOS__ */
637 
638 static SANE_Status
init(struct backend * be)639 init (struct backend *be)
640 {
641   SANE_Status status;
642   SANE_Int version;
643 
644   if (!be->loaded)
645     {
646       status = load (be);
647       if (status != SANE_STATUS_GOOD)
648 	return status;
649     }
650 
651   DBG (3, "init: initializing backend `%s'\n", be->name);
652 
653   status = (*(op_init_t)be->op[OP_INIT]) (&version, auth_callback);
654   if (status != SANE_STATUS_GOOD)
655     return status;
656 
657   if (SANE_VERSION_MAJOR (version) != SANE_CURRENT_MAJOR)
658     {
659       DBG (1,
660 	   "init: backend `%s' has a wrong major version (%d instead of %d)\n",
661 	   be->name, SANE_VERSION_MAJOR (version), SANE_CURRENT_MAJOR);
662       return SANE_STATUS_INVAL;
663     }
664   DBG (4, "init: backend `%s' is version %d.%d.%d\n", be->name,
665        SANE_VERSION_MAJOR (version), SANE_VERSION_MINOR (version),
666        SANE_VERSION_BUILD (version));
667 
668   be->inited = 1;
669 
670   return SANE_STATUS_GOOD;
671 }
672 
673 
674 static void
add_alias(const char * line_param)675 add_alias (const char *line_param)
676 {
677 #ifndef __BEOS__
678   const char *command;
679   enum
680   { CMD_ALIAS, CMD_HIDE }
681   cmd;
682   const char *oldname, *oldend, *newname;
683   size_t oldlen, newlen;
684   struct alias *alias;
685   char *line;
686 
687   command = sanei_config_skip_whitespace (line_param);
688   if (!*command)
689     return;
690 
691   line = strchr (command, '#');
692   if (line)
693     *line = '\0';
694 
695   line = strpbrk (command, " \t");
696   if (!line)
697     return;
698   *line++ = '\0';
699 
700   if (strcmp (command, "alias") == 0)
701     cmd = CMD_ALIAS;
702   else if (strcmp (command, "hide") == 0)
703     cmd = CMD_HIDE;
704   else
705     return;
706 
707   newlen = 0;
708   newname = NULL;
709   if (cmd == CMD_ALIAS)
710     {
711       char *newend;
712 
713       newname = sanei_config_skip_whitespace (line);
714       if (!*newname)
715 	return;
716       if (*newname == '\"')
717 	{
718 	  ++newname;
719 	  newend = strchr (newname, '\"');
720 	}
721       else
722 	newend = strpbrk (newname, " \t");
723       if (!newend)
724 	return;
725 
726       newlen = newend - newname;
727       line = (char *) (newend + 1);
728     }
729 
730   oldname = sanei_config_skip_whitespace (line);
731   if (!*oldname)
732     return;
733   oldend = oldname + strcspn (oldname, " \t");
734 
735   oldlen = oldend - oldname;
736 
737   alias = malloc (sizeof (struct alias));
738   if (alias)
739     {
740       alias->oldname = malloc (oldlen + newlen + 2);
741       if (alias->oldname)
742 	{
743 	  strncpy (alias->oldname, oldname, oldlen);
744 	  alias->oldname[oldlen] = '\0';
745 	  if (cmd == CMD_ALIAS)
746 	    {
747 	      alias->newname = alias->oldname + oldlen + 1;
748 	      strncpy (alias->newname, newname, newlen);
749 	      alias->newname[newlen] = '\0';
750 	    }
751 	  else
752 	    alias->newname = NULL;
753 
754 	  alias->next = first_alias;
755 	  first_alias = alias;
756 	  return;
757 	}
758       free (alias);
759     }
760   return;
761 #endif
762 }
763 
764 
765 static void
read_config(const char * conffile)766 read_config (const char *conffile)
767 {
768   FILE *fp;
769   char config_line[PATH_MAX];
770   char *backend_name;
771 
772   fp = sanei_config_open (conffile);
773   if (!fp)
774     {
775       DBG (1, "sane_init/read_config: Couldn't open config file (%s): %s\n",
776            conffile, strerror (errno));
777       return; /* don't insist on config file */
778     }
779 
780   DBG (5, "sane_init/read_config: reading %s\n", conffile);
781   while (sanei_config_read (config_line, sizeof (config_line), fp))
782     {
783       char *comment;
784       SANE_String_Const cp;
785 
786       cp = sanei_config_get_string (config_line, &backend_name);
787       /* ignore empty lines */
788       if (!backend_name || cp == config_line)
789         {
790           if (backend_name)
791             free (backend_name);
792           continue;
793         }
794       /* ignore line comments */
795       if (backend_name[0] == '#')
796         {
797           free (backend_name);
798           continue;
799         }
800       /* ignore comments after backend names */
801       comment = strchr (backend_name, '#');
802       if (comment)
803         *comment = '\0';
804       add_backend (backend_name, 0);
805       free (backend_name);
806     }
807   fclose (fp);
808 }
809 
810 static void
read_dlld(void)811 read_dlld (void)
812 {
813   DIR *dlld;
814   struct dirent *dllconf;
815   struct stat st;
816   char dlldir[PATH_MAX];
817   char conffile[PATH_MAX + strlen("/") + NAME_MAX];
818   size_t len, plen;
819   const char *dir_list;
820   char *copy, *next, *dir;
821 
822   dir_list = sanei_config_get_paths ();
823   if (!dir_list)
824     {
825       DBG(2, "sane_init/read_dlld: Unable to detect configuration directories\n");
826       return;
827     }
828 
829   copy = strdup (dir_list);
830 
831   for (next = copy; (dir = strsep (&next, DIR_SEP)) != NULL;)
832     {
833       snprintf (dlldir, sizeof (dlldir), "%s%s", dir, "/dll.d");
834 
835       DBG(4, "sane_init/read_dlld: attempting to open directory `%s'\n", dlldir);
836 
837       dlld = opendir (dlldir);
838       if (dlld)
839 	{
840 	  /* length of path to parent dir of dll.d/ */
841 	  plen = strlen (dir) + 1;
842 
843 	  DBG(3, "sane_init/read_dlld: using config directory `%s'\n", dlldir);
844 	  break;
845 	}
846     }
847   free (copy);
848 
849   if (dlld == NULL)
850     {
851       DBG (1, "sane_init/read_dlld: opendir failed: %s\n",
852            strerror (errno));
853       return;
854     }
855 
856   while ((dllconf = readdir (dlld)) != NULL)
857     {
858       /* dotfile (or directory) */
859       if (dllconf->d_name[0] == '.')
860         continue;
861 
862       len = strlen (dllconf->d_name);
863 
864       /* backup files */
865       if ((dllconf->d_name[len-1] == '~')
866           || (dllconf->d_name[len-1] == '#'))
867         continue;
868 
869       snprintf (conffile, sizeof(conffile), "%s/%s", dlldir, dllconf->d_name);
870 
871       DBG (5, "sane_init/read_dlld: considering %s\n", conffile);
872 
873       if (stat (conffile, &st) != 0)
874         continue;
875 
876       if (!S_ISREG (st.st_mode))
877         continue;
878 
879       /* expects a path relative to PATH_SANE_CONFIG_DIR */
880       read_config (conffile+plen);
881     }
882 
883   closedir (dlld);
884 
885   DBG (5, "sane_init/read_dlld: done.\n");
886 }
887 
888 SANE_Status
sane_init(SANE_Int * version_code,SANE_Auth_Callback authorize)889 sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
890 {
891 #ifndef __BEOS__
892   char config_line[PATH_MAX];
893   size_t len;
894   FILE *fp;
895   int i;
896 #else
897   DIR *dir;
898   struct dirent *dirent;
899   char path[1024];
900   directory_which which[3] = { B_USER_ADDONS_DIRECTORY, B_COMMON_ADDONS_DIRECTORY, B_BEOS_ADDONS_DIRECTORY };
901   int i;
902 #endif
903 
904   DBG_INIT ();
905 
906   auth_callback = authorize;
907 
908   DBG (1, "sane_init: SANE dll backend version %s from %s\n", DLL_VERSION,
909        PACKAGE_STRING);
910 
911 #ifndef __BEOS__
912   /* chain preloaded backends together: */
913   for (i = 0; i < NELEMS (preloaded_backends); ++i)
914     {
915       if (!preloaded_backends[i].name)
916 	continue;
917       DBG (3, "sane_init: adding backend `%s' (preloaded)\n", preloaded_backends[i].name);
918       preloaded_backends[i].next = first_backend;
919       first_backend = &preloaded_backends[i];
920     }
921 
922   /* Return the version number of the sane-backends package to allow
923      the frontend to print them. This is done only for net and dll,
924      because these backends are usually called by the frontend. */
925   if (version_code)
926     *version_code = SANE_VERSION_CODE (SANE_DLL_V_MAJOR, SANE_DLL_V_MINOR,
927 				       SANE_DLL_V_BUILD);
928 
929   /*
930    * Read dll.conf & dll.d
931    * Read dll.d first, so that the extras backends will be tried last
932    */
933   read_dlld ();
934   read_config (DLL_CONFIG_FILE);
935 
936   fp = sanei_config_open (DLL_ALIASES_FILE);
937   if (!fp)
938     return SANE_STATUS_GOOD;	/* don't insist on aliases file */
939 
940   DBG (5, "sane_init: reading %s\n", DLL_ALIASES_FILE);
941   while (sanei_config_read (config_line, sizeof (config_line), fp))
942     {
943       if (config_line[0] == '#')	/* ignore line comments */
944 	continue;
945 
946       len = strlen (config_line);
947       if (!len)
948 	continue;		/* ignore empty lines */
949 
950       add_alias (config_line);
951     }
952   fclose (fp);
953 
954 #else
955 	/* no ugly config files, just get scanners from their ~/config/add-ons/SANE */
956 	/* look for drivers */
957 	for (i = 0; i < 3; i++)
958 	{
959 		if (find_directory(which[i],0,true,path,1024) < B_OK)
960 			continue;
961 		strcat(path,"/SANE/");
962 		dir=opendir(path);
963 		if(!dir) continue;
964 
965 		while((dirent=readdir(dir)))
966 		{
967 			if((strcmp(dirent->d_name,".")==0) || (strcmp(dirent->d_name,"..")==0)) continue;
968 			if((strcmp(dirent->d_name,"dll")==0)) continue;
969 			add_backend(dirent->d_name,0);
970 		}
971 		closedir(dir);
972 	}
973 #endif /* __BEOS__ */
974 
975   return SANE_STATUS_GOOD;
976 }
977 
978 void
sane_exit(void)979 sane_exit (void)
980 {
981   struct backend *be, *next;
982   struct alias *alias;
983 
984   DBG (2, "sane_exit: exiting\n");
985 
986   for (be = first_backend; be; be = next)
987     {
988       next = be->next;
989       if (be->loaded)
990 	{
991 	  if (be->inited)
992 	    {
993 	      DBG (3, "sane_exit: calling backend `%s's exit function\n",
994 		   be->name);
995 	      (*(op_exit_t)be->op[OP_EXIT]) ();
996 	    }
997 #ifdef __BEOS__
998 	  /* use BeOS kernel functions to unload add-ons */
999 	  if(be->handle) unload_add_on((image_id)be->handle);
1000 #else
1001 #ifdef HAVE_DLL
1002 
1003 #ifdef HAVE_DLOPEN
1004 	  if (be->handle)
1005 	    dlclose (be->handle);
1006 #elif defined(HAVE_SHL_LOAD)
1007 	  if (be->handle)
1008 	    shl_unload (be->handle);
1009 #elif defined(HAVE_NSLINKMODULE)
1010 	  if (be->handle)
1011 	    NSUnLinkModule (be->handle, NSUNLINKMODULE_OPTION_NONE
1012 # ifdef __ppc__
1013 			    | NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES
1014 # endif
1015 	      );
1016 #else
1017 # error "Tried to compile unsupported DLL."
1018 #endif /* HAVE_DLOPEN */
1019 
1020 #endif /* HAVE_DLL */
1021 #endif /* __BEOS__ */
1022 	}
1023       if (!be->permanent)
1024 	{
1025 	  if (be->name)
1026 	    free ((void *) be->name);
1027 	  free (be);
1028 	}
1029       else
1030 	{
1031 	  be->inited = 0;
1032 	}
1033     }
1034   first_backend = 0;
1035 
1036   while ((alias = first_alias) != NULL)
1037     {
1038       first_alias = first_alias->next;
1039       free (alias->oldname);
1040       free (alias);
1041     }
1042 
1043   if (NULL != devlist)
1044     {				/* Release memory allocated by sane_get_devices(). */
1045       int i = 0;
1046       while (devlist[i])
1047 	free (devlist[i++]);
1048       free (devlist);
1049 
1050       devlist = NULL;
1051       devlist_size = 0;
1052       devlist_len = 0;
1053     }
1054   DBG (3, "sane_exit: finished\n");
1055 }
1056 
1057 /* Note that a call to get_devices() implies that we'll have to load
1058    all backends.  To avoid this, you can call sane_open() directly
1059    (assuming you know the name of the backend/device).  This is
1060    appropriate for the command-line interface of SANE, for example.
1061  */
1062 SANE_Status
sane_get_devices(const SANE_Device *** device_list,SANE_Bool local_only)1063 sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
1064 {
1065   const SANE_Device **be_list;
1066   struct backend *be;
1067   SANE_Status status;
1068   char *full_name;
1069   int i, num_devs;
1070   size_t len;
1071 #define ASSERT_SPACE(n) do                                                 \
1072   {                                                                        \
1073     if (devlist_len + (n) > devlist_size)                                  \
1074       {                                                                    \
1075         devlist_size += (n) + 15;                                          \
1076         if (devlist)                                                       \
1077           devlist = realloc (devlist, devlist_size * sizeof (devlist[0])); \
1078         else                                                               \
1079           devlist = malloc (devlist_size * sizeof (devlist[0]));           \
1080         if (!devlist)                                                      \
1081           return SANE_STATUS_NO_MEM;                                       \
1082       }                                                                    \
1083   } while (0)
1084 
1085   DBG (3, "sane_get_devices\n");
1086 
1087   if (devlist)
1088     for (i = 0; i < devlist_len; ++i)
1089       free ((void *) devlist[i]);
1090   devlist_len = 0;
1091 
1092   for (be = first_backend; be; be = be->next)
1093     {
1094       if (!be->inited)
1095 	if (init (be) != SANE_STATUS_GOOD)
1096 	  continue;
1097 
1098       status = (*(op_get_devs_t)be->op[OP_GET_DEVS]) (&be_list, local_only);
1099       if (status != SANE_STATUS_GOOD || !be_list)
1100 	continue;
1101 
1102       /* count the number of devices for this backend: */
1103       for (num_devs = 0; be_list[num_devs]; ++num_devs);
1104 
1105       ASSERT_SPACE (num_devs);
1106 
1107       for (i = 0; i < num_devs; ++i)
1108 	{
1109 	  SANE_Device *dev;
1110 	  char *mem;
1111 	  struct alias *alias;
1112 
1113 	  for (alias = first_alias; alias != NULL; alias = alias->next)
1114 	    {
1115 	      len = strlen (be->name);
1116 	      if (strlen (alias->oldname) <= len)
1117 		continue;
1118 	      if (strncmp (alias->oldname, be->name, len) == 0
1119 		  && alias->oldname[len] == ':'
1120 		  && strcmp (&alias->oldname[len + 1], be_list[i]->name) == 0)
1121 		break;
1122 	    }
1123 
1124 	  if (alias)
1125 	    {
1126 	      if (!alias->newname)	/* hidden device */
1127 		continue;
1128 
1129 	      len = strlen (alias->newname);
1130 	      mem = malloc (sizeof (*dev) + len + 1);
1131 	      if (!mem)
1132 		return SANE_STATUS_NO_MEM;
1133 
1134 	      full_name = mem + sizeof (*dev);
1135 	      strcpy (full_name, alias->newname);
1136 	    }
1137 	  else
1138 	    {
1139 	      /* create a new device entry with a device name that is the
1140 	         sum of the backend name a colon and the backend's device
1141 	         name: */
1142 	      len = strlen (be->name) + 1 + strlen (be_list[i]->name);
1143 	      mem = malloc (sizeof (*dev) + len + 1);
1144 	      if (!mem)
1145 		return SANE_STATUS_NO_MEM;
1146 
1147 	      full_name = mem + sizeof (*dev);
1148 	      strcpy (full_name, be->name);
1149 	      strcat (full_name, ":");
1150 	      strcat (full_name, be_list[i]->name);
1151 	    }
1152 
1153 	  dev = (SANE_Device *) mem;
1154 	  dev->name = full_name;
1155 	  dev->vendor = be_list[i]->vendor;
1156 	  dev->model = be_list[i]->model;
1157 	  dev->type = be_list[i]->type;
1158 
1159 	  devlist[devlist_len++] = dev;
1160 	}
1161     }
1162 
1163   /* terminate device list with NULL entry: */
1164   ASSERT_SPACE (1);
1165   devlist[devlist_len++] = 0;
1166 
1167   *device_list = (const SANE_Device **) devlist;
1168   DBG (3, "sane_get_devices: found %d devices\n", devlist_len - 1);
1169   return SANE_STATUS_GOOD;
1170 }
1171 
1172 SANE_Status
sane_open(SANE_String_Const full_name,SANE_Handle * meta_handle)1173 sane_open (SANE_String_Const full_name, SANE_Handle * meta_handle)
1174 {
1175   char *be_name;
1176   const char *dev_name;
1177   struct meta_scanner *s;
1178   SANE_Handle handle;
1179   struct backend *be;
1180   SANE_Status status;
1181   struct alias *alias;
1182 
1183   DBG (3, "sane_open: trying to open `%s'\n", full_name);
1184 
1185   for (alias = first_alias; alias != NULL; alias = alias->next)
1186     {
1187       if (!alias->newname)
1188 	continue;
1189       if (strcmp (alias->newname, full_name) == 0)
1190 	{
1191 	  full_name = alias->oldname;
1192 	  break;
1193 	}
1194     }
1195 
1196   dev_name = strchr (full_name, ':');
1197 
1198   int is_fakeusb = 0, is_fakeusbdev = 0, is_fakeusbout = 0;
1199 
1200   if (dev_name)
1201     {
1202       is_fakeusb = strncmp(full_name, "fakeusb", dev_name - full_name) == 0 &&
1203           dev_name - full_name == 7;
1204       is_fakeusbdev = strncmp(full_name, "fakeusbdev", dev_name - full_name) == 0 &&
1205           dev_name - full_name == 10;
1206       is_fakeusbout = strncmp(full_name, "fakeusbout", dev_name - full_name) == 0 &&
1207           dev_name - full_name == 10;
1208     }
1209 
1210   if (is_fakeusb || is_fakeusbdev)
1211     {
1212       ++dev_name; // skip colon
1213       status = sanei_usb_testing_enable_replay(dev_name, is_fakeusbdev);
1214       if (status != SANE_STATUS_GOOD)
1215         return status;
1216 
1217       be_name = sanei_usb_testing_get_backend();
1218       if (be_name == NULL)
1219         {
1220           DBG (0, "%s: unknown backend for testing\n", __func__);
1221           return SANE_STATUS_ACCESS_DENIED;
1222         }
1223     }
1224   else
1225     {
1226       char* fakeusbout_path = NULL;
1227       if (is_fakeusbout)
1228       {
1229         ++dev_name; // skip colon
1230 
1231         const char* path_end = strchr(dev_name, ':');
1232         if (path_end == NULL)
1233           {
1234             DBG (0, "%s: the device name does not contain path\n", __func__);
1235             return SANE_STATUS_INVAL;
1236           }
1237         fakeusbout_path = strndup(dev_name, path_end - dev_name);
1238 
1239         full_name = path_end + 1; // skip colon
1240         dev_name = strchr(full_name, ':');
1241       }
1242 
1243       if (dev_name)
1244         {
1245           be_name = strndup(full_name, dev_name - full_name);
1246           ++dev_name;		/* skip colon */
1247         }
1248       else
1249         {
1250           /* if no colon interpret full_name as the backend name; an empty
1251              backend device name will cause us to open the first device of
1252              that backend.  */
1253           be_name = strdup(full_name);
1254           dev_name = "";
1255         }
1256 
1257       if (is_fakeusbout)
1258         {
1259           status = sanei_usb_testing_enable_record(fakeusbout_path, be_name);
1260           free(fakeusbout_path);
1261           if (status != SANE_STATUS_GOOD)
1262             return status;
1263         }
1264     }
1265 
1266   if (!be_name)
1267     return SANE_STATUS_NO_MEM;
1268 
1269   if (!be_name[0])
1270     be = first_backend;
1271   else
1272     for (be = first_backend; be; be = be->next)
1273       if (strcmp (be->name, be_name) == 0)
1274 	break;
1275 
1276   if (!be)
1277     {
1278       status = add_backend (be_name, &be);
1279       if (status != SANE_STATUS_GOOD)
1280         {
1281           free(be_name);
1282           return status;
1283         }
1284     }
1285   free(be_name);
1286 
1287   if (!be->inited)
1288     {
1289       status = init (be);
1290       if (status != SANE_STATUS_GOOD)
1291 	return status;
1292     }
1293 
1294   status = (*(op_open_t)be->op[OP_OPEN]) (dev_name, &handle);
1295   if (status != SANE_STATUS_GOOD)
1296     return status;
1297 
1298   s = calloc (1, sizeof (*s));
1299   if (!s)
1300     return SANE_STATUS_NO_MEM;
1301 
1302   s->be = be;
1303   s->handle = handle;
1304   *meta_handle = s;
1305 
1306   DBG (3, "sane_open: open successful\n");
1307   return SANE_STATUS_GOOD;
1308 }
1309 
1310 void
sane_close(SANE_Handle handle)1311 sane_close (SANE_Handle handle)
1312 {
1313   struct meta_scanner *s = handle;
1314 
1315   DBG (3, "sane_close(handle=%p)\n", handle);
1316   (*(op_close_t)s->be->op[OP_CLOSE]) (s->handle);
1317   free (s);
1318 }
1319 
1320 const SANE_Option_Descriptor *
sane_get_option_descriptor(SANE_Handle handle,SANE_Int option)1321 sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
1322 {
1323   struct meta_scanner *s = handle;
1324 
1325   DBG (3, "sane_get_option_descriptor(handle=%p,option=%d)\n", handle,
1326        option);
1327   return (*(op_get_option_desc_t)s->be->op[OP_GET_OPTION_DESC]) (s->handle, option);
1328 }
1329 
1330 SANE_Status
sane_control_option(SANE_Handle handle,SANE_Int option,SANE_Action action,void * value,SANE_Word * info)1331 sane_control_option (SANE_Handle handle, SANE_Int option,
1332 		     SANE_Action action, void *value, SANE_Word * info)
1333 {
1334   struct meta_scanner *s = handle;
1335 
1336   DBG (3,
1337        "sane_control_option(handle=%p,option=%d,action=%d,value=%p,info=%p)\n",
1338        handle, option, action, value, (void *) info);
1339   return (*(op_ctl_option_t)s->be->op[OP_CTL_OPTION]) (s->handle, option, action, value,
1340 					     info);
1341 }
1342 
1343 SANE_Status
sane_get_parameters(SANE_Handle handle,SANE_Parameters * params)1344 sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
1345 {
1346   struct meta_scanner *s = handle;
1347 
1348   DBG (3, "sane_get_parameters(handle=%p,params=%p)\n", handle, (void *) params);
1349   return (*(op_get_params_t)s->be->op[OP_GET_PARAMS]) (s->handle, params);
1350 }
1351 
1352 SANE_Status
sane_start(SANE_Handle handle)1353 sane_start (SANE_Handle handle)
1354 {
1355   struct meta_scanner *s = handle;
1356 
1357   DBG (3, "sane_start(handle=%p)\n", handle);
1358   return (*(op_start_t)s->be->op[OP_START]) (s->handle);
1359 }
1360 
1361 SANE_Status
sane_read(SANE_Handle handle,SANE_Byte * data,SANE_Int max_length,SANE_Int * length)1362 sane_read (SANE_Handle handle, SANE_Byte * data, SANE_Int max_length,
1363 	   SANE_Int * length)
1364 {
1365   struct meta_scanner *s = handle;
1366 
1367   DBG (3, "sane_read(handle=%p,data=%p,maxlen=%d,lenp=%p)\n",
1368        handle, (void *) data, max_length, (void *) length);
1369   return (*(op_read_t)s->be->op[OP_READ]) (s->handle, data, max_length, length);
1370 }
1371 
1372 void
sane_cancel(SANE_Handle handle)1373 sane_cancel (SANE_Handle handle)
1374 {
1375   struct meta_scanner *s = handle;
1376 
1377   DBG (3, "sane_cancel(handle=%p)\n", handle);
1378   (*(op_cancel_t)s->be->op[OP_CANCEL]) (s->handle);
1379 }
1380 
1381 SANE_Status
sane_set_io_mode(SANE_Handle handle,SANE_Bool non_blocking)1382 sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
1383 {
1384   struct meta_scanner *s = handle;
1385 
1386   DBG (3, "sane_set_io_mode(handle=%p,nonblocking=%d)\n", handle,
1387        non_blocking);
1388   return (*(op_set_io_mode_t)s->be->op[OP_SET_IO_MODE]) (s->handle, non_blocking);
1389 }
1390 
1391 SANE_Status
sane_get_select_fd(SANE_Handle handle,SANE_Int * fd)1392 sane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
1393 {
1394   struct meta_scanner *s = handle;
1395 
1396   DBG (3, "sane_get_select_fd(handle=%p,fdp=%p)\n", handle, (void *) fd);
1397   return (*(op_get_select_fd_t)s->be->op[OP_GET_SELECT_FD]) (s->handle, fd);
1398 }
1399