1/* 2 * This program is free software; you can redistribute it and/or 3 * modify it under the terms of the GNU General Public License as 4 * published by the Free Software Foundation; either version 2 of 5 * the License, or (at your option) any later version. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program; if not, write to the Free Software 14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 15 * MA 02111-1307 USA 16 */ 17/*************************************************************************** 18 * LPRng - An Extended Print Spooler System 19 * 20 * Copyright 1988-2003, Patrick Powell, San Diego, CA 21 * papowell@lprng.com 22 * See LICENSE for conditions of use. 23 * 24 ***************************************************************************/ 25 26 static char *const _id = 27"$Id: lockfile.c,v 1.1.1.1 2008/10/15 03:28:27 james26_jang Exp $"; 28 29/*************************************************************************** 30 * MODULE: lockfile.c 31 * lock file manipulation procedures. 32 *************************************************************************** 33 * File Locking Routines: 34 * int Do_lock( int fd, int block ); 35 * fd - file descriptor 36 * block - non-zero- block until lock 37 * Returns: 0 - success 38 * -1 - fail 39 *************************************************************************** 40 * Lock File Manipulation: 41 * Each active server has a lock file, which it uses to record its 42 * activity. The lock file is created and then locked; 43 * the deamon will place its PID and an activity in the lock file. 44 * 45 * The struct lockfile{} gives the format of this file. 46 * 47 * Programs wanting to know the server status will read the file. 48 * Note: only active servers, not status programs, will lock the file. 49 * This prevents a status program from locking out a server. 50 * The information in the lock file may be stale, as the lock program 51 * may update the file without the knowledge of the checker. 52 * However, by making the file fixed size and small, we can read/write 53 * it with a single operation, making the window of modification small. 54 ***************************************************************************/ 55 56#include "lp.h" 57#include "lockfile.h" 58#include "fileopen.h" 59/**** ENDINCLUDE ****/ 60 61#if defined(HAVE_SYS_TTYCOM_H) 62#include <sys/ttycom.h> 63#endif 64#if defined(HAVE_SYS_TTOLD_H) && !defined(IRIX) 65#include <sys/ttold.h> 66#endif 67#if defined(HAVE_SYS_IOCTL_H) 68#include <sys/ioctl.h> 69#endif 70 71 72/*************************************************************************** 73 * Do_lock( fd , int block ) 74 * does a lock on a file; 75 * if block is nonzero, block until file unlocked 76 * Returns: < 0 if lock fn failed 77 * 0 if successful 78 ***************************************************************************/ 79 80int Do_lock( int fd, int block ) 81{ 82 int code = -2; 83 84 DEBUG3("Do_lock: fd %d, block '%d'", fd, block ); 85 86#if defined(HAVE_FLOCK) 87 if( code == -2 ){ 88 int err; 89 int how; 90 91 if( block ){ 92 how = LOCK_EX; 93 } else { 94 how = LOCK_EX|LOCK_NB; 95 } 96 97 DEBUG3 ("Do_lock: using flock" ); 98 code = flock( fd, how ); 99 err = errno; 100 if( code < 0 ){ 101 DEBUG1( "Do_lock: flock failed '%s'", Errormsg( err )); 102 code = -1; 103 } else { 104 code = 0; 105 } 106 errno = err; 107 } 108#endif 109#if defined(HAVE_LOCKF) 110 if( code == -2 ){ 111 int err; 112 int how; 113 114 if( block ){ 115 how = F_LOCK; 116 } else { 117 how = F_TLOCK; 118 } 119 120 DEBUG3 ("Do_lock: using lockf" ); 121 code = lockf( fd, how, 0); 122 err = errno; 123 if( code < 0 ){ 124 DEBUG1( "Do_lock: lockf failed '%s'", Errormsg( err)); 125 code = -1; 126 } else { 127 code = 0; 128 } 129 errno = err; 130 } 131#endif 132#if defined(HAVE_FCNTL) 133 if( code == -2 ){ 134 struct flock file_lock; 135 int err; 136 int how; 137 DEBUG3 ("Do_lock: using fcntl with SEEK_SET, block %d", block ); 138 139 how = F_SETLK; 140 if( block ) how = F_SETLKW; 141 142 memset( &file_lock, 0, sizeof( file_lock ) ); 143 file_lock.l_type = F_WRLCK; 144 file_lock.l_whence = SEEK_SET; 145 code = fcntl( fd, how, &file_lock); 146 err = errno; 147 if( code < 0 ){ 148 code = -1; 149 } else { 150 code = 0; 151 } 152 DEBUG3 ("devlock_fcntl: status %d", code ); 153 errno = err; 154 } 155#endif 156 157 DEBUG3 ("Do_lock: status %d", code); 158 return( code); 159} 160 161 162 163/*************************************************************************** 164 * Do_unlock( fd ) 165 * unlocks a lock on a file; 166 * Returns: < 0 if lock fn failed 167 * 0 if successful 168 ***************************************************************************/ 169 170int Do_unlock( int fd ) 171{ 172 int code = -2; 173 174 DEBUG3("Do_unlock: fd %d", fd ); 175 176#if defined(HAVE_FLOCK) 177 if( code == -2 ){ 178 int err; 179 int how; 180 181 how = LOCK_EX|LOCK_UN; 182 DEBUG3 ("Do_unlock: using flock" ); 183 code = flock( fd, how ); 184 err = errno; 185 if( code < 0 ){ 186 DEBUG1( "Do_unlock: flock failed '%s'", Errormsg( err )); 187 code = -1; 188 } else { 189 code = 0; 190 } 191 errno = err; 192 } 193#endif 194#if defined(HAVE_LOCKF) 195 if( code == -2 ){ 196 int err; 197 int how; 198 199 how = F_ULOCK; 200 201 DEBUG3 ("Do_unlock: using lockf" ); 202 code = lockf( fd, how, 0); 203 err = errno; 204 if( code < 0 ){ 205 DEBUG1( "Do_unlock: lockf failed '%s'", Errormsg( err)); 206 code = -1; 207 } else { 208 code = 0; 209 } 210 errno = err; 211 } 212#endif 213#if defined(HAVE_FCNTL) 214 if( code == -2 ){ 215 struct flock file_lock; 216 int err; 217 int how; 218 DEBUG3 ("Do_unlock: using fcntl with SEEK_SET" ); 219 220 how = F_SETLK; 221 memset( &file_lock, 0, sizeof( file_lock ) ); 222 file_lock.l_type = F_UNLCK; 223 file_lock.l_whence = SEEK_SET; 224 code = fcntl( fd, how, &file_lock); 225 err = errno; 226 if( code < 0 ){ 227 code = -1; 228 } else { 229 code = 0; 230 } 231 DEBUG3 ("devlock_fcntl: status %d", code ); 232 errno = err; 233 } 234#endif 235 236 DEBUG3 ("Do_unlock: status %d", code); 237 return( code); 238} 239 240 241 242 243/*************************************************************************** 244 * LockDevice(fd, block) 245 * Tries to lock the device file so that two or more queues can work on 246 * the same print device. First does a non-blocking lock, if this fails, 247 * puts a nice message in the status file and blocks in a second lock. 248 * (contributed by Michael Joosten <joost@cadlab.de>) 249 * 250 * Finally, you can set locking off (:lk@:) 251 * 252 * RETURNS: >= 0 if successful, < 0 if fails 253 ***************************************************************************/ 254 255int LockDevice(int fd, int block ) 256{ 257 int lock = -1; 258 int err = errno; 259 260 DEBUG2 ("LockDevice: locking '%d'", fd ); 261 262#if defined(TIOCEXCL) && !defined(HAVE_BROKEN_TIOCEXCL) 263 DEBUG2 ("LockDevice: TIOCEXL on '%d', isatty %d", 264 fd, isatty( fd ) ); 265 if( isatty (fd) ){ 266 /* use the TIOCEXCL ioctl. See termio(4). */ 267 DEBUG2 ("LockDevice: TIOCEXL on '%d'", fd); 268 lock = ioctl( fd, TIOCEXCL, (void *) 0); 269 err = errno; 270 if( lock < 0) { 271 lock = -1; 272 LOGERR(LOG_INFO) "LockDevice: TIOCEXCL failed"); 273 } else { 274 lock = 0; 275 } 276 } 277#endif 278 if( lock < 0 ){ 279 lock = Do_lock( fd, block ); 280 } 281 282 errno = err; 283 return( lock ); 284} 285