1 /* Copyright (C) 2007-2008 The Android Open Source Project 2 ** 3 ** This software is licensed under the terms of the GNU General Public 4 ** License version 2, as published by the Free Software Foundation, and 5 ** may be copied, distributed, and modified under those terms. 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 13 #include "android/utils/eintr_wrapper.h" 14 #include "android/utils/filelock.h" 15 #include "android/utils/path.h" 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <errno.h> 19 #include <sys/stat.h> 20 #include <time.h> 21 #include <fcntl.h> 22 #ifdef _WIN32 23 # include <process.h> 24 # include <windows.h> 25 # include <tlhelp32.h> 26 #else 27 # include <sys/types.h> 28 # include <unistd.h> 29 # include <signal.h> 30 #endif 31 32 // Set to 1 to enable debug traces here. 33 #if 0 34 #define D(...) printf(__VA_ARGS__), printf("\n"), fflush(stdout) 35 #else 36 #define D(...) ((void)0) 37 #endif 38 39 /** FILE LOCKS SUPPORT 40 ** 41 ** A FileLock is useful to prevent several emulator instances from using 42 ** the same writable file (e.g. the userdata.img disk images). 43 ** 44 ** Create a FileLock object with filelock_create(), this function should 45 ** return NULL only if the corresponding file path could not be locked. 46 ** 47 ** All file locks are automatically released and destroyed when the program 48 ** exits. The filelock_lock() function can also detect stale file locks 49 ** that can linger when the emulator crashes unexpectedly, and will happily 50 ** clean them for you 51 ** 52 ** Here's how it works, three files are used: 53 ** file - the data file accessed by the emulator 54 ** lock - a lock file (file + '.lock') 55 ** temp - a temporary file made unique with mkstemp 56 ** 57 ** When locking: 58 ** create 'temp' and store our pid in it 59 ** attemp to link 'lock' to 'temp' 60 ** if the link succeeds, we obtain the lock 61 ** unlink 'temp' 62 ** 63 ** When unlocking: 64 ** unlink 'lock' 65 ** 66 ** 67 ** On Windows, 'lock' is a directory name. locking is equivalent to 68 ** creating it. The directory will contain a file named 'pid' that 69 ** contains the locking process' PID. 70 ** 71 **/ 72 73 struct FileLock 74 { 75 const char* file; 76 const char* lock; 77 char* temp; 78 int locked; 79 FileLock* next; 80 }; 81 82 /* used to cleanup all locks at emulator exit */ 83 static FileLock* _all_filelocks; 84 85 86 #define LOCK_NAME ".lock" 87 #define TEMP_NAME ".tmp-XXXXXX" 88 89 #ifdef _WIN32 90 #define PIDFILE_NAME "pid" 91 #endif 92 93 /* returns 0 on success, -1 on failure */ 94 static int 95 filelock_lock( FileLock* lock ) 96 { 97 int ret; 98 #ifdef _WIN32 99 int pidfile_fd = -1; 100 101 ret = mkdir( lock->lock ); 102 if (ret < 0) { 103 if (errno == ENOENT) { 104 D( "could not access directory '%s', check path elements", lock->lock ); 105 return -1; 106 } else if (errno != EEXIST) { 107 D( "mkdir(%s): %s", lock->lock, strerror(errno) ); 108 return -1; 109 } 110 111 /* if we get here, it's because the .lock directory already exists */ 112 /* check to see if there is a pid file in it */ 113 D("directory '%s' already exist, waiting a bit to ensure that no other emulator instance is starting", lock->lock ); 114 { 115 int _sleep = 200; 116 int tries; 117 118 for ( tries = 4; tries > 0; tries-- ) 119 { 120 pidfile_fd = open( lock->temp, O_RDONLY ); 121 122 if (pidfile_fd >= 0) 123 break; 124 125 Sleep( _sleep ); 126 _sleep *= 2; 127 } 128 } 129 130 if (pidfile_fd < 0) { 131 D( "no pid file in '%s', assuming stale directory", lock->lock ); 132 } 133 else 134 { 135 /* read the pidfile, and check wether the corresponding process is still running */ 136 char buf[16]; 137 int len, lockpid; 138 HANDLE processSnapshot; 139 PROCESSENTRY32 pe32; 140 int is_locked = 0; 141 142 len = read( pidfile_fd, buf, sizeof(buf)-1 ); 143 if (len < 0) { 144 D( "could not read pid file '%s'", lock->temp ); 145 close( pidfile_fd ); 146 return -1; 147 } 148 buf[len] = 0; 149 lockpid = atoi(buf); 150 151 /* PID 0 is the IDLE process, and 0 is returned in case of invalid input */ 152 if (lockpid == 0) 153 lockpid = -1; 154 155 close( pidfile_fd ); 156 157 pe32.dwSize = sizeof( PROCESSENTRY32 ); 158 processSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ); 159 160 if ( processSnapshot == INVALID_HANDLE_VALUE ) { 161 D( "could not retrieve the list of currently active processes\n" ); 162 is_locked = 1; 163 } 164 else if ( !Process32First( processSnapshot, &pe32 ) ) 165 { 166 D( "could not retrieve first process id\n" ); 167 CloseHandle( processSnapshot ); 168 is_locked = 1; 169 } 170 else 171 { 172 do { 173 if (pe32.th32ProcessID == lockpid) { 174 is_locked = 1; 175 break; 176 } 177 } while (Process32Next( processSnapshot, &pe32 ) ); 178 179 CloseHandle( processSnapshot ); 180 } 181 182 if (is_locked) { 183 D( "the file '%s' is locked by process ID %d\n", lock->file, lockpid ); 184 return -1; 185 } 186 } 187 } 188 189 /* write our PID into the pid file */ 190 pidfile_fd = open( lock->temp, O_WRONLY | O_CREAT | O_TRUNC ); 191 if (pidfile_fd < 0) { 192 if (errno == EACCES) { 193 if ( path_delete_file( lock->temp ) < 0 ) { 194 D( "could not remove '%s': %s\n", lock->temp, strerror(errno) ); 195 return -1; 196 } 197 pidfile_fd = open( lock->temp, O_WRONLY | O_CREAT | O_TRUNC ); 198 } 199 if (pidfile_fd < 0) { 200 D( "could not create '%s': %s\n", lock->temp, strerror(errno) ); 201 return -1; 202 } 203 } 204 205 { 206 char buf[16]; 207 sprintf( buf, "%ld", GetCurrentProcessId() ); 208 ret = write( pidfile_fd, buf, strlen(buf) ); 209 close(pidfile_fd); 210 if (ret < 0) { 211 D( "could not write PID to '%s'\n", lock->temp ); 212 return -1; 213 } 214 } 215 216 lock->locked = 1; 217 return 0; 218 #else 219 int temp_fd = -1; 220 int lock_fd = -1; 221 int rc, tries; 222 FILE* f = NULL; 223 char pid[8]; 224 struct stat st_temp; 225 226 temp_fd = mkstemp(lock->temp); 227 228 if (temp_fd < 0) { 229 D("Cannot create locking temp file '%s'", lock->temp); 230 goto Fail; 231 } 232 233 snprintf(pid, sizeof pid, "%d", getpid()); 234 ret = HANDLE_EINTR(write(temp_fd, pid, strlen(pid) + 1)); 235 if (ret < 0) { 236 D("Cannot write to locking temp file '%s'", lock->temp); 237 goto Fail; 238 } 239 close(temp_fd); 240 temp_fd = -1; 241 242 rc = HANDLE_EINTR(lstat(lock->temp, &st_temp)); 243 if (rc < 0) { 244 D("Can't properly stat our locking temp file '%s'", lock->temp); 245 goto Fail; 246 } 247 248 /* now attempt to link the temp file to the lock file */ 249 int sleep_duration_us = 0; 250 for (tries = 4; tries > 0; tries--) 251 { 252 const int kSleepDurationUsMax = 2000000; // 2 seconds. 253 const int kSleepDurationUsIncrement = 200000; // 0.2 seconds 254 255 if (sleep_duration_us > 0) { 256 if (sleep_duration_us > kSleepDurationUsMax) { 257 D("Cannot acquire lock file '%s'", lock->lock); 258 goto Fail; 259 } 260 usleep(sleep_duration_us); 261 } 262 sleep_duration_us += kSleepDurationUsIncrement; 263 264 // The return value of link() is buggy on NFS, so ignore it. 265 // and use lstat() to look at the result. 266 rc = HANDLE_EINTR(link(lock->temp, lock->lock)); 267 268 struct stat st_lock; 269 rc = HANDLE_EINTR(lstat(lock->lock, &st_lock)); 270 if (rc != 0) { 271 // Try again after sleeping a little. 272 continue; 273 } 274 275 if (st_temp.st_rdev == st_lock.st_rdev && 276 st_temp.st_ino == st_lock.st_ino ) { 277 /* The link() operation suceeded */ 278 lock->locked = 1; 279 rc = HANDLE_EINTR(unlink(lock->temp)); 280 return 0; 281 } 282 283 if (S_ISDIR(st_lock.st_mode)) { 284 // The .lock file is a directory. This can only happen 285 // when the AVD was previously used by a Win32 emulator 286 // instance running under Wine on the same machine. 287 fprintf(stderr, 288 "Stale Win32 lock file detected: %s\n", 289 lock->lock); 290 goto Fail; 291 } 292 293 /* if we get there, it means that the link() call failed */ 294 /* check the lockfile to see if it is stale */ 295 typedef enum { 296 FRESHNESS_UNKNOWN = 0, 297 FRESHNESS_FRESH, 298 FRESHNESS_STALE, 299 } Freshness; 300 301 Freshness freshness = FRESHNESS_UNKNOWN; 302 303 struct stat st; 304 time_t now; 305 rc = HANDLE_EINTR(time(&now)); 306 st.st_mtime = now - 120; 307 308 int lockpid = 0; 309 int lockfd = HANDLE_EINTR(open(lock->lock,O_RDONLY)); 310 if (lockfd >= 0) { 311 char buf[16]; 312 int len = HANDLE_EINTR(read(lockfd, buf, sizeof(buf) - 1U)); 313 if (len < 0) { 314 len = 0; 315 } 316 buf[len] = 0; 317 lockpid = atoi(buf); 318 319 rc = HANDLE_EINTR(fstat(lockfd, &st)); 320 if (rc == 0) { 321 now = st.st_atime; 322 } 323 IGNORE_EINTR(close(lockfd)); 324 } 325 /* if there is a PID, check that it is still alive */ 326 if (lockpid > 0) { 327 rc = HANDLE_EINTR(kill(lockpid, 0)); 328 if (rc == 0 || errno == EPERM) { 329 freshness = FRESHNESS_FRESH; 330 } else if (rc < 0 && errno == ESRCH) { 331 freshness = FRESHNESS_STALE; 332 } 333 } 334 if (freshness == FRESHNESS_UNKNOWN) { 335 /* no pid, stale if the file is older than 1 minute */ 336 freshness = (now >= st.st_mtime + 60) ? 337 FRESHNESS_STALE : 338 FRESHNESS_FRESH; 339 } 340 341 if (freshness == FRESHNESS_STALE) { 342 D("Removing stale lockfile '%s'", lock->lock); 343 rc = HANDLE_EINTR(unlink(lock->lock)); 344 sleep_duration_us = 0; 345 tries++; 346 } 347 } 348 D("file '%s' is already in use by another process", lock->file); 349 350 Fail: 351 if (f) { 352 fclose(f); 353 } 354 355 if (temp_fd >= 0) { 356 IGNORE_EINTR(close(temp_fd)); 357 } 358 359 if (lock_fd >= 0) { 360 IGNORE_EINTR(close(lock_fd)); 361 } 362 363 HANDLE_EINTR(unlink(lock->lock)); 364 HANDLE_EINTR(unlink(lock->temp)); 365 return -1; 366 #endif 367 } 368 369 void 370 filelock_release( FileLock* lock ) 371 { 372 if (lock->locked) { 373 #ifdef _WIN32 374 path_delete_file( (char*)lock->temp ); 375 rmdir( (char*)lock->lock ); 376 #else 377 unlink( (char*)lock->lock ); 378 #endif 379 lock->locked = 0; 380 } 381 } 382 383 static void 384 filelock_atexit( void ) 385 { 386 FileLock* lock; 387 388 for (lock = _all_filelocks; lock != NULL; lock = lock->next) 389 filelock_release( lock ); 390 } 391 392 /* create a file lock */ 393 FileLock* 394 filelock_create( const char* file ) 395 { 396 int file_len = strlen(file); 397 int lock_len = file_len + sizeof(LOCK_NAME); 398 #ifdef _WIN32 399 int temp_len = lock_len + 1 + sizeof(PIDFILE_NAME); 400 #else 401 int temp_len = file_len + sizeof(TEMP_NAME); 402 #endif 403 int total_len = sizeof(FileLock) + file_len + lock_len + temp_len + 3; 404 405 FileLock* lock = malloc(total_len); 406 407 lock->file = (const char*)(lock + 1); 408 memcpy( (char*)lock->file, file, file_len+1 ); 409 410 lock->lock = lock->file + file_len + 1; 411 memcpy( (char*)lock->lock, file, file_len+1 ); 412 strcat( (char*)lock->lock, LOCK_NAME ); 413 414 lock->temp = (char*)lock->lock + lock_len + 1; 415 #ifdef _WIN32 416 snprintf( (char*)lock->temp, temp_len, "%s\\" PIDFILE_NAME, lock->lock ); 417 #else 418 snprintf((char*)lock->temp, temp_len, "%s%s", lock->file, TEMP_NAME); 419 #endif 420 lock->locked = 0; 421 422 if (filelock_lock(lock) < 0) { 423 free(lock); 424 return NULL; 425 } 426 427 lock->next = _all_filelocks; 428 _all_filelocks = lock; 429 430 if (lock->next == NULL) 431 atexit( filelock_atexit ); 432 433 return lock; 434 } 435