1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy. 2141cc406Sopenharmony_ci Copyright (C) 1996, 1997 David Mosberger-Tang 3141cc406Sopenharmony_ci This file is part of the SANE package. 4141cc406Sopenharmony_ci 5141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 6141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 7141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 8141cc406Sopenharmony_ci License, or (at your option) any later version. 9141cc406Sopenharmony_ci 10141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 11141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 12141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13141cc406Sopenharmony_ci General Public License for more details. 14141cc406Sopenharmony_ci 15141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 16141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 17141cc406Sopenharmony_ci 18141cc406Sopenharmony_ci As a special exception, the authors of SANE give permission for 19141cc406Sopenharmony_ci additional uses of the libraries contained in this release of SANE. 20141cc406Sopenharmony_ci 21141cc406Sopenharmony_ci The exception is that, if you link a SANE library with other files 22141cc406Sopenharmony_ci to produce an executable, this does not by itself cause the 23141cc406Sopenharmony_ci resulting executable to be covered by the GNU General Public 24141cc406Sopenharmony_ci License. Your use of that executable is in no way restricted on 25141cc406Sopenharmony_ci account of linking the SANE library code into it. 26141cc406Sopenharmony_ci 27141cc406Sopenharmony_ci This exception does not, however, invalidate any other reasons why 28141cc406Sopenharmony_ci the executable file might be covered by the GNU General Public 29141cc406Sopenharmony_ci License. 30141cc406Sopenharmony_ci 31141cc406Sopenharmony_ci If you submit changes to SANE to the maintainers to be included in 32141cc406Sopenharmony_ci a subsequent release, you agree by submitting the changes that 33141cc406Sopenharmony_ci those changes may be distributed with this exception intact. 34141cc406Sopenharmony_ci 35141cc406Sopenharmony_ci If you write modifications of your own for SANE, it is your choice 36141cc406Sopenharmony_ci whether to permit this exception to apply to your modifications. 37141cc406Sopenharmony_ci If you do not wish that, delete this exception notice. 38141cc406Sopenharmony_ci 39141cc406Sopenharmony_ci This file implements a dynamic linking based SANE meta backend. It 40141cc406Sopenharmony_ci allows managing an arbitrary number of SANE backends by using 41141cc406Sopenharmony_ci dynamic linking to load backends on demand. */ 42141cc406Sopenharmony_ci 43141cc406Sopenharmony_ci/* Please increase version number with every change 44141cc406Sopenharmony_ci (don't forget to update dll.desc) */ 45141cc406Sopenharmony_ci#define DLL_VERSION "1.0.13" 46141cc406Sopenharmony_ci 47141cc406Sopenharmony_ci#ifdef _AIX 48141cc406Sopenharmony_ci# include "lalloca.h" /* MUST come first for AIX! */ 49141cc406Sopenharmony_ci#endif 50141cc406Sopenharmony_ci 51141cc406Sopenharmony_ci#ifdef __BEOS__ 52141cc406Sopenharmony_ci#include <kernel/OS.h> 53141cc406Sopenharmony_ci#include <storage/FindDirectory.h> 54141cc406Sopenharmony_ci#include <kernel/image.h> 55141cc406Sopenharmony_ci#include <posix/dirent.h> 56141cc406Sopenharmony_ci#endif 57141cc406Sopenharmony_ci 58141cc406Sopenharmony_ci#include "../include/sane/config.h" 59141cc406Sopenharmony_ci#include "lalloca.h" 60141cc406Sopenharmony_ci 61141cc406Sopenharmony_ci#include <errno.h> 62141cc406Sopenharmony_ci#include <limits.h> 63141cc406Sopenharmony_ci#include <stdio.h> 64141cc406Sopenharmony_ci#include <stdlib.h> 65141cc406Sopenharmony_ci#include <string.h> 66141cc406Sopenharmony_ci 67141cc406Sopenharmony_ci#if defined(HAVE_DLOPEN) && defined(HAVE_DLFCN_H) 68141cc406Sopenharmony_ci# include <dlfcn.h> 69141cc406Sopenharmony_ci 70141cc406Sopenharmony_ci /* This works around a pedantic GCC compiler warning. The ISO C 71141cc406Sopenharmony_ci standard says that the behaviour of converting an object pointer 72141cc406Sopenharmony_ci like the void * returned by dlsym() to a function pointer like 73141cc406Sopenharmony_ci void *(*)() is implementation defined. POSIX though guarantees 74141cc406Sopenharmony_ci that this works fine. 75141cc406Sopenharmony_ci 76141cc406Sopenharmony_ci Workaround based on http://stackoverflow.com/a/36385690. Turns 77141cc406Sopenharmony_ci off pedantic warnings for the duration of the definition only. 78141cc406Sopenharmony_ci */ 79141cc406Sopenharmony_ci# pragma GCC diagnostic push 80141cc406Sopenharmony_ci# pragma GCC diagnostic ignored "-Wpedantic" 81141cc406Sopenharmony_citypedef void *(*func_ptr)(void); 82141cc406Sopenharmony_ci 83141cc406Sopenharmony_cifunc_ptr 84141cc406Sopenharmony_ciposix_dlsym (void *handle, const char *func) 85141cc406Sopenharmony_ci{ 86141cc406Sopenharmony_ci return dlsym (handle, func); 87141cc406Sopenharmony_ci} 88141cc406Sopenharmony_ci# pragma GCC diagnostic pop 89141cc406Sopenharmony_ci 90141cc406Sopenharmony_ci /* Similar to the above, GCC also warns about conversion between 91141cc406Sopenharmony_ci pointers to functions. The ISO C standard says that invoking a 92141cc406Sopenharmony_ci converted pointer to a function whose type is not compatible with 93141cc406Sopenharmony_ci the pointed-to type, the behavior is undefined. Although GCC is 94141cc406Sopenharmony_ci correct to warn about this, the dll backend has been using these 95141cc406Sopenharmony_ci conversions without issues for a very long time already. 96141cc406Sopenharmony_ci 97141cc406Sopenharmony_ci Rather than push/pop around every use, which would get very ugly 98141cc406Sopenharmony_ci real fast, ignore this particular warning for the remainder of 99141cc406Sopenharmony_ci the file. 100141cc406Sopenharmony_ci */ 101141cc406Sopenharmony_ci# pragma GCC diagnostic ignored "-Wpragmas" /* backward compatibility */ 102141cc406Sopenharmony_ci# pragma GCC diagnostic ignored "-Wcast-function-type" 103141cc406Sopenharmony_ci 104141cc406Sopenharmony_ci /* Older versions of dlopen() don't define RTLD_NOW and RTLD_LAZY. 105141cc406Sopenharmony_ci They all seem to use a mode of 1 to indicate RTLD_NOW and some do 106141cc406Sopenharmony_ci not support RTLD_LAZY at all. Hence, unless defined, we define 107141cc406Sopenharmony_ci both macros as 1 to play it safe. */ 108141cc406Sopenharmony_ci# ifndef RTLD_NOW 109141cc406Sopenharmony_ci# define RTLD_NOW 1 110141cc406Sopenharmony_ci# endif 111141cc406Sopenharmony_ci# ifndef RTLD_LAZY 112141cc406Sopenharmony_ci# define RTLD_LAZY 1 113141cc406Sopenharmony_ci# endif 114141cc406Sopenharmony_ci# define HAVE_DLL 115141cc406Sopenharmony_ci#endif 116141cc406Sopenharmony_ci 117141cc406Sopenharmony_ci/* HP/UX DLL support */ 118141cc406Sopenharmony_ci#if defined (HAVE_SHL_LOAD) && defined(HAVE_DL_H) 119141cc406Sopenharmony_ci# include <dl.h> 120141cc406Sopenharmony_ci# define HAVE_DLL 121141cc406Sopenharmony_ci#endif 122141cc406Sopenharmony_ci 123141cc406Sopenharmony_ci/* Mac OS X/Darwin support */ 124141cc406Sopenharmony_ci#if defined (HAVE_NSLINKMODULE) && defined(HAVE_MACH_O_DYLD_H) 125141cc406Sopenharmony_ci# include <mach-o/dyld.h> 126141cc406Sopenharmony_ci# define HAVE_DLL 127141cc406Sopenharmony_ci#endif 128141cc406Sopenharmony_ci 129141cc406Sopenharmony_ci#include <sys/types.h> 130141cc406Sopenharmony_ci#include <sys/stat.h> 131141cc406Sopenharmony_ci#include <dirent.h> 132141cc406Sopenharmony_ci 133141cc406Sopenharmony_ci#include "../include/sane/sane.h" 134141cc406Sopenharmony_ci#include "../include/sane/sanei.h" 135141cc406Sopenharmony_ci 136141cc406Sopenharmony_ci#define BACKEND_NAME dll 137141cc406Sopenharmony_ci#include "../include/sane/sanei_backend.h" 138141cc406Sopenharmony_ci 139141cc406Sopenharmony_ci#ifndef PATH_MAX 140141cc406Sopenharmony_ci# define PATH_MAX 1024 141141cc406Sopenharmony_ci#endif 142141cc406Sopenharmony_ci 143141cc406Sopenharmony_ci#ifndef NAME_MAX 144141cc406Sopenharmony_ci# define NAME_MAX FILENAME_MAX 145141cc406Sopenharmony_ci#endif 146141cc406Sopenharmony_ci 147141cc406Sopenharmony_ci#if defined(_WIN32) || defined(HAVE_OS2_H) 148141cc406Sopenharmony_ci# define DIR_SEP ";" 149141cc406Sopenharmony_ci#else 150141cc406Sopenharmony_ci# define DIR_SEP ":" 151141cc406Sopenharmony_ci#endif 152141cc406Sopenharmony_ci 153141cc406Sopenharmony_ci 154141cc406Sopenharmony_ci#include "../include/sane/sanei_config.h" 155141cc406Sopenharmony_ci#define DLL_CONFIG_FILE "dll.conf" 156141cc406Sopenharmony_ci#define DLL_ALIASES_FILE "dll.aliases" 157141cc406Sopenharmony_ci 158141cc406Sopenharmony_ci#include "../include/sane/sanei_usb.h" 159141cc406Sopenharmony_ci 160141cc406Sopenharmony_cienum SANE_Ops 161141cc406Sopenharmony_ci{ 162141cc406Sopenharmony_ci OP_INIT = 0, 163141cc406Sopenharmony_ci OP_EXIT, 164141cc406Sopenharmony_ci OP_GET_DEVS, 165141cc406Sopenharmony_ci OP_OPEN, 166141cc406Sopenharmony_ci OP_CLOSE, 167141cc406Sopenharmony_ci OP_GET_OPTION_DESC, 168141cc406Sopenharmony_ci OP_CTL_OPTION, 169141cc406Sopenharmony_ci OP_GET_PARAMS, 170141cc406Sopenharmony_ci OP_START, 171141cc406Sopenharmony_ci OP_READ, 172141cc406Sopenharmony_ci OP_CANCEL, 173141cc406Sopenharmony_ci OP_SET_IO_MODE, 174141cc406Sopenharmony_ci OP_GET_SELECT_FD, 175141cc406Sopenharmony_ci NUM_OPS 176141cc406Sopenharmony_ci}; 177141cc406Sopenharmony_ci 178141cc406Sopenharmony_citypedef SANE_Status (*op_init_t) (SANE_Int *, SANE_Auth_Callback); 179141cc406Sopenharmony_citypedef void (*op_exit_t) (void); 180141cc406Sopenharmony_citypedef SANE_Status (*op_get_devs_t) (const SANE_Device ***, SANE_Bool); 181141cc406Sopenharmony_citypedef SANE_Status (*op_open_t) (SANE_String_Const, SANE_Handle *); 182141cc406Sopenharmony_citypedef void (*op_close_t) (SANE_Handle); 183141cc406Sopenharmony_citypedef const SANE_Option_Descriptor * (*op_get_option_desc_t) (SANE_Handle, 184141cc406Sopenharmony_ci SANE_Int); 185141cc406Sopenharmony_citypedef SANE_Status (*op_ctl_option_t) (SANE_Handle, SANE_Int, SANE_Action, 186141cc406Sopenharmony_ci void *, SANE_Int *); 187141cc406Sopenharmony_citypedef SANE_Status (*op_get_params_t) (SANE_Handle, SANE_Parameters *); 188141cc406Sopenharmony_citypedef SANE_Status (*op_start_t) (SANE_Handle); 189141cc406Sopenharmony_citypedef SANE_Status (*op_read_t) (SANE_Handle, SANE_Byte *, SANE_Int, 190141cc406Sopenharmony_ci SANE_Int *); 191141cc406Sopenharmony_citypedef void (*op_cancel_t) (SANE_Handle); 192141cc406Sopenharmony_citypedef SANE_Status (*op_set_io_mode_t) (SANE_Handle, SANE_Bool); 193141cc406Sopenharmony_citypedef SANE_Status (*op_get_select_fd_t) (SANE_Handle, SANE_Int *); 194141cc406Sopenharmony_ci 195141cc406Sopenharmony_cistruct backend 196141cc406Sopenharmony_ci{ 197141cc406Sopenharmony_ci struct backend *next; 198141cc406Sopenharmony_ci char *name; 199141cc406Sopenharmony_ci u_int permanent:1; /* is the backend preloaded? */ 200141cc406Sopenharmony_ci u_int loaded:1; /* are the functions available? */ 201141cc406Sopenharmony_ci u_int inited:1; /* has the backend been initialized? */ 202141cc406Sopenharmony_ci void *handle; /* handle returned by dlopen() */ 203141cc406Sopenharmony_ci void *(*op[NUM_OPS]) (void); 204141cc406Sopenharmony_ci}; 205141cc406Sopenharmony_ci 206141cc406Sopenharmony_ci#define BE_ENTRY(be,func) sane_##be##_##func 207141cc406Sopenharmony_ci 208141cc406Sopenharmony_ci#define PRELOAD_DECL(name) \ 209141cc406Sopenharmony_ci extern SANE_Status BE_ENTRY(name,init) (SANE_Int *, SANE_Auth_Callback); \ 210141cc406Sopenharmony_ci extern void BE_ENTRY(name,exit) (void); \ 211141cc406Sopenharmony_ci extern SANE_Status BE_ENTRY(name,get_devices) (const SANE_Device ***, SANE_Bool); \ 212141cc406Sopenharmony_ci extern SANE_Status BE_ENTRY(name,open) (SANE_String_Const, SANE_Handle *); \ 213141cc406Sopenharmony_ci extern void BE_ENTRY(name,close) (SANE_Handle); \ 214141cc406Sopenharmony_ci extern const SANE_Option_Descriptor *BE_ENTRY(name,get_option_descriptor) (SANE_Handle, SANE_Int); \ 215141cc406Sopenharmony_ci extern SANE_Status BE_ENTRY(name,control_option) (SANE_Handle, SANE_Int, SANE_Action, void *, SANE_Int *); \ 216141cc406Sopenharmony_ci extern SANE_Status BE_ENTRY(name,get_parameters) (SANE_Handle, SANE_Parameters *); \ 217141cc406Sopenharmony_ci extern SANE_Status BE_ENTRY(name,start) (SANE_Handle); \ 218141cc406Sopenharmony_ci extern SANE_Status BE_ENTRY(name,read) (SANE_Handle, SANE_Byte *, SANE_Int, SANE_Int *); \ 219141cc406Sopenharmony_ci extern void BE_ENTRY(name,cancel) (SANE_Handle); \ 220141cc406Sopenharmony_ci extern SANE_Status BE_ENTRY(name,set_io_mode) (SANE_Handle, SANE_Bool); \ 221141cc406Sopenharmony_ci extern SANE_Status BE_ENTRY(name,get_select_fd) (SANE_Handle, SANE_Int *); 222141cc406Sopenharmony_ci 223141cc406Sopenharmony_ci#define PRELOAD_DEFN(name) \ 224141cc406Sopenharmony_ci{ \ 225141cc406Sopenharmony_ci 0 /* next */, #name, \ 226141cc406Sopenharmony_ci 1 /* permanent */, \ 227141cc406Sopenharmony_ci 1 /* loaded */, \ 228141cc406Sopenharmony_ci 0 /* inited */, \ 229141cc406Sopenharmony_ci 0 /* handle */, \ 230141cc406Sopenharmony_ci { \ 231141cc406Sopenharmony_ci BE_ENTRY(name,init), \ 232141cc406Sopenharmony_ci BE_ENTRY(name,exit), \ 233141cc406Sopenharmony_ci BE_ENTRY(name,get_devices), \ 234141cc406Sopenharmony_ci BE_ENTRY(name,open), \ 235141cc406Sopenharmony_ci BE_ENTRY(name,close), \ 236141cc406Sopenharmony_ci BE_ENTRY(name,get_option_descriptor), \ 237141cc406Sopenharmony_ci BE_ENTRY(name,control_option), \ 238141cc406Sopenharmony_ci BE_ENTRY(name,get_parameters), \ 239141cc406Sopenharmony_ci BE_ENTRY(name,start), \ 240141cc406Sopenharmony_ci BE_ENTRY(name,read), \ 241141cc406Sopenharmony_ci BE_ENTRY(name,cancel), \ 242141cc406Sopenharmony_ci BE_ENTRY(name,set_io_mode), \ 243141cc406Sopenharmony_ci BE_ENTRY(name,get_select_fd) \ 244141cc406Sopenharmony_ci } \ 245141cc406Sopenharmony_ci} 246141cc406Sopenharmony_ci 247141cc406Sopenharmony_ci#ifndef __BEOS__ 248141cc406Sopenharmony_ci#ifdef ENABLE_PRELOAD 249141cc406Sopenharmony_ci#include "dll-preload.h" 250141cc406Sopenharmony_ci#else 251141cc406Sopenharmony_cistatic struct backend preloaded_backends[] = { 252141cc406Sopenharmony_ci { 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }} 253141cc406Sopenharmony_ci}; 254141cc406Sopenharmony_ci#endif 255141cc406Sopenharmony_ci#endif 256141cc406Sopenharmony_ci 257141cc406Sopenharmony_cistruct meta_scanner 258141cc406Sopenharmony_ci{ 259141cc406Sopenharmony_ci struct backend *be; 260141cc406Sopenharmony_ci SANE_Handle handle; 261141cc406Sopenharmony_ci}; 262141cc406Sopenharmony_ci 263141cc406Sopenharmony_cistruct alias 264141cc406Sopenharmony_ci{ 265141cc406Sopenharmony_ci struct alias *next; 266141cc406Sopenharmony_ci char *oldname; 267141cc406Sopenharmony_ci char *newname; 268141cc406Sopenharmony_ci}; 269141cc406Sopenharmony_ci 270141cc406Sopenharmony_ci/* 271141cc406Sopenharmony_ci * List of available devices, allocated by sane_get_devices, released 272141cc406Sopenharmony_ci * by sane_exit() 273141cc406Sopenharmony_ci */ 274141cc406Sopenharmony_cistatic SANE_Device **devlist = NULL; 275141cc406Sopenharmony_cistatic int devlist_size = 0, devlist_len = 0; 276141cc406Sopenharmony_ci 277141cc406Sopenharmony_cistatic struct alias *first_alias; 278141cc406Sopenharmony_cistatic SANE_Auth_Callback auth_callback; 279141cc406Sopenharmony_cistatic struct backend *first_backend; 280141cc406Sopenharmony_ci 281141cc406Sopenharmony_ci#ifndef __BEOS__ 282141cc406Sopenharmony_cistatic const char *op_name[] = { 283141cc406Sopenharmony_ci "init", "exit", "get_devices", "open", "close", "get_option_descriptor", 284141cc406Sopenharmony_ci "control_option", "get_parameters", "start", "read", "cancel", 285141cc406Sopenharmony_ci "set_io_mode", "get_select_fd" 286141cc406Sopenharmony_ci}; 287141cc406Sopenharmony_ci#else 288141cc406Sopenharmony_cistatic const char *op_name[] = { 289141cc406Sopenharmony_ci "sane_init", "sane_exit", "sane_get_devices", "sane_open", "sane_close", "sane_get_option_descriptor", 290141cc406Sopenharmony_ci "sane_control_option", "sane_get_parameters", "sane_start", "sane_read", "sane_cancel", 291141cc406Sopenharmony_ci "sane_set_io_mode", "sane_get_select_fd" 292141cc406Sopenharmony_ci}; 293141cc406Sopenharmony_ci#endif /* __BEOS__ */ 294141cc406Sopenharmony_ci 295141cc406Sopenharmony_cistatic void * 296141cc406Sopenharmony_ciop_unsupported (void) 297141cc406Sopenharmony_ci{ 298141cc406Sopenharmony_ci DBG (1, "op_unsupported: call to unsupported backend operation\n"); 299141cc406Sopenharmony_ci return (void *) (long) SANE_STATUS_UNSUPPORTED; 300141cc406Sopenharmony_ci} 301141cc406Sopenharmony_ci 302141cc406Sopenharmony_ci 303141cc406Sopenharmony_cistatic SANE_Status 304141cc406Sopenharmony_ciadd_backend (const char *name, struct backend **bep) 305141cc406Sopenharmony_ci{ 306141cc406Sopenharmony_ci struct backend *be, *prev; 307141cc406Sopenharmony_ci 308141cc406Sopenharmony_ci DBG (3, "add_backend: adding backend `%s'\n", name); 309141cc406Sopenharmony_ci 310141cc406Sopenharmony_ci if (strcmp (name, "dll") == 0) 311141cc406Sopenharmony_ci { 312141cc406Sopenharmony_ci DBG (0, "add_backend: remove the dll-backend from your dll.conf!\n"); 313141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 314141cc406Sopenharmony_ci } 315141cc406Sopenharmony_ci 316141cc406Sopenharmony_ci for (prev = 0, be = first_backend; be; prev = be, be = be->next) 317141cc406Sopenharmony_ci if (strcmp (be->name, name) == 0) 318141cc406Sopenharmony_ci { 319141cc406Sopenharmony_ci DBG (1, "add_backend: `%s' is already there\n", name); 320141cc406Sopenharmony_ci /* move to front so we preserve order that we'd get with 321141cc406Sopenharmony_ci dynamic loading: */ 322141cc406Sopenharmony_ci if (prev) 323141cc406Sopenharmony_ci { 324141cc406Sopenharmony_ci prev->next = be->next; 325141cc406Sopenharmony_ci be->next = first_backend; 326141cc406Sopenharmony_ci first_backend = be; 327141cc406Sopenharmony_ci } 328141cc406Sopenharmony_ci if (bep) 329141cc406Sopenharmony_ci *bep = be; 330141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 331141cc406Sopenharmony_ci } 332141cc406Sopenharmony_ci 333141cc406Sopenharmony_ci be = calloc (1, sizeof (*be)); 334141cc406Sopenharmony_ci if (!be) 335141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 336141cc406Sopenharmony_ci 337141cc406Sopenharmony_ci be->name = strdup (name); 338141cc406Sopenharmony_ci if (!be->name) 339141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 340141cc406Sopenharmony_ci be->next = first_backend; 341141cc406Sopenharmony_ci first_backend = be; 342141cc406Sopenharmony_ci if (bep) 343141cc406Sopenharmony_ci *bep = be; 344141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 345141cc406Sopenharmony_ci} 346141cc406Sopenharmony_ci 347141cc406Sopenharmony_ci#if defined(HAVE_NSLINKMODULE) 348141cc406Sopenharmony_cistatic const char *dyld_get_error_str (); 349141cc406Sopenharmony_ci 350141cc406Sopenharmony_cistatic const char * 351141cc406Sopenharmony_cidyld_get_error_str () 352141cc406Sopenharmony_ci{ 353141cc406Sopenharmony_ci NSLinkEditErrors c; 354141cc406Sopenharmony_ci int errorNumber; 355141cc406Sopenharmony_ci const char *fileName; 356141cc406Sopenharmony_ci const char *errorString; 357141cc406Sopenharmony_ci 358141cc406Sopenharmony_ci NSLinkEditError (&c, &errorNumber, &fileName, &errorString); 359141cc406Sopenharmony_ci return errorString; 360141cc406Sopenharmony_ci} 361141cc406Sopenharmony_ci#endif 362141cc406Sopenharmony_ci 363141cc406Sopenharmony_ci#if defined(HAVE_SCAN_SERVICE) 364141cc406Sopenharmony_cistatic int has_suffix(const char *filename, const char *suffix) { 365141cc406Sopenharmony_ci size_t len_filename = strlen(filename); 366141cc406Sopenharmony_ci size_t len_suffix = strlen(suffix); 367141cc406Sopenharmony_ci return len_suffix <= len_filename && strcmp(filename + len_filename - len_suffix, suffix) == 0; 368141cc406Sopenharmony_ci} 369141cc406Sopenharmony_ci 370141cc406Sopenharmony_cistatic void find_libname_by_drivername(char* libname, char* dir, char* drivername) 371141cc406Sopenharmony_ci{ 372141cc406Sopenharmony_ci DBG(1, "%s: begin", __func__); 373141cc406Sopenharmony_ci if (libname == NULL || dir == NULL || drivername == NULL) 374141cc406Sopenharmony_ci { 375141cc406Sopenharmony_ci DBG(2, "%s: input parameter is a nullptr.\n", __func__); 376141cc406Sopenharmony_ci return; 377141cc406Sopenharmony_ci } 378141cc406Sopenharmony_ci char driver[PATH_MAX] = {0}; 379141cc406Sopenharmony_ci snprintf (driver, sizeof (driver), "libsane-%s.z.so", drivername); 380141cc406Sopenharmony_ci DIR *backends_dir = opendir(dir); 381141cc406Sopenharmony_ci if (backends_dir == NULL) { 382141cc406Sopenharmony_ci DBG(2, "open dir %s error\n", backends_dir); 383141cc406Sopenharmony_ci return; 384141cc406Sopenharmony_ci } 385141cc406Sopenharmony_ci struct dirent *entry; 386141cc406Sopenharmony_ci char full_path[PATH_MAX] = {0}; 387141cc406Sopenharmony_ci while ((entry = readdir(backends_dir)) != NULL) { 388141cc406Sopenharmony_ci // ignore '.' and '..' 389141cc406Sopenharmony_ci if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { 390141cc406Sopenharmony_ci memset(full_path, 0, PATH_MAX); 391141cc406Sopenharmony_ci snprintf(full_path, PATH_MAX, "%s/" "%s", dir, entry->d_name); 392141cc406Sopenharmony_ci DBG(2, "full_path %s\n", full_path); 393141cc406Sopenharmony_ci if (has_suffix(full_path, driver)) { 394141cc406Sopenharmony_ci memset(libname, 0, PATH_MAX); 395141cc406Sopenharmony_ci strncpy(libname, full_path, PATH_MAX); 396141cc406Sopenharmony_ci break; 397141cc406Sopenharmony_ci } 398141cc406Sopenharmony_ci } 399141cc406Sopenharmony_ci } 400141cc406Sopenharmony_ci closedir(backends_dir); 401141cc406Sopenharmony_ci} 402141cc406Sopenharmony_ci#endif 403141cc406Sopenharmony_ci 404141cc406Sopenharmony_ci#ifdef __BEOS__ 405141cc406Sopenharmony_ci#include <FindDirectory.h> 406141cc406Sopenharmony_ci 407141cc406Sopenharmony_cistatic SANE_Status 408141cc406Sopenharmony_ciload (struct backend *be) 409141cc406Sopenharmony_ci{ 410141cc406Sopenharmony_ci /* use BeOS kernel function to load scanner addons from ~/config/add-ons/SANE */ 411141cc406Sopenharmony_ci char path[PATH_MAX]; 412141cc406Sopenharmony_ci image_id id = -1; 413141cc406Sopenharmony_ci int i, w; 414141cc406Sopenharmony_ci directory_which which[3] = { B_USER_ADDONS_DIRECTORY, B_COMMON_ADDONS_DIRECTORY, B_BEOS_ADDONS_DIRECTORY }; 415141cc406Sopenharmony_ci 416141cc406Sopenharmony_ci /* look for config files in SANE/conf */ 417141cc406Sopenharmony_ci for (w = 0; (w < 3) && (id < 0) && (find_directory(which[w],0,true,path,PATH_MAX) == 0); w++) 418141cc406Sopenharmony_ci { 419141cc406Sopenharmony_ci strcat(path,"/SANE/"); 420141cc406Sopenharmony_ci strcat(path,be->name); 421141cc406Sopenharmony_ci DBG(1, "loading backend %s\n", be->name); 422141cc406Sopenharmony_ci 423141cc406Sopenharmony_ci /* initialize all ops to "unsupported" so we can "use" the backend 424141cc406Sopenharmony_ci even if the stuff later in this function fails */ 425141cc406Sopenharmony_ci be->loaded = 1; 426141cc406Sopenharmony_ci be->handle = 0; 427141cc406Sopenharmony_ci for (i = 0; i < NUM_OPS; ++i) be->op[i] = op_unsupported; 428141cc406Sopenharmony_ci DBG(2, "dlopen()ing `%s'\n", path); 429141cc406Sopenharmony_ci id=load_add_on(path); 430141cc406Sopenharmony_ci if (id < 0) 431141cc406Sopenharmony_ci { 432141cc406Sopenharmony_ci continue; /* try next path */ 433141cc406Sopenharmony_ci } 434141cc406Sopenharmony_ci be->handle=(void *)id; 435141cc406Sopenharmony_ci 436141cc406Sopenharmony_ci for (i = 0; i < NUM_OPS; ++i) 437141cc406Sopenharmony_ci { 438141cc406Sopenharmony_ci void *(*op) (); 439141cc406Sopenharmony_ci op = NULL; 440141cc406Sopenharmony_ci /* Look for the symbol */ 441141cc406Sopenharmony_ci if ((get_image_symbol(id, op_name[i],B_SYMBOL_TYPE_TEXT,(void **)&op) < 0) || !op) 442141cc406Sopenharmony_ci DBG(2, "unable to find %s\n", op_name[i]); 443141cc406Sopenharmony_ci else be->op[i]=op; 444141cc406Sopenharmony_ci } 445141cc406Sopenharmony_ci } 446141cc406Sopenharmony_ci if (id < 0) 447141cc406Sopenharmony_ci { 448141cc406Sopenharmony_ci DBG(2, "load: couldn't find %s\n",path); 449141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 450141cc406Sopenharmony_ci } 451141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 452141cc406Sopenharmony_ci} 453141cc406Sopenharmony_ci 454141cc406Sopenharmony_ci#else 455141cc406Sopenharmony_cistatic SANE_Status 456141cc406Sopenharmony_ciload (struct backend *be) 457141cc406Sopenharmony_ci{ 458141cc406Sopenharmony_ci#ifdef HAVE_DLL 459141cc406Sopenharmony_ci int mode = 0; 460141cc406Sopenharmony_ci char *funcname, *src, *orig_src = 0, *dir, *path = 0; 461141cc406Sopenharmony_ci char libname[PATH_MAX]; 462141cc406Sopenharmony_ci int i; 463141cc406Sopenharmony_ci int src_len; 464141cc406Sopenharmony_ci FILE *fp = 0; 465141cc406Sopenharmony_ci 466141cc406Sopenharmony_ci#if defined(HAVE_DLOPEN) 467141cc406Sopenharmony_ci# define PREFIX "libsane-" 468141cc406Sopenharmony_ci# ifdef __hpux 469141cc406Sopenharmony_ci# define POSTFIX ".sl.%u" 470141cc406Sopenharmony_ci# define ALT_POSTFIX ".so.%u" 471141cc406Sopenharmony_ci# elif defined (HAVE_WINDOWS_H) 472141cc406Sopenharmony_ci# undef PREFIX 473141cc406Sopenharmony_ci# define PREFIX "cygsane-" 474141cc406Sopenharmony_ci# define POSTFIX "-%u.dll" 475141cc406Sopenharmony_ci# elif defined (HAVE_OS2_H) 476141cc406Sopenharmony_ci# undef PREFIX 477141cc406Sopenharmony_ci# define PREFIX "" 478141cc406Sopenharmony_ci# define POSTFIX ".dll" 479141cc406Sopenharmony_ci# elif defined (__APPLE__) && defined (__MACH__) 480141cc406Sopenharmony_ci# define POSTFIX ".%u.so" 481141cc406Sopenharmony_ci# else 482141cc406Sopenharmony_ci# define POSTFIX ".so.%u" 483141cc406Sopenharmony_ci# endif 484141cc406Sopenharmony_ci mode = getenv ("LD_BIND_NOW") ? RTLD_NOW : RTLD_LAZY; 485141cc406Sopenharmony_ci#elif defined(HAVE_SHL_LOAD) 486141cc406Sopenharmony_ci# define PREFIX "libsane-" 487141cc406Sopenharmony_ci# define POSTFIX ".sl.%u" 488141cc406Sopenharmony_ci mode = BIND_DEFERRED; 489141cc406Sopenharmony_ci#elif defined(HAVE_NSLINKMODULE) 490141cc406Sopenharmony_ci# define PREFIX "libsane-" 491141cc406Sopenharmony_ci# define POSTFIX ".%u.so" 492141cc406Sopenharmony_ci mode = NSLINKMODULE_OPTION_RETURN_ON_ERROR + NSLINKMODULE_OPTION_PRIVATE; 493141cc406Sopenharmony_ci#else 494141cc406Sopenharmony_ci# error "Tried to compile unsupported DLL." 495141cc406Sopenharmony_ci#endif /* HAVE_DLOPEN */ 496141cc406Sopenharmony_ci 497141cc406Sopenharmony_ci /* initialize all ops to "unsupported" so we can "use" the backend 498141cc406Sopenharmony_ci even if the stuff later in this function fails */ 499141cc406Sopenharmony_ci be->loaded = 1; 500141cc406Sopenharmony_ci be->handle = 0; 501141cc406Sopenharmony_ci for (i = 0; i < NUM_OPS; ++i) 502141cc406Sopenharmony_ci be->op[i] = op_unsupported; 503141cc406Sopenharmony_ci 504141cc406Sopenharmony_ci path = getenv ("LD_LIBRARY_PATH"); 505141cc406Sopenharmony_ci if (!path) 506141cc406Sopenharmony_ci path = getenv ("SHLIB_PATH"); /* for HP-UX */ 507141cc406Sopenharmony_ci if (!path) 508141cc406Sopenharmony_ci path = getenv ("LIBPATH"); /* for AIX */ 509141cc406Sopenharmony_ci 510141cc406Sopenharmony_ci if (path) 511141cc406Sopenharmony_ci { 512141cc406Sopenharmony_ci src_len = strlen (path) + strlen (DIR_SEP) + strlen(LIBDIR) + 1; 513141cc406Sopenharmony_ci src = malloc (src_len); 514141cc406Sopenharmony_ci if (!src) 515141cc406Sopenharmony_ci { 516141cc406Sopenharmony_ci DBG (1, "load: malloc failed: %s\n", strerror (errno)); 517141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 518141cc406Sopenharmony_ci } 519141cc406Sopenharmony_ci snprintf (src, src_len, "%s%s%s", path, DIR_SEP, LIBDIR); 520141cc406Sopenharmony_ci } 521141cc406Sopenharmony_ci else 522141cc406Sopenharmony_ci { 523141cc406Sopenharmony_ci src = LIBDIR; 524141cc406Sopenharmony_ci src = strdup (src); 525141cc406Sopenharmony_ci if (!src) 526141cc406Sopenharmony_ci { 527141cc406Sopenharmony_ci DBG (1, "load: strdup failed: %s\n", strerror (errno)); 528141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 529141cc406Sopenharmony_ci } 530141cc406Sopenharmony_ci } 531141cc406Sopenharmony_ci DBG (3, "load: searching backend `%s' in `%s'\n", be->name, src); 532141cc406Sopenharmony_ci 533141cc406Sopenharmony_ci orig_src = src; 534141cc406Sopenharmony_ci dir = strsep (&src, DIR_SEP); 535141cc406Sopenharmony_ci 536141cc406Sopenharmony_ci while (dir) 537141cc406Sopenharmony_ci { 538141cc406Sopenharmony_ci#ifdef HAVE_OS2_H /* only max 7.3 names work with dlopen() for DLLs on OS/2 */ 539141cc406Sopenharmony_ci snprintf (libname, sizeof (libname), "%s/" PREFIX "%.2s%.5s" POSTFIX, 540141cc406Sopenharmony_ci dir, be->name, strlen(be->name)>7 ? (be->name)+strlen(be->name)-5 : 541141cc406Sopenharmony_ci (be->name)+2, V_MAJOR); 542141cc406Sopenharmony_ci#elif defined (HAVE_SCAN_SERVICE) 543141cc406Sopenharmony_ci find_libname_by_drivername(libname, dir, be->name); 544141cc406Sopenharmony_ci#else 545141cc406Sopenharmony_ci snprintf (libname, sizeof (libname), "%s/" PREFIX "%s" POSTFIX, 546141cc406Sopenharmony_ci dir, be->name, V_MAJOR); 547141cc406Sopenharmony_ci#endif 548141cc406Sopenharmony_ci DBG (4, "load: trying to load `%s'\n", libname); 549141cc406Sopenharmony_ci fp = fopen (libname, "r"); 550141cc406Sopenharmony_ci if (fp) 551141cc406Sopenharmony_ci break; 552141cc406Sopenharmony_ci DBG (4, "load: couldn't open `%s' (%s)\n", libname, strerror (errno)); 553141cc406Sopenharmony_ci 554141cc406Sopenharmony_ci#ifdef ALT_POSTFIX 555141cc406Sopenharmony_ci /* Some platforms have two ways of storing their libraries, try both 556141cc406Sopenharmony_ci postfixes */ 557141cc406Sopenharmony_ci snprintf (libname, sizeof (libname), "%s/" PREFIX "%s" ALT_POSTFIX, 558141cc406Sopenharmony_ci dir, be->name, V_MAJOR); 559141cc406Sopenharmony_ci DBG (4, "load: trying to load `%s'\n", libname); 560141cc406Sopenharmony_ci fp = fopen (libname, "r"); 561141cc406Sopenharmony_ci if (fp) 562141cc406Sopenharmony_ci break; 563141cc406Sopenharmony_ci DBG (4, "load: couldn't open `%s' (%s)\n", libname, strerror (errno)); 564141cc406Sopenharmony_ci#endif 565141cc406Sopenharmony_ci 566141cc406Sopenharmony_ci dir = strsep (&src, DIR_SEP); 567141cc406Sopenharmony_ci } 568141cc406Sopenharmony_ci if (orig_src) 569141cc406Sopenharmony_ci free (orig_src); 570141cc406Sopenharmony_ci if (!fp) 571141cc406Sopenharmony_ci { 572141cc406Sopenharmony_ci DBG (1, "load: couldn't find backend `%s' (%s)\n", 573141cc406Sopenharmony_ci be->name, strerror (errno)); 574141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 575141cc406Sopenharmony_ci } 576141cc406Sopenharmony_ci fclose (fp); 577141cc406Sopenharmony_ci DBG (3, "load: dlopen()ing `%s'\n", libname); 578141cc406Sopenharmony_ci 579141cc406Sopenharmony_ci#ifdef HAVE_DLOPEN 580141cc406Sopenharmony_ci be->handle = dlopen (libname, mode); 581141cc406Sopenharmony_ci#elif defined(HAVE_SHL_LOAD) 582141cc406Sopenharmony_ci be->handle = (shl_t) shl_load (libname, mode, 0L); 583141cc406Sopenharmony_ci#elif defined(HAVE_NSLINKMODULE) 584141cc406Sopenharmony_ci { 585141cc406Sopenharmony_ci NSObjectFileImage objectfile_img = NULL; 586141cc406Sopenharmony_ci if (NSCreateObjectFileImageFromFile (libname, &objectfile_img) 587141cc406Sopenharmony_ci == NSObjectFileImageSuccess) 588141cc406Sopenharmony_ci { 589141cc406Sopenharmony_ci be->handle = NSLinkModule (objectfile_img, libname, mode); 590141cc406Sopenharmony_ci NSDestroyObjectFileImage (objectfile_img); 591141cc406Sopenharmony_ci } 592141cc406Sopenharmony_ci } 593141cc406Sopenharmony_ci#else 594141cc406Sopenharmony_ci# error "Tried to compile unsupported DLL." 595141cc406Sopenharmony_ci#endif /* HAVE_DLOPEN */ 596141cc406Sopenharmony_ci if (!be->handle) 597141cc406Sopenharmony_ci { 598141cc406Sopenharmony_ci#ifdef HAVE_DLOPEN 599141cc406Sopenharmony_ci DBG (1, "load: dlopen() failed (%s)\n", dlerror ()); 600141cc406Sopenharmony_ci#elif defined(HAVE_NSLINKMODULE) 601141cc406Sopenharmony_ci DBG (1, "load: dyld error (%s)\n", dyld_get_error_str ()); 602141cc406Sopenharmony_ci#else 603141cc406Sopenharmony_ci DBG (1, "load: dlopen() failed (%s)\n", strerror (errno)); 604141cc406Sopenharmony_ci#endif 605141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 606141cc406Sopenharmony_ci } 607141cc406Sopenharmony_ci 608141cc406Sopenharmony_ci /* all is dandy---lookup and fill in backend ops: */ 609141cc406Sopenharmony_ci funcname = alloca (strlen (be->name) + 64); 610141cc406Sopenharmony_ci for (i = 0; i < NUM_OPS; ++i) 611141cc406Sopenharmony_ci { 612141cc406Sopenharmony_ci void *(*op) (void); 613141cc406Sopenharmony_ci 614141cc406Sopenharmony_ci sprintf (funcname, "_sane_%s_%s", be->name, op_name[i]); 615141cc406Sopenharmony_ci 616141cc406Sopenharmony_ci /* First try looking up the symbol without a leading underscore. */ 617141cc406Sopenharmony_ci#ifdef HAVE_DLOPEN 618141cc406Sopenharmony_ci op = posix_dlsym (be->handle, funcname + 1); 619141cc406Sopenharmony_ci#elif defined(HAVE_SHL_LOAD) 620141cc406Sopenharmony_ci shl_findsym ((shl_t *) & (be->handle), funcname + 1, TYPE_UNDEFINED, 621141cc406Sopenharmony_ci &op); 622141cc406Sopenharmony_ci#elif defined(HAVE_NSLINKMODULE) 623141cc406Sopenharmony_ci { 624141cc406Sopenharmony_ci NSSymbol *nssym = NSLookupSymbolInModule (be->handle, funcname); 625141cc406Sopenharmony_ci if (!nssym) 626141cc406Sopenharmony_ci { 627141cc406Sopenharmony_ci DBG (15, "dyld error: %s\n", dyld_get_error_str ()); 628141cc406Sopenharmony_ci } 629141cc406Sopenharmony_ci else 630141cc406Sopenharmony_ci { 631141cc406Sopenharmony_ci op = (void *(*)(void)) NSAddressOfSymbol (nssym); 632141cc406Sopenharmony_ci } 633141cc406Sopenharmony_ci } 634141cc406Sopenharmony_ci#else 635141cc406Sopenharmony_ci# error "Tried to compile unsupported DLL." 636141cc406Sopenharmony_ci#endif /* HAVE_DLOPEN */ 637141cc406Sopenharmony_ci if (op) 638141cc406Sopenharmony_ci be->op[i] = op; 639141cc406Sopenharmony_ci else 640141cc406Sopenharmony_ci { 641141cc406Sopenharmony_ci /* Try again, with an underscore prepended. */ 642141cc406Sopenharmony_ci#ifdef HAVE_DLOPEN 643141cc406Sopenharmony_ci op = posix_dlsym (be->handle, funcname); 644141cc406Sopenharmony_ci#elif defined(HAVE_SHL_LOAD) 645141cc406Sopenharmony_ci shl_findsym (be->handle, funcname, TYPE_UNDEFINED, &op); 646141cc406Sopenharmony_ci#elif defined(HAVE_NSLINKMODULE) 647141cc406Sopenharmony_ci { 648141cc406Sopenharmony_ci NSSymbol *nssym = NSLookupSymbolInModule (be->handle, funcname); 649141cc406Sopenharmony_ci if (!nssym) 650141cc406Sopenharmony_ci { 651141cc406Sopenharmony_ci DBG (15, "dyld error: %s\n", dyld_get_error_str ()); 652141cc406Sopenharmony_ci } 653141cc406Sopenharmony_ci else 654141cc406Sopenharmony_ci { 655141cc406Sopenharmony_ci op = (void *(*)(void)) NSAddressOfSymbol (nssym); 656141cc406Sopenharmony_ci } 657141cc406Sopenharmony_ci } 658141cc406Sopenharmony_ci#else 659141cc406Sopenharmony_ci# error "Tried to compile unsupported DLL." 660141cc406Sopenharmony_ci#endif /* HAVE_DLOPEN */ 661141cc406Sopenharmony_ci if (op) 662141cc406Sopenharmony_ci be->op[i] = op; 663141cc406Sopenharmony_ci } 664141cc406Sopenharmony_ci if (NULL == op) 665141cc406Sopenharmony_ci DBG (1, "load: unable to find %s\n", funcname); 666141cc406Sopenharmony_ci } 667141cc406Sopenharmony_ci 668141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 669141cc406Sopenharmony_ci 670141cc406Sopenharmony_ci# undef PREFIX 671141cc406Sopenharmony_ci# undef POSTFIX 672141cc406Sopenharmony_ci#else /* HAVE_DLL */ 673141cc406Sopenharmony_ci DBG (1, 674141cc406Sopenharmony_ci "load: ignoring attempt to load `%s'; compiled without dl support\n", 675141cc406Sopenharmony_ci be->name); 676141cc406Sopenharmony_ci return SANE_STATUS_UNSUPPORTED; 677141cc406Sopenharmony_ci#endif /* HAVE_DLL */ 678141cc406Sopenharmony_ci} 679141cc406Sopenharmony_ci#endif /* __BEOS__ */ 680141cc406Sopenharmony_ci 681141cc406Sopenharmony_cistatic SANE_Status 682141cc406Sopenharmony_ciinit (struct backend *be) 683141cc406Sopenharmony_ci{ 684141cc406Sopenharmony_ci SANE_Status status; 685141cc406Sopenharmony_ci SANE_Int version; 686141cc406Sopenharmony_ci 687141cc406Sopenharmony_ci if (!be->loaded) 688141cc406Sopenharmony_ci { 689141cc406Sopenharmony_ci status = load (be); 690141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 691141cc406Sopenharmony_ci return status; 692141cc406Sopenharmony_ci } 693141cc406Sopenharmony_ci 694141cc406Sopenharmony_ci DBG (3, "init: initializing backend `%s'\n", be->name); 695141cc406Sopenharmony_ci 696141cc406Sopenharmony_ci status = (*(op_init_t)be->op[OP_INIT]) (&version, auth_callback); 697141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 698141cc406Sopenharmony_ci return status; 699141cc406Sopenharmony_ci 700141cc406Sopenharmony_ci if (SANE_VERSION_MAJOR (version) != SANE_CURRENT_MAJOR) 701141cc406Sopenharmony_ci { 702141cc406Sopenharmony_ci DBG (1, 703141cc406Sopenharmony_ci "init: backend `%s' has a wrong major version (%d instead of %d)\n", 704141cc406Sopenharmony_ci be->name, SANE_VERSION_MAJOR (version), SANE_CURRENT_MAJOR); 705141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 706141cc406Sopenharmony_ci } 707141cc406Sopenharmony_ci DBG (4, "init: backend `%s' is version %d.%d.%d\n", be->name, 708141cc406Sopenharmony_ci SANE_VERSION_MAJOR (version), SANE_VERSION_MINOR (version), 709141cc406Sopenharmony_ci SANE_VERSION_BUILD (version)); 710141cc406Sopenharmony_ci 711141cc406Sopenharmony_ci be->inited = 1; 712141cc406Sopenharmony_ci 713141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 714141cc406Sopenharmony_ci} 715141cc406Sopenharmony_ci 716141cc406Sopenharmony_ci 717141cc406Sopenharmony_cistatic void 718141cc406Sopenharmony_ciadd_alias (const char *line_param) 719141cc406Sopenharmony_ci{ 720141cc406Sopenharmony_ci#ifndef __BEOS__ 721141cc406Sopenharmony_ci const char *command; 722141cc406Sopenharmony_ci enum 723141cc406Sopenharmony_ci { CMD_ALIAS, CMD_HIDE } 724141cc406Sopenharmony_ci cmd; 725141cc406Sopenharmony_ci const char *oldname, *oldend, *newname; 726141cc406Sopenharmony_ci size_t oldlen, newlen; 727141cc406Sopenharmony_ci struct alias *alias; 728141cc406Sopenharmony_ci char *line; 729141cc406Sopenharmony_ci 730141cc406Sopenharmony_ci command = sanei_config_skip_whitespace (line_param); 731141cc406Sopenharmony_ci if (!*command) 732141cc406Sopenharmony_ci return; 733141cc406Sopenharmony_ci 734141cc406Sopenharmony_ci line = strchr (command, '#'); 735141cc406Sopenharmony_ci if (line) 736141cc406Sopenharmony_ci *line = '\0'; 737141cc406Sopenharmony_ci 738141cc406Sopenharmony_ci line = strpbrk (command, " \t"); 739141cc406Sopenharmony_ci if (!line) 740141cc406Sopenharmony_ci return; 741141cc406Sopenharmony_ci *line++ = '\0'; 742141cc406Sopenharmony_ci 743141cc406Sopenharmony_ci if (strcmp (command, "alias") == 0) 744141cc406Sopenharmony_ci cmd = CMD_ALIAS; 745141cc406Sopenharmony_ci else if (strcmp (command, "hide") == 0) 746141cc406Sopenharmony_ci cmd = CMD_HIDE; 747141cc406Sopenharmony_ci else 748141cc406Sopenharmony_ci return; 749141cc406Sopenharmony_ci 750141cc406Sopenharmony_ci newlen = 0; 751141cc406Sopenharmony_ci newname = NULL; 752141cc406Sopenharmony_ci if (cmd == CMD_ALIAS) 753141cc406Sopenharmony_ci { 754141cc406Sopenharmony_ci char *newend; 755141cc406Sopenharmony_ci 756141cc406Sopenharmony_ci newname = sanei_config_skip_whitespace (line); 757141cc406Sopenharmony_ci if (!*newname) 758141cc406Sopenharmony_ci return; 759141cc406Sopenharmony_ci if (*newname == '\"') 760141cc406Sopenharmony_ci { 761141cc406Sopenharmony_ci ++newname; 762141cc406Sopenharmony_ci newend = strchr (newname, '\"'); 763141cc406Sopenharmony_ci } 764141cc406Sopenharmony_ci else 765141cc406Sopenharmony_ci newend = strpbrk (newname, " \t"); 766141cc406Sopenharmony_ci if (!newend) 767141cc406Sopenharmony_ci return; 768141cc406Sopenharmony_ci 769141cc406Sopenharmony_ci newlen = newend - newname; 770141cc406Sopenharmony_ci line = (char *) (newend + 1); 771141cc406Sopenharmony_ci } 772141cc406Sopenharmony_ci 773141cc406Sopenharmony_ci oldname = sanei_config_skip_whitespace (line); 774141cc406Sopenharmony_ci if (!*oldname) 775141cc406Sopenharmony_ci return; 776141cc406Sopenharmony_ci oldend = oldname + strcspn (oldname, " \t"); 777141cc406Sopenharmony_ci 778141cc406Sopenharmony_ci oldlen = oldend - oldname; 779141cc406Sopenharmony_ci 780141cc406Sopenharmony_ci alias = malloc (sizeof (struct alias)); 781141cc406Sopenharmony_ci if (alias) 782141cc406Sopenharmony_ci { 783141cc406Sopenharmony_ci alias->oldname = malloc (oldlen + newlen + 2); 784141cc406Sopenharmony_ci if (alias->oldname) 785141cc406Sopenharmony_ci { 786141cc406Sopenharmony_ci strncpy (alias->oldname, oldname, oldlen); 787141cc406Sopenharmony_ci alias->oldname[oldlen] = '\0'; 788141cc406Sopenharmony_ci if (cmd == CMD_ALIAS) 789141cc406Sopenharmony_ci { 790141cc406Sopenharmony_ci alias->newname = alias->oldname + oldlen + 1; 791141cc406Sopenharmony_ci strncpy (alias->newname, newname, newlen); 792141cc406Sopenharmony_ci alias->newname[newlen] = '\0'; 793141cc406Sopenharmony_ci } 794141cc406Sopenharmony_ci else 795141cc406Sopenharmony_ci alias->newname = NULL; 796141cc406Sopenharmony_ci 797141cc406Sopenharmony_ci alias->next = first_alias; 798141cc406Sopenharmony_ci first_alias = alias; 799141cc406Sopenharmony_ci return; 800141cc406Sopenharmony_ci } 801141cc406Sopenharmony_ci free (alias); 802141cc406Sopenharmony_ci } 803141cc406Sopenharmony_ci return; 804141cc406Sopenharmony_ci#endif 805141cc406Sopenharmony_ci} 806141cc406Sopenharmony_ci 807141cc406Sopenharmony_ci 808141cc406Sopenharmony_cistatic void 809141cc406Sopenharmony_ciread_config (const char *conffile) 810141cc406Sopenharmony_ci{ 811141cc406Sopenharmony_ci FILE *fp; 812141cc406Sopenharmony_ci char config_line[PATH_MAX]; 813141cc406Sopenharmony_ci char *backend_name; 814141cc406Sopenharmony_ci 815141cc406Sopenharmony_ci fp = sanei_config_open (conffile); 816141cc406Sopenharmony_ci if (!fp) 817141cc406Sopenharmony_ci { 818141cc406Sopenharmony_ci DBG (1, "sane_init/read_config: Couldn't open config file (%s): %s\n", 819141cc406Sopenharmony_ci conffile, strerror (errno)); 820141cc406Sopenharmony_ci return; /* don't insist on config file */ 821141cc406Sopenharmony_ci } 822141cc406Sopenharmony_ci 823141cc406Sopenharmony_ci DBG (5, "sane_init/read_config: reading %s\n", conffile); 824141cc406Sopenharmony_ci while (sanei_config_read (config_line, sizeof (config_line), fp)) 825141cc406Sopenharmony_ci { 826141cc406Sopenharmony_ci char *comment; 827141cc406Sopenharmony_ci SANE_String_Const cp; 828141cc406Sopenharmony_ci 829141cc406Sopenharmony_ci cp = sanei_config_get_string (config_line, &backend_name); 830141cc406Sopenharmony_ci /* ignore empty lines */ 831141cc406Sopenharmony_ci if (!backend_name || cp == config_line) 832141cc406Sopenharmony_ci { 833141cc406Sopenharmony_ci if (backend_name) 834141cc406Sopenharmony_ci free (backend_name); 835141cc406Sopenharmony_ci continue; 836141cc406Sopenharmony_ci } 837141cc406Sopenharmony_ci /* ignore line comments */ 838141cc406Sopenharmony_ci if (backend_name[0] == '#') 839141cc406Sopenharmony_ci { 840141cc406Sopenharmony_ci free (backend_name); 841141cc406Sopenharmony_ci continue; 842141cc406Sopenharmony_ci } 843141cc406Sopenharmony_ci /* ignore comments after backend names */ 844141cc406Sopenharmony_ci comment = strchr (backend_name, '#'); 845141cc406Sopenharmony_ci if (comment) 846141cc406Sopenharmony_ci *comment = '\0'; 847141cc406Sopenharmony_ci add_backend (backend_name, 0); 848141cc406Sopenharmony_ci free (backend_name); 849141cc406Sopenharmony_ci } 850141cc406Sopenharmony_ci fclose (fp); 851141cc406Sopenharmony_ci} 852141cc406Sopenharmony_ci 853141cc406Sopenharmony_cistatic void 854141cc406Sopenharmony_ciread_dlld (void) 855141cc406Sopenharmony_ci{ 856141cc406Sopenharmony_ci DIR *dlld; 857141cc406Sopenharmony_ci struct dirent *dllconf; 858141cc406Sopenharmony_ci struct stat st; 859141cc406Sopenharmony_ci char dlldir[PATH_MAX]; 860141cc406Sopenharmony_ci char conffile[PATH_MAX + strlen("/") + NAME_MAX]; 861141cc406Sopenharmony_ci size_t len, plen; 862141cc406Sopenharmony_ci const char *dir_list; 863141cc406Sopenharmony_ci char *copy, *next, *dir; 864141cc406Sopenharmony_ci 865141cc406Sopenharmony_ci dir_list = sanei_config_get_paths (); 866141cc406Sopenharmony_ci if (!dir_list) 867141cc406Sopenharmony_ci { 868141cc406Sopenharmony_ci DBG(2, "sane_init/read_dlld: Unable to detect configuration directories\n"); 869141cc406Sopenharmony_ci return; 870141cc406Sopenharmony_ci } 871141cc406Sopenharmony_ci 872141cc406Sopenharmony_ci copy = strdup (dir_list); 873141cc406Sopenharmony_ci 874141cc406Sopenharmony_ci for (next = copy; (dir = strsep (&next, DIR_SEP)) != NULL;) 875141cc406Sopenharmony_ci { 876141cc406Sopenharmony_ci snprintf (dlldir, sizeof (dlldir), "%s%s", dir, "/dll.d"); 877141cc406Sopenharmony_ci 878141cc406Sopenharmony_ci DBG(4, "sane_init/read_dlld: attempting to open directory `%s'\n", dlldir); 879141cc406Sopenharmony_ci 880141cc406Sopenharmony_ci dlld = opendir (dlldir); 881141cc406Sopenharmony_ci if (dlld) 882141cc406Sopenharmony_ci { 883141cc406Sopenharmony_ci /* length of path to parent dir of dll.d/ */ 884141cc406Sopenharmony_ci plen = strlen (dir) + 1; 885141cc406Sopenharmony_ci 886141cc406Sopenharmony_ci DBG(3, "sane_init/read_dlld: using config directory `%s'\n", dlldir); 887141cc406Sopenharmony_ci break; 888141cc406Sopenharmony_ci } 889141cc406Sopenharmony_ci } 890141cc406Sopenharmony_ci free (copy); 891141cc406Sopenharmony_ci 892141cc406Sopenharmony_ci if (dlld == NULL) 893141cc406Sopenharmony_ci { 894141cc406Sopenharmony_ci DBG (1, "sane_init/read_dlld: opendir failed: %s\n", 895141cc406Sopenharmony_ci strerror (errno)); 896141cc406Sopenharmony_ci return; 897141cc406Sopenharmony_ci } 898141cc406Sopenharmony_ci 899141cc406Sopenharmony_ci while ((dllconf = readdir (dlld)) != NULL) 900141cc406Sopenharmony_ci { 901141cc406Sopenharmony_ci /* dotfile (or directory) */ 902141cc406Sopenharmony_ci if (dllconf->d_name[0] == '.') 903141cc406Sopenharmony_ci continue; 904141cc406Sopenharmony_ci 905141cc406Sopenharmony_ci len = strlen (dllconf->d_name); 906141cc406Sopenharmony_ci 907141cc406Sopenharmony_ci /* backup files */ 908141cc406Sopenharmony_ci if ((dllconf->d_name[len-1] == '~') 909141cc406Sopenharmony_ci || (dllconf->d_name[len-1] == '#')) 910141cc406Sopenharmony_ci continue; 911141cc406Sopenharmony_ci 912141cc406Sopenharmony_ci snprintf (conffile, sizeof(conffile), "%s/%s", dlldir, dllconf->d_name); 913141cc406Sopenharmony_ci 914141cc406Sopenharmony_ci DBG (5, "sane_init/read_dlld: considering %s\n", conffile); 915141cc406Sopenharmony_ci 916141cc406Sopenharmony_ci if (stat (conffile, &st) != 0) 917141cc406Sopenharmony_ci continue; 918141cc406Sopenharmony_ci 919141cc406Sopenharmony_ci if (!S_ISREG (st.st_mode)) 920141cc406Sopenharmony_ci continue; 921141cc406Sopenharmony_ci 922141cc406Sopenharmony_ci /* expects a path relative to PATH_SANE_CONFIG_DIR */ 923141cc406Sopenharmony_ci read_config (conffile+plen); 924141cc406Sopenharmony_ci } 925141cc406Sopenharmony_ci 926141cc406Sopenharmony_ci closedir (dlld); 927141cc406Sopenharmony_ci 928141cc406Sopenharmony_ci DBG (5, "sane_init/read_dlld: done.\n"); 929141cc406Sopenharmony_ci} 930141cc406Sopenharmony_ci 931141cc406Sopenharmony_ciSANE_Status 932141cc406Sopenharmony_cisane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) 933141cc406Sopenharmony_ci{ 934141cc406Sopenharmony_ci#ifndef __BEOS__ 935141cc406Sopenharmony_ci char config_line[PATH_MAX]; 936141cc406Sopenharmony_ci size_t len; 937141cc406Sopenharmony_ci FILE *fp; 938141cc406Sopenharmony_ci int i; 939141cc406Sopenharmony_ci#else 940141cc406Sopenharmony_ci DIR *dir; 941141cc406Sopenharmony_ci struct dirent *dirent; 942141cc406Sopenharmony_ci char path[1024]; 943141cc406Sopenharmony_ci directory_which which[3] = { B_USER_ADDONS_DIRECTORY, B_COMMON_ADDONS_DIRECTORY, B_BEOS_ADDONS_DIRECTORY }; 944141cc406Sopenharmony_ci int i; 945141cc406Sopenharmony_ci#endif 946141cc406Sopenharmony_ci 947141cc406Sopenharmony_ci DBG_INIT (); 948141cc406Sopenharmony_ci 949141cc406Sopenharmony_ci auth_callback = authorize; 950141cc406Sopenharmony_ci 951141cc406Sopenharmony_ci DBG (1, "sane_init: SANE dll backend version %s from %s\n", DLL_VERSION, 952141cc406Sopenharmony_ci PACKAGE_STRING); 953141cc406Sopenharmony_ci 954141cc406Sopenharmony_ci#ifndef __BEOS__ 955141cc406Sopenharmony_ci /* chain preloaded backends together: */ 956141cc406Sopenharmony_ci for (i = 0; i < NELEMS (preloaded_backends); ++i) 957141cc406Sopenharmony_ci { 958141cc406Sopenharmony_ci if (!preloaded_backends[i].name) 959141cc406Sopenharmony_ci continue; 960141cc406Sopenharmony_ci DBG (3, "sane_init: adding backend `%s' (preloaded)\n", preloaded_backends[i].name); 961141cc406Sopenharmony_ci preloaded_backends[i].next = first_backend; 962141cc406Sopenharmony_ci first_backend = &preloaded_backends[i]; 963141cc406Sopenharmony_ci } 964141cc406Sopenharmony_ci 965141cc406Sopenharmony_ci /* Return the version number of the sane-backends package to allow 966141cc406Sopenharmony_ci the frontend to print them. This is done only for net and dll, 967141cc406Sopenharmony_ci because these backends are usually called by the frontend. */ 968141cc406Sopenharmony_ci if (version_code) 969141cc406Sopenharmony_ci *version_code = SANE_VERSION_CODE (SANE_DLL_V_MAJOR, SANE_DLL_V_MINOR, 970141cc406Sopenharmony_ci SANE_DLL_V_BUILD); 971141cc406Sopenharmony_ci 972141cc406Sopenharmony_ci /* 973141cc406Sopenharmony_ci * Read dll.conf & dll.d 974141cc406Sopenharmony_ci * Read dll.d first, so that the extras backends will be tried last 975141cc406Sopenharmony_ci */ 976141cc406Sopenharmony_ci read_dlld (); 977141cc406Sopenharmony_ci read_config (DLL_CONFIG_FILE); 978141cc406Sopenharmony_ci 979141cc406Sopenharmony_ci fp = sanei_config_open (DLL_ALIASES_FILE); 980141cc406Sopenharmony_ci if (!fp) 981141cc406Sopenharmony_ci return SANE_STATUS_GOOD; /* don't insist on aliases file */ 982141cc406Sopenharmony_ci 983141cc406Sopenharmony_ci DBG (5, "sane_init: reading %s\n", DLL_ALIASES_FILE); 984141cc406Sopenharmony_ci while (sanei_config_read (config_line, sizeof (config_line), fp)) 985141cc406Sopenharmony_ci { 986141cc406Sopenharmony_ci if (config_line[0] == '#') /* ignore line comments */ 987141cc406Sopenharmony_ci continue; 988141cc406Sopenharmony_ci 989141cc406Sopenharmony_ci len = strlen (config_line); 990141cc406Sopenharmony_ci if (!len) 991141cc406Sopenharmony_ci continue; /* ignore empty lines */ 992141cc406Sopenharmony_ci 993141cc406Sopenharmony_ci add_alias (config_line); 994141cc406Sopenharmony_ci } 995141cc406Sopenharmony_ci fclose (fp); 996141cc406Sopenharmony_ci 997141cc406Sopenharmony_ci#else 998141cc406Sopenharmony_ci /* no ugly config files, just get scanners from their ~/config/add-ons/SANE */ 999141cc406Sopenharmony_ci /* look for drivers */ 1000141cc406Sopenharmony_ci for (i = 0; i < 3; i++) 1001141cc406Sopenharmony_ci { 1002141cc406Sopenharmony_ci if (find_directory(which[i],0,true,path,1024) < B_OK) 1003141cc406Sopenharmony_ci continue; 1004141cc406Sopenharmony_ci strcat(path,"/SANE/"); 1005141cc406Sopenharmony_ci dir=opendir(path); 1006141cc406Sopenharmony_ci if(!dir) continue; 1007141cc406Sopenharmony_ci 1008141cc406Sopenharmony_ci while((dirent=readdir(dir))) 1009141cc406Sopenharmony_ci { 1010141cc406Sopenharmony_ci if((strcmp(dirent->d_name,".")==0) || (strcmp(dirent->d_name,"..")==0)) continue; 1011141cc406Sopenharmony_ci if((strcmp(dirent->d_name,"dll")==0)) continue; 1012141cc406Sopenharmony_ci add_backend(dirent->d_name,0); 1013141cc406Sopenharmony_ci } 1014141cc406Sopenharmony_ci closedir(dir); 1015141cc406Sopenharmony_ci } 1016141cc406Sopenharmony_ci#endif /* __BEOS__ */ 1017141cc406Sopenharmony_ci 1018141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1019141cc406Sopenharmony_ci} 1020141cc406Sopenharmony_ci 1021141cc406Sopenharmony_civoid 1022141cc406Sopenharmony_cisane_exit (void) 1023141cc406Sopenharmony_ci{ 1024141cc406Sopenharmony_ci struct backend *be, *next; 1025141cc406Sopenharmony_ci struct alias *alias; 1026141cc406Sopenharmony_ci 1027141cc406Sopenharmony_ci DBG (2, "sane_exit: exiting\n"); 1028141cc406Sopenharmony_ci 1029141cc406Sopenharmony_ci for (be = first_backend; be; be = next) 1030141cc406Sopenharmony_ci { 1031141cc406Sopenharmony_ci next = be->next; 1032141cc406Sopenharmony_ci if (be->loaded) 1033141cc406Sopenharmony_ci { 1034141cc406Sopenharmony_ci if (be->inited) 1035141cc406Sopenharmony_ci { 1036141cc406Sopenharmony_ci DBG (3, "sane_exit: calling backend `%s's exit function\n", 1037141cc406Sopenharmony_ci be->name); 1038141cc406Sopenharmony_ci (*(op_exit_t)be->op[OP_EXIT]) (); 1039141cc406Sopenharmony_ci } 1040141cc406Sopenharmony_ci#ifdef __BEOS__ 1041141cc406Sopenharmony_ci /* use BeOS kernel functions to unload add-ons */ 1042141cc406Sopenharmony_ci if(be->handle) unload_add_on((image_id)be->handle); 1043141cc406Sopenharmony_ci#else 1044141cc406Sopenharmony_ci#ifdef HAVE_DLL 1045141cc406Sopenharmony_ci 1046141cc406Sopenharmony_ci#ifdef HAVE_DLOPEN 1047141cc406Sopenharmony_ci if (be->handle) 1048141cc406Sopenharmony_ci dlclose (be->handle); 1049141cc406Sopenharmony_ci#elif defined(HAVE_SHL_LOAD) 1050141cc406Sopenharmony_ci if (be->handle) 1051141cc406Sopenharmony_ci shl_unload (be->handle); 1052141cc406Sopenharmony_ci#elif defined(HAVE_NSLINKMODULE) 1053141cc406Sopenharmony_ci if (be->handle) 1054141cc406Sopenharmony_ci NSUnLinkModule (be->handle, NSUNLINKMODULE_OPTION_NONE 1055141cc406Sopenharmony_ci# ifdef __ppc__ 1056141cc406Sopenharmony_ci | NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES 1057141cc406Sopenharmony_ci# endif 1058141cc406Sopenharmony_ci ); 1059141cc406Sopenharmony_ci#else 1060141cc406Sopenharmony_ci# error "Tried to compile unsupported DLL." 1061141cc406Sopenharmony_ci#endif /* HAVE_DLOPEN */ 1062141cc406Sopenharmony_ci 1063141cc406Sopenharmony_ci#endif /* HAVE_DLL */ 1064141cc406Sopenharmony_ci#endif /* __BEOS__ */ 1065141cc406Sopenharmony_ci } 1066141cc406Sopenharmony_ci if (!be->permanent) 1067141cc406Sopenharmony_ci { 1068141cc406Sopenharmony_ci if (be->name) 1069141cc406Sopenharmony_ci free ((void *) be->name); 1070141cc406Sopenharmony_ci free (be); 1071141cc406Sopenharmony_ci } 1072141cc406Sopenharmony_ci else 1073141cc406Sopenharmony_ci { 1074141cc406Sopenharmony_ci be->inited = 0; 1075141cc406Sopenharmony_ci } 1076141cc406Sopenharmony_ci } 1077141cc406Sopenharmony_ci first_backend = 0; 1078141cc406Sopenharmony_ci 1079141cc406Sopenharmony_ci while ((alias = first_alias) != NULL) 1080141cc406Sopenharmony_ci { 1081141cc406Sopenharmony_ci first_alias = first_alias->next; 1082141cc406Sopenharmony_ci free (alias->oldname); 1083141cc406Sopenharmony_ci free (alias); 1084141cc406Sopenharmony_ci } 1085141cc406Sopenharmony_ci 1086141cc406Sopenharmony_ci if (NULL != devlist) 1087141cc406Sopenharmony_ci { /* Release memory allocated by sane_get_devices(). */ 1088141cc406Sopenharmony_ci int i = 0; 1089141cc406Sopenharmony_ci while (devlist[i]) 1090141cc406Sopenharmony_ci free (devlist[i++]); 1091141cc406Sopenharmony_ci free (devlist); 1092141cc406Sopenharmony_ci 1093141cc406Sopenharmony_ci devlist = NULL; 1094141cc406Sopenharmony_ci devlist_size = 0; 1095141cc406Sopenharmony_ci devlist_len = 0; 1096141cc406Sopenharmony_ci } 1097141cc406Sopenharmony_ci DBG (3, "sane_exit: finished\n"); 1098141cc406Sopenharmony_ci} 1099141cc406Sopenharmony_ci 1100141cc406Sopenharmony_ci/* Note that a call to get_devices() implies that we'll have to load 1101141cc406Sopenharmony_ci all backends. To avoid this, you can call sane_open() directly 1102141cc406Sopenharmony_ci (assuming you know the name of the backend/device). This is 1103141cc406Sopenharmony_ci appropriate for the command-line interface of SANE, for example. 1104141cc406Sopenharmony_ci */ 1105141cc406Sopenharmony_ciSANE_Status 1106141cc406Sopenharmony_cisane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) 1107141cc406Sopenharmony_ci{ 1108141cc406Sopenharmony_ci const SANE_Device **be_list; 1109141cc406Sopenharmony_ci struct backend *be; 1110141cc406Sopenharmony_ci SANE_Status status; 1111141cc406Sopenharmony_ci char *full_name; 1112141cc406Sopenharmony_ci int i, num_devs; 1113141cc406Sopenharmony_ci size_t len; 1114141cc406Sopenharmony_ci#define ASSERT_SPACE(n) do \ 1115141cc406Sopenharmony_ci { \ 1116141cc406Sopenharmony_ci if (devlist_len + (n) > devlist_size) \ 1117141cc406Sopenharmony_ci { \ 1118141cc406Sopenharmony_ci devlist_size += (n) + 15; \ 1119141cc406Sopenharmony_ci if (devlist) \ 1120141cc406Sopenharmony_ci devlist = realloc (devlist, devlist_size * sizeof (devlist[0])); \ 1121141cc406Sopenharmony_ci else \ 1122141cc406Sopenharmony_ci devlist = malloc (devlist_size * sizeof (devlist[0])); \ 1123141cc406Sopenharmony_ci if (!devlist) \ 1124141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; \ 1125141cc406Sopenharmony_ci } \ 1126141cc406Sopenharmony_ci } while (0) 1127141cc406Sopenharmony_ci 1128141cc406Sopenharmony_ci DBG (3, "sane_get_devices\n"); 1129141cc406Sopenharmony_ci 1130141cc406Sopenharmony_ci if (devlist) 1131141cc406Sopenharmony_ci for (i = 0; i < devlist_len; ++i) 1132141cc406Sopenharmony_ci free ((void *) devlist[i]); 1133141cc406Sopenharmony_ci devlist_len = 0; 1134141cc406Sopenharmony_ci 1135141cc406Sopenharmony_ci for (be = first_backend; be; be = be->next) 1136141cc406Sopenharmony_ci { 1137141cc406Sopenharmony_ci if (!be->inited) 1138141cc406Sopenharmony_ci if (init (be) != SANE_STATUS_GOOD) 1139141cc406Sopenharmony_ci continue; 1140141cc406Sopenharmony_ci 1141141cc406Sopenharmony_ci status = (*(op_get_devs_t)be->op[OP_GET_DEVS]) (&be_list, local_only); 1142141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD || !be_list) 1143141cc406Sopenharmony_ci continue; 1144141cc406Sopenharmony_ci 1145141cc406Sopenharmony_ci /* count the number of devices for this backend: */ 1146141cc406Sopenharmony_ci for (num_devs = 0; be_list[num_devs]; ++num_devs); 1147141cc406Sopenharmony_ci 1148141cc406Sopenharmony_ci ASSERT_SPACE (num_devs); 1149141cc406Sopenharmony_ci 1150141cc406Sopenharmony_ci for (i = 0; i < num_devs; ++i) 1151141cc406Sopenharmony_ci { 1152141cc406Sopenharmony_ci SANE_Device *dev; 1153141cc406Sopenharmony_ci char *mem; 1154141cc406Sopenharmony_ci struct alias *alias; 1155141cc406Sopenharmony_ci 1156141cc406Sopenharmony_ci for (alias = first_alias; alias != NULL; alias = alias->next) 1157141cc406Sopenharmony_ci { 1158141cc406Sopenharmony_ci len = strlen (be->name); 1159141cc406Sopenharmony_ci if (strlen (alias->oldname) <= len) 1160141cc406Sopenharmony_ci continue; 1161141cc406Sopenharmony_ci if (strncmp (alias->oldname, be->name, len) == 0 1162141cc406Sopenharmony_ci && alias->oldname[len] == ':' 1163141cc406Sopenharmony_ci && strcmp (&alias->oldname[len + 1], be_list[i]->name) == 0) 1164141cc406Sopenharmony_ci break; 1165141cc406Sopenharmony_ci } 1166141cc406Sopenharmony_ci 1167141cc406Sopenharmony_ci if (alias) 1168141cc406Sopenharmony_ci { 1169141cc406Sopenharmony_ci if (!alias->newname) /* hidden device */ 1170141cc406Sopenharmony_ci continue; 1171141cc406Sopenharmony_ci 1172141cc406Sopenharmony_ci len = strlen (alias->newname); 1173141cc406Sopenharmony_ci mem = malloc (sizeof (*dev) + len + 1); 1174141cc406Sopenharmony_ci if (!mem) 1175141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1176141cc406Sopenharmony_ci 1177141cc406Sopenharmony_ci full_name = mem + sizeof (*dev); 1178141cc406Sopenharmony_ci strcpy (full_name, alias->newname); 1179141cc406Sopenharmony_ci } 1180141cc406Sopenharmony_ci else 1181141cc406Sopenharmony_ci { 1182141cc406Sopenharmony_ci /* create a new device entry with a device name that is the 1183141cc406Sopenharmony_ci sum of the backend name a colon and the backend's device 1184141cc406Sopenharmony_ci name: */ 1185141cc406Sopenharmony_ci len = strlen (be->name) + 1 + strlen (be_list[i]->name); 1186141cc406Sopenharmony_ci mem = malloc (sizeof (*dev) + len + 1); 1187141cc406Sopenharmony_ci if (!mem) 1188141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1189141cc406Sopenharmony_ci 1190141cc406Sopenharmony_ci full_name = mem + sizeof (*dev); 1191141cc406Sopenharmony_ci strcpy (full_name, be->name); 1192141cc406Sopenharmony_ci strcat (full_name, ":"); 1193141cc406Sopenharmony_ci strcat (full_name, be_list[i]->name); 1194141cc406Sopenharmony_ci } 1195141cc406Sopenharmony_ci 1196141cc406Sopenharmony_ci dev = (SANE_Device *) mem; 1197141cc406Sopenharmony_ci dev->name = full_name; 1198141cc406Sopenharmony_ci dev->vendor = be_list[i]->vendor; 1199141cc406Sopenharmony_ci dev->model = be_list[i]->model; 1200141cc406Sopenharmony_ci dev->type = be_list[i]->type; 1201141cc406Sopenharmony_ci 1202141cc406Sopenharmony_ci devlist[devlist_len++] = dev; 1203141cc406Sopenharmony_ci } 1204141cc406Sopenharmony_ci } 1205141cc406Sopenharmony_ci 1206141cc406Sopenharmony_ci /* terminate device list with NULL entry: */ 1207141cc406Sopenharmony_ci ASSERT_SPACE (1); 1208141cc406Sopenharmony_ci devlist[devlist_len++] = 0; 1209141cc406Sopenharmony_ci 1210141cc406Sopenharmony_ci *device_list = (const SANE_Device **) devlist; 1211141cc406Sopenharmony_ci DBG (3, "sane_get_devices: found %d devices\n", devlist_len - 1); 1212141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1213141cc406Sopenharmony_ci} 1214141cc406Sopenharmony_ci 1215141cc406Sopenharmony_ciSANE_Status 1216141cc406Sopenharmony_cisane_open (SANE_String_Const full_name, SANE_Handle * meta_handle) 1217141cc406Sopenharmony_ci{ 1218141cc406Sopenharmony_ci char *be_name; 1219141cc406Sopenharmony_ci const char *dev_name; 1220141cc406Sopenharmony_ci struct meta_scanner *s; 1221141cc406Sopenharmony_ci SANE_Handle handle; 1222141cc406Sopenharmony_ci struct backend *be; 1223141cc406Sopenharmony_ci SANE_Status status; 1224141cc406Sopenharmony_ci struct alias *alias; 1225141cc406Sopenharmony_ci 1226141cc406Sopenharmony_ci DBG (3, "sane_open: trying to open `%s'\n", full_name); 1227141cc406Sopenharmony_ci 1228141cc406Sopenharmony_ci for (alias = first_alias; alias != NULL; alias = alias->next) 1229141cc406Sopenharmony_ci { 1230141cc406Sopenharmony_ci if (!alias->newname) 1231141cc406Sopenharmony_ci continue; 1232141cc406Sopenharmony_ci if (strcmp (alias->newname, full_name) == 0) 1233141cc406Sopenharmony_ci { 1234141cc406Sopenharmony_ci full_name = alias->oldname; 1235141cc406Sopenharmony_ci break; 1236141cc406Sopenharmony_ci } 1237141cc406Sopenharmony_ci } 1238141cc406Sopenharmony_ci 1239141cc406Sopenharmony_ci dev_name = strchr (full_name, ':'); 1240141cc406Sopenharmony_ci 1241141cc406Sopenharmony_ci int is_fakeusb = 0, is_fakeusbdev = 0, is_fakeusbout = 0; 1242141cc406Sopenharmony_ci 1243141cc406Sopenharmony_ci if (dev_name) 1244141cc406Sopenharmony_ci { 1245141cc406Sopenharmony_ci is_fakeusb = strncmp(full_name, "fakeusb", dev_name - full_name) == 0 && 1246141cc406Sopenharmony_ci dev_name - full_name == 7; 1247141cc406Sopenharmony_ci is_fakeusbdev = strncmp(full_name, "fakeusbdev", dev_name - full_name) == 0 && 1248141cc406Sopenharmony_ci dev_name - full_name == 10; 1249141cc406Sopenharmony_ci is_fakeusbout = strncmp(full_name, "fakeusbout", dev_name - full_name) == 0 && 1250141cc406Sopenharmony_ci dev_name - full_name == 10; 1251141cc406Sopenharmony_ci } 1252141cc406Sopenharmony_ci 1253141cc406Sopenharmony_ci if (is_fakeusb || is_fakeusbdev) 1254141cc406Sopenharmony_ci { 1255141cc406Sopenharmony_ci ++dev_name; // skip colon 1256141cc406Sopenharmony_ci status = sanei_usb_testing_enable_replay(dev_name, is_fakeusbdev); 1257141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1258141cc406Sopenharmony_ci return status; 1259141cc406Sopenharmony_ci 1260141cc406Sopenharmony_ci be_name = sanei_usb_testing_get_backend(); 1261141cc406Sopenharmony_ci if (be_name == NULL) 1262141cc406Sopenharmony_ci { 1263141cc406Sopenharmony_ci DBG (0, "%s: unknown backend for testing\n", __func__); 1264141cc406Sopenharmony_ci return SANE_STATUS_ACCESS_DENIED; 1265141cc406Sopenharmony_ci } 1266141cc406Sopenharmony_ci } 1267141cc406Sopenharmony_ci else 1268141cc406Sopenharmony_ci { 1269141cc406Sopenharmony_ci char* fakeusbout_path = NULL; 1270141cc406Sopenharmony_ci if (is_fakeusbout) 1271141cc406Sopenharmony_ci { 1272141cc406Sopenharmony_ci ++dev_name; // skip colon 1273141cc406Sopenharmony_ci 1274141cc406Sopenharmony_ci const char* path_end = strchr(dev_name, ':'); 1275141cc406Sopenharmony_ci if (path_end == NULL) 1276141cc406Sopenharmony_ci { 1277141cc406Sopenharmony_ci DBG (0, "%s: the device name does not contain path\n", __func__); 1278141cc406Sopenharmony_ci return SANE_STATUS_INVAL; 1279141cc406Sopenharmony_ci } 1280141cc406Sopenharmony_ci fakeusbout_path = strndup(dev_name, path_end - dev_name); 1281141cc406Sopenharmony_ci 1282141cc406Sopenharmony_ci full_name = path_end + 1; // skip colon 1283141cc406Sopenharmony_ci dev_name = strchr(full_name, ':'); 1284141cc406Sopenharmony_ci } 1285141cc406Sopenharmony_ci 1286141cc406Sopenharmony_ci if (dev_name) 1287141cc406Sopenharmony_ci { 1288141cc406Sopenharmony_ci be_name = strndup(full_name, dev_name - full_name); 1289141cc406Sopenharmony_ci ++dev_name; /* skip colon */ 1290141cc406Sopenharmony_ci } 1291141cc406Sopenharmony_ci else 1292141cc406Sopenharmony_ci { 1293141cc406Sopenharmony_ci /* if no colon interpret full_name as the backend name; an empty 1294141cc406Sopenharmony_ci backend device name will cause us to open the first device of 1295141cc406Sopenharmony_ci that backend. */ 1296141cc406Sopenharmony_ci be_name = strdup(full_name); 1297141cc406Sopenharmony_ci dev_name = ""; 1298141cc406Sopenharmony_ci } 1299141cc406Sopenharmony_ci 1300141cc406Sopenharmony_ci if (is_fakeusbout) 1301141cc406Sopenharmony_ci { 1302141cc406Sopenharmony_ci status = sanei_usb_testing_enable_record(fakeusbout_path, be_name); 1303141cc406Sopenharmony_ci free(fakeusbout_path); 1304141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1305141cc406Sopenharmony_ci return status; 1306141cc406Sopenharmony_ci } 1307141cc406Sopenharmony_ci } 1308141cc406Sopenharmony_ci 1309141cc406Sopenharmony_ci if (!be_name) 1310141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1311141cc406Sopenharmony_ci 1312141cc406Sopenharmony_ci if (!be_name[0]) 1313141cc406Sopenharmony_ci be = first_backend; 1314141cc406Sopenharmony_ci else 1315141cc406Sopenharmony_ci for (be = first_backend; be; be = be->next) 1316141cc406Sopenharmony_ci if (strcmp (be->name, be_name) == 0) 1317141cc406Sopenharmony_ci break; 1318141cc406Sopenharmony_ci 1319141cc406Sopenharmony_ci if (!be) 1320141cc406Sopenharmony_ci { 1321141cc406Sopenharmony_ci status = add_backend (be_name, &be); 1322141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1323141cc406Sopenharmony_ci { 1324141cc406Sopenharmony_ci free(be_name); 1325141cc406Sopenharmony_ci return status; 1326141cc406Sopenharmony_ci } 1327141cc406Sopenharmony_ci } 1328141cc406Sopenharmony_ci free(be_name); 1329141cc406Sopenharmony_ci 1330141cc406Sopenharmony_ci if (!be->inited) 1331141cc406Sopenharmony_ci { 1332141cc406Sopenharmony_ci status = init (be); 1333141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1334141cc406Sopenharmony_ci return status; 1335141cc406Sopenharmony_ci } 1336141cc406Sopenharmony_ci 1337141cc406Sopenharmony_ci status = (*(op_open_t)be->op[OP_OPEN]) (dev_name, &handle); 1338141cc406Sopenharmony_ci if (status != SANE_STATUS_GOOD) 1339141cc406Sopenharmony_ci return status; 1340141cc406Sopenharmony_ci 1341141cc406Sopenharmony_ci s = calloc (1, sizeof (*s)); 1342141cc406Sopenharmony_ci if (!s) 1343141cc406Sopenharmony_ci return SANE_STATUS_NO_MEM; 1344141cc406Sopenharmony_ci 1345141cc406Sopenharmony_ci s->be = be; 1346141cc406Sopenharmony_ci s->handle = handle; 1347141cc406Sopenharmony_ci *meta_handle = s; 1348141cc406Sopenharmony_ci 1349141cc406Sopenharmony_ci DBG (3, "sane_open: open successful\n"); 1350141cc406Sopenharmony_ci return SANE_STATUS_GOOD; 1351141cc406Sopenharmony_ci} 1352141cc406Sopenharmony_ci 1353141cc406Sopenharmony_civoid 1354141cc406Sopenharmony_cisane_close (SANE_Handle handle) 1355141cc406Sopenharmony_ci{ 1356141cc406Sopenharmony_ci struct meta_scanner *s = handle; 1357141cc406Sopenharmony_ci 1358141cc406Sopenharmony_ci DBG (3, "sane_close(handle=%p)\n", handle); 1359141cc406Sopenharmony_ci (*(op_close_t)s->be->op[OP_CLOSE]) (s->handle); 1360141cc406Sopenharmony_ci free (s); 1361141cc406Sopenharmony_ci} 1362141cc406Sopenharmony_ci 1363141cc406Sopenharmony_ciconst SANE_Option_Descriptor * 1364141cc406Sopenharmony_cisane_get_option_descriptor (SANE_Handle handle, SANE_Int option) 1365141cc406Sopenharmony_ci{ 1366141cc406Sopenharmony_ci struct meta_scanner *s = handle; 1367141cc406Sopenharmony_ci 1368141cc406Sopenharmony_ci DBG (3, "sane_get_option_descriptor(handle=%p,option=%d)\n", handle, 1369141cc406Sopenharmony_ci option); 1370141cc406Sopenharmony_ci return (*(op_get_option_desc_t)s->be->op[OP_GET_OPTION_DESC]) (s->handle, option); 1371141cc406Sopenharmony_ci} 1372141cc406Sopenharmony_ci 1373141cc406Sopenharmony_ciSANE_Status 1374141cc406Sopenharmony_cisane_control_option (SANE_Handle handle, SANE_Int option, 1375141cc406Sopenharmony_ci SANE_Action action, void *value, SANE_Word * info) 1376141cc406Sopenharmony_ci{ 1377141cc406Sopenharmony_ci struct meta_scanner *s = handle; 1378141cc406Sopenharmony_ci 1379141cc406Sopenharmony_ci DBG (3, 1380141cc406Sopenharmony_ci "sane_control_option(handle=%p,option=%d,action=%d,value=%p,info=%p)\n", 1381141cc406Sopenharmony_ci handle, option, action, value, (void *) info); 1382141cc406Sopenharmony_ci return (*(op_ctl_option_t)s->be->op[OP_CTL_OPTION]) (s->handle, option, action, value, 1383141cc406Sopenharmony_ci info); 1384141cc406Sopenharmony_ci} 1385141cc406Sopenharmony_ci 1386141cc406Sopenharmony_ciSANE_Status 1387141cc406Sopenharmony_cisane_get_parameters (SANE_Handle handle, SANE_Parameters * params) 1388141cc406Sopenharmony_ci{ 1389141cc406Sopenharmony_ci struct meta_scanner *s = handle; 1390141cc406Sopenharmony_ci 1391141cc406Sopenharmony_ci DBG (3, "sane_get_parameters(handle=%p,params=%p)\n", handle, (void *) params); 1392141cc406Sopenharmony_ci return (*(op_get_params_t)s->be->op[OP_GET_PARAMS]) (s->handle, params); 1393141cc406Sopenharmony_ci} 1394141cc406Sopenharmony_ci 1395141cc406Sopenharmony_ciSANE_Status 1396141cc406Sopenharmony_cisane_start (SANE_Handle handle) 1397141cc406Sopenharmony_ci{ 1398141cc406Sopenharmony_ci struct meta_scanner *s = handle; 1399141cc406Sopenharmony_ci 1400141cc406Sopenharmony_ci DBG (3, "sane_start(handle=%p)\n", handle); 1401141cc406Sopenharmony_ci return (*(op_start_t)s->be->op[OP_START]) (s->handle); 1402141cc406Sopenharmony_ci} 1403141cc406Sopenharmony_ci 1404141cc406Sopenharmony_ciSANE_Status 1405141cc406Sopenharmony_cisane_read (SANE_Handle handle, SANE_Byte * data, SANE_Int max_length, 1406141cc406Sopenharmony_ci SANE_Int * length) 1407141cc406Sopenharmony_ci{ 1408141cc406Sopenharmony_ci struct meta_scanner *s = handle; 1409141cc406Sopenharmony_ci 1410141cc406Sopenharmony_ci DBG (3, "sane_read(handle=%p,data=%p,maxlen=%d,lenp=%p)\n", 1411141cc406Sopenharmony_ci handle, (void *) data, max_length, (void *) length); 1412141cc406Sopenharmony_ci return (*(op_read_t)s->be->op[OP_READ]) (s->handle, data, max_length, length); 1413141cc406Sopenharmony_ci} 1414141cc406Sopenharmony_ci 1415141cc406Sopenharmony_civoid 1416141cc406Sopenharmony_cisane_cancel (SANE_Handle handle) 1417141cc406Sopenharmony_ci{ 1418141cc406Sopenharmony_ci struct meta_scanner *s = handle; 1419141cc406Sopenharmony_ci 1420141cc406Sopenharmony_ci DBG (3, "sane_cancel(handle=%p)\n", handle); 1421141cc406Sopenharmony_ci (*(op_cancel_t)s->be->op[OP_CANCEL]) (s->handle); 1422141cc406Sopenharmony_ci} 1423141cc406Sopenharmony_ci 1424141cc406Sopenharmony_ciSANE_Status 1425141cc406Sopenharmony_cisane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) 1426141cc406Sopenharmony_ci{ 1427141cc406Sopenharmony_ci struct meta_scanner *s = handle; 1428141cc406Sopenharmony_ci 1429141cc406Sopenharmony_ci DBG (3, "sane_set_io_mode(handle=%p,nonblocking=%d)\n", handle, 1430141cc406Sopenharmony_ci non_blocking); 1431141cc406Sopenharmony_ci return (*(op_set_io_mode_t)s->be->op[OP_SET_IO_MODE]) (s->handle, non_blocking); 1432141cc406Sopenharmony_ci} 1433141cc406Sopenharmony_ci 1434141cc406Sopenharmony_ciSANE_Status 1435141cc406Sopenharmony_cisane_get_select_fd (SANE_Handle handle, SANE_Int * fd) 1436141cc406Sopenharmony_ci{ 1437141cc406Sopenharmony_ci struct meta_scanner *s = handle; 1438141cc406Sopenharmony_ci 1439141cc406Sopenharmony_ci DBG (3, "sane_get_select_fd(handle=%p,fdp=%p)\n", handle, (void *) fd); 1440141cc406Sopenharmony_ci return (*(op_get_select_fd_t)s->be->op[OP_GET_SELECT_FD]) (s->handle, fd); 1441141cc406Sopenharmony_ci} 1442