• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* sane - Scanner Access Now Easy.
2    Copyright (C) 2005 Gerhard Jaeger
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 
40 #include "../include/sane/config.h"
41 
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <errno.h>
46 #include <signal.h>
47 #include <limits.h>
48 #ifdef HAVE_UNISTD_H
49 # include <unistd.h>
50 #endif
51 #include <fcntl.h>
52 
53 #define BACKEND_NAME sanei_access     /**< name of this module for debugging */
54 
55 #include "../include/sane/sane.h"
56 #include "../include/sane/sanei_debug.h"
57 #include "../include/sane/sanei_access.h"
58 
59 #ifndef PATH_MAX
60 # define PATH_MAX	1024
61 #endif
62 
63 #if defined(_WIN32) || defined(HAVE_OS2_H)
64 # define PATH_SEP	'\\'
65 #else
66 # define PATH_SEP	'/'
67 #endif
68 
69 #define REPLACEMENT_CHAR '_'
70 
71 #define PID_BUFSIZE  50
72 
73 #define PROCESS_SELF  0
74 #define PROCESS_DEAD -1
75 #define PROCESS_OTHER 1
76 
77 
78 #ifdef ENABLE_LOCKING
79 /** get the status/owner of a lock file
80  *
81  * The function tries to open an existing lockfile. On success, it reads out
82  * the pid which is stored inside and tries to find out more about the status
83  * of the process with the corresponding PID.
84  *
85  * @param fn - the complete filename of the lockfile to check
86  * @return
87  * - PROCESS_SELF  - the calling process is owner of the lockfile
88  * - PROCESS_DEAD  - the process who created the lockfile is already dead
89  * - PROCESS_OTHER - the process who created the lockfile is still alive
90  */
91 static int
get_lock_status(char * fn)92 get_lock_status( char *fn )
93 {
94 	char  pid_buf[PID_BUFSIZE];
95 	int   fd, status;
96 	pid_t pid;
97 
98 	fd = open( fn, O_RDONLY );
99 	if( fd < 0 ) {
100 		DBG( 2, "does_process_exist: open >%s< failed: %s\n",
101 		        fn, strerror(errno));
102 		return PROCESS_OTHER;
103 	}
104 	read( fd, pid_buf, (PID_BUFSIZE-1));
105 	pid_buf[PID_BUFSIZE-1] = '\0';
106 	close( fd );
107 
108 	pid_buf[24] = '\0';
109 	pid = strtol( pid_buf, NULL, 10 );
110 	DBG( 2, "does_process_exist: PID %i\n", pid );
111 
112 	status = kill( pid, 0 );
113 	if( status == -1 ) {
114 		if( errno == ESRCH ) {
115 			DBG( 2, "does_process_exist: process %i does not exist!\n", pid );
116 			return PROCESS_DEAD;
117 		}
118 		DBG( 1, "does_process_exist: kill failed: %s\n", strerror(errno));
119 	} else {
120 		DBG( 2, "does_process_exist: process %i does exist!\n", pid );
121 		if( pid == getpid()){
122 			DBG( 2, "does_process_exist: it's me!!!\n" );
123 			return PROCESS_SELF;
124 		}
125 	}
126 	return PROCESS_OTHER;
127 }
128 
129 static void
create_lock_filename(char * fn,const char * devname)130 create_lock_filename( char *fn, const char *devname )
131 {
132 	char *p;
133 
134 	strcpy( fn, STRINGIFY(PATH_SANE_LOCK_DIR)"/LCK.." );
135 	p = &fn[strlen(fn)];
136 
137 	strcat( fn, devname );
138 
139 	while( *p != '\0' ) {
140 		if( *p == PATH_SEP )
141 			*p = REPLACEMENT_CHAR;
142 		p++;
143 	}
144 	DBG( 2, "sanei_access: lockfile name >%s<\n", fn );
145 }
146 #endif
147 
148 void
sanei_access_init(const char * backend)149 sanei_access_init( const char *backend )
150 {
151 	DBG_INIT();
152 
153 	DBG( 2, "sanei_access_init: >%s<\n", backend);
154 }
155 
156 SANE_Status
sanei_access_lock(const char * devicename,SANE_Word timeout)157 sanei_access_lock( const char *devicename, SANE_Word timeout )
158 {
159 #ifdef ENABLE_LOCKING
160 	char fn[PATH_MAX];
161 	char pid_buf[PID_BUFSIZE];
162 	int  fd, to, i;
163 #endif
164 
165 	DBG( 2, "sanei_access_lock: devname >%s<, timeout: %u\n",
166 	        devicename, timeout );
167 #ifndef ENABLE_LOCKING
168 	return SANE_STATUS_GOOD;
169 #else
170 	to = timeout;
171 	if (to <= 0)
172 		to = 1;
173 
174 	create_lock_filename( fn, devicename );
175 
176 	for (i = 0; i < to; i++) {
177 
178 		fd = open( fn, O_CREAT | O_EXCL | O_WRONLY, 0644 );
179 		if (fd < 0) {
180 
181 			if (errno == EEXIST) {
182 				switch( get_lock_status( fn )) {
183 				case PROCESS_DEAD:
184 					DBG( 2, "sanei_access_lock: "
185 					        "deleting old lock file, retrying...\n" );
186 					unlink( fn );
187 					continue;
188 					break;
189 				case PROCESS_SELF:
190 					DBG( 2, "sanei_access_lock: success\n" );
191 					return SANE_STATUS_GOOD;
192 					break;
193 				default:
194 					break;
195 				}
196 				DBG( 2, "sanei_access_lock: lock exists, waiting...\n" );
197 				sleep(1);
198 			} else {
199 				DBG( 1, "sanei_access_lock: open >%s< failed: %s\n",
200 				        fn, strerror(errno));
201 				return SANE_STATUS_ACCESS_DENIED;
202 			}
203 		} else {
204 			DBG( 2, "sanei_access_lock: success\n" );
205 			sprintf( pid_buf, "% 11i sane\n", getpid());
206 			write(fd, pid_buf, strlen(pid_buf));
207 			close( fd );
208 			return SANE_STATUS_GOOD;
209 		}
210 	}
211 	DBG( 1, "sanei_access_lock: timeout!\n");
212 	return SANE_STATUS_ACCESS_DENIED;
213 #endif
214 }
215 
216 SANE_Status
sanei_access_unlock(const char * devicename)217 sanei_access_unlock( const char *devicename )
218 {
219 #ifdef ENABLE_LOCKING
220 	char fn[PATH_MAX];
221 #endif
222 	DBG( 2, "sanei_access_unlock: devname >%s<\n", devicename );
223 #ifdef ENABLE_LOCKING
224 	create_lock_filename( fn, devicename );
225 	unlink( fn );
226 #endif
227 	return SANE_STATUS_GOOD;
228 }
229 
230 /* END sanei_access.c .......................................................*/
231