From d498239305667fc644818e81e93b805f1b02fdf6 Mon Sep 17 00:00:00 2001 From: Gerhard Jaeger Date: Fri, 1 Apr 2005 14:04:19 +0000 Subject: [PATCH] Initial checkin. --- include/sane/sanei_access.h | 97 +++++++++++++++++ sanei/sanei_access.c | 209 ++++++++++++++++++++++++++++++++++++ 2 files changed, 306 insertions(+) create mode 100644 include/sane/sanei_access.h create mode 100644 sanei/sanei_access.c diff --git a/include/sane/sanei_access.h b/include/sane/sanei_access.h new file mode 100644 index 000000000..e383be376 --- /dev/null +++ b/include/sane/sanei_access.h @@ -0,0 +1,97 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2005 Gerhard Jaeger + + This file is part of the SANE package. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. + +*/ + +/** @file sanei_access.h + * Interface file for the sanei_access functions. + * + * The idea is to provide some simple locking/unlocking mecanism, which + * can be used to protect device access from more than one frontend + * simultaneously. + */ + +#ifndef sanei_access_h +#define sanei_access_h + +#include "../include/sane/config.h" +#include "../include/sane/sane.h" + +/** Initialize sanei_access. + * + * This function must be called before any other sanei_access function. + * + * @param backend - backend name, who uses this lib + */ +extern void sanei_access_init( const char * backend ); + +/** Set a lock. + * + * The function tries to open/create exclusively a lock file in + * $PATH_SANE_LOCK_DIR/lock/sane. + * If the file could be created successfully, the function fills in the + * process ID. + * The complete filename of the lockfile is created as follows: + * $PATH_SANE_LOCK_DIR/lock/LCK.. + * If the lock could not be set, the function tries it until the timeout + * period has been elapsed. + * + * @param devicename - unique part of the lockfile name + * @param timeout - time in seconds to try to set a lock + * @return + * - SANE_STATUS_GOOD - if the lock has been successfully set + * - SANE_STATUS_ACCESS_DENIED - the lock could not set + */ +extern SANE_Status sanei_access_lock( const char * devicename, SANE_Word timeout ); + +/** Unlock a previously set lock. + * + * The function tries to unlock a previously created lock. The lockfile will be + * closed and removed. + * + * @param devicename - part of the lockfile name, use for sanei_acess_lock() + * @return + * - SANE_STATUS_GOOD - currently the one and only return value + */ +extern SANE_Status sanei_access_unlock( const char * devicename ); + +#endif /* sanei_access_h */ diff --git a/sanei/sanei_access.c b/sanei/sanei_access.c new file mode 100644 index 000000000..0a3e5600c --- /dev/null +++ b/sanei/sanei_access.c @@ -0,0 +1,209 @@ +/* sane - Scanner Access Now Easy. + Copyright (C) 2005 Gerhard Jaeger + This file is part of the SANE package. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + As a special exception, the authors of SANE give permission for + additional uses of the libraries contained in this release of SANE. + + The exception is that, if you link a SANE library with other files + to produce an executable, this does not by itself cause the + resulting executable to be covered by the GNU General Public + License. Your use of that executable is in no way restricted on + account of linking the SANE library code into it. + + This exception does not, however, invalidate any other reasons why + the executable file might be covered by the GNU General Public + License. + + If you submit changes to SANE to the maintainers to be included in + a subsequent release, you agree by submitting the changes that + those changes may be distributed with this exception intact. + + If you write modifications of your own for SANE, it is your choice + whether to permit this exception to apply to your modifications. + If you do not wish that, delete this exception notice. +*/ + +#include "../include/sane/config.h" + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#include + +#define BACKEND_NAME sanei_access /**< name of this module for debugging */ + +#include "../include/sane/sane.h" +#include "../include/sane/sanei_debug.h" +#include "../include/sane/sanei_access.h" + +#define PID_BUFSIZE 50 + +#define PROCESS_SELF 0 +#define PROCESS_DEAD -1 +#define PROCESS_OTHER 1 + + +#ifdef ENABLE_LOCKING +/** get the status/owner of a lock file + * + * The function tries to open an existing lockfile. On success, it reads out + * the pid which is stored inside and tries to find out more about the status + * of the process with the corresponding PID. + * + * @param fn - the complete filename of the lockfile to check + * @return + * - PROCESS_SELF - the calling process is owner of the lockfile + * - PROCESS_DEAD - the process who created the lockfile is already dead + * - PROCESS_OTHER - the process who created the lockfile is still alive + */ +static int +get_lock_status( char *fn ) +{ + char pid_buf[PID_BUFSIZE]; + int fd, status; + pid_t pid; + + fd = open( fn, O_RDONLY ); + if( fd < 0 ) { + DBG( 2, "does_process_exist: open >%s< failed: %s\n", + fn, strerror(errno)); + return PROCESS_OTHER; + } + read( fd, pid_buf, (PID_BUFSIZE-1)); + pid_buf[PID_BUFSIZE-1] = '\0'; + close( fd ); + + pid_buf[24] = '\0'; + pid = strtol( pid_buf, NULL, 10 ); + DBG( 2, "does_process_exist: PID %i\n", pid ); + + status = kill( pid, 0 ); + if( status == -1 ) { + if( errno == ESRCH ) { + DBG( 2, "does_process_exist: process %i does not exist!\n", pid ); + return PROCESS_DEAD; + } + DBG( 1, "does_process_exist: kill failed: %s\n", strerror(errno)); + } else { + DBG( 2, "does_process_exist: process %i does exist!\n", pid ); + if( pid == getpid()){ + DBG( 2, "does_process_exist: it's me!!!\n" ); + return PROCESS_SELF; + } + } + return PROCESS_OTHER; +} + +static void +create_lock_filename( char *fn, const char *devname ) +{ + strcpy( fn, STRINGIFY(PATH_SANE_LOCK_DIR)"/lock/sane/LCK.." ); + strcat( fn, devname ); +} +#endif + +void +sanei_access_init( const char *backend ) +{ + DBG_INIT(); + + DBG( 2, "sanei_access_init: >%s<\n", backend); +} + +SANE_Status +sanei_access_lock( const char *devicename, SANE_Word timeout ) +{ +#ifdef ENABLE_LOCKING + char fn[PATH_MAX]; + char pid_buf[PID_BUFSIZE]; + int fd, to, i; +#endif + + DBG( 2, "sanei_access_lock: devname >%s<, timeout: %u\n", + devicename, timeout ); +#ifndef ENABLE_LOCKING + return SANE_STATUS_GOOD; +#else + to = timeout; + if (to <= 0) + to = 1; + + create_lock_filename( fn, devicename ); + + for (i = 0; i < to; i++) { + + fd = open( fn, O_CREAT | O_EXCL | O_WRONLY, 0644 ); + if (fd < 0) { + + if (errno == EEXIST) { + switch( get_lock_status( fn )) { + case PROCESS_DEAD: + DBG( 2, "sanei_access_lock: " + "deleting old lock file, retrying...\n" ); + unlink( fn ); + continue; + break; + case PROCESS_SELF: + DBG( 2, "sanei_access_lock: success\n" ); + return SANE_STATUS_GOOD; + break; + default: + break; + } + DBG( 2, "sanei_access_lock: lock exists, waiting...\n" ); + sleep(1); + } else { + DBG( 1, "sanei_access_lock: open >%s< failed: %s\n", + fn, strerror(errno)); + return SANE_STATUS_ACCESS_DENIED; + } + } else { + DBG( 2, "sanei_access_lock: success\n" ); + sprintf( pid_buf, "% 11i sane\n", getpid()); + write(fd, pid_buf, strlen(pid_buf)); + close( fd ); + return SANE_STATUS_GOOD; + } + } + DBG( 1, "sanei_access_lock: timeout!\n"); + return SANE_STATUS_ACCESS_DENIED; +#endif +} + +SANE_Status +sanei_access_unlock( const char *devicename ) +{ +#ifdef ENABLE_LOCKING + char fn[PATH_MAX]; +#endif + DBG( 2, "sanei_access_unlock: devname >%s<\n", devicename ); +#ifdef ENABLE_LOCKING + create_lock_filename( fn, devicename ); + unlink( fn ); +#endif + return SANE_STATUS_GOOD; +} + +/* END sanei_access.c .......................................................*/