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