1*10d63b7dSRichard Lowe /* 2*10d63b7dSRichard Lowe * CDDL HEADER START 3*10d63b7dSRichard Lowe * 4*10d63b7dSRichard Lowe * The contents of this file are subject to the terms of the 5*10d63b7dSRichard Lowe * Common Development and Distribution License (the "License"). 6*10d63b7dSRichard Lowe * You may not use this file except in compliance with the License. 7*10d63b7dSRichard Lowe * 8*10d63b7dSRichard Lowe * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*10d63b7dSRichard Lowe * or http://www.opensolaris.org/os/licensing. 10*10d63b7dSRichard Lowe * See the License for the specific language governing permissions 11*10d63b7dSRichard Lowe * and limitations under the License. 12*10d63b7dSRichard Lowe * 13*10d63b7dSRichard Lowe * When distributing Covered Code, include this CDDL HEADER in each 14*10d63b7dSRichard Lowe * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*10d63b7dSRichard Lowe * If applicable, add the following below this CDDL HEADER, with the 16*10d63b7dSRichard Lowe * fields enclosed by brackets "[]" replaced with your own identifying 17*10d63b7dSRichard Lowe * information: Portions Copyright [yyyy] [name of copyright owner] 18*10d63b7dSRichard Lowe * 19*10d63b7dSRichard Lowe * CDDL HEADER END 20*10d63b7dSRichard Lowe */ 21*10d63b7dSRichard Lowe /* 22*10d63b7dSRichard Lowe * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 23*10d63b7dSRichard Lowe * Use is subject to license terms. 24*10d63b7dSRichard Lowe */ 25*10d63b7dSRichard Lowe 26*10d63b7dSRichard Lowe #include <stdio.h> 27*10d63b7dSRichard Lowe #include <stdlib.h> 28*10d63b7dSRichard Lowe #include <unistd.h> 29*10d63b7dSRichard Lowe #include <string.h> 30*10d63b7dSRichard Lowe #include <fcntl.h> 31*10d63b7dSRichard Lowe #include <sys/types.h> 32*10d63b7dSRichard Lowe #include <sys/param.h> 33*10d63b7dSRichard Lowe #include <sys/stat.h> 34*10d63b7dSRichard Lowe #include <sys/errno.h> 35*10d63b7dSRichard Lowe #include <errno.h> /* errno */ 36*10d63b7dSRichard Lowe 37*10d63b7dSRichard Lowe #if defined(_LP64) 38*10d63b7dSRichard Lowe /* 39*10d63b7dSRichard Lowe * The symbols _sys_errlist and _sys_nerr are not visible in the 40*10d63b7dSRichard Lowe * LP64 libc. Use strerror(3C) instead. 41*10d63b7dSRichard Lowe */ 42*10d63b7dSRichard Lowe #else /* #_LP64 */ 43*10d63b7dSRichard Lowe extern char * sys_errlist[]; 44*10d63b7dSRichard Lowe extern int sys_nerr; 45*10d63b7dSRichard Lowe #endif /* #_LP64 */ 46*10d63b7dSRichard Lowe 47*10d63b7dSRichard Lowe static void file_lock_error(); 48*10d63b7dSRichard Lowe 49*10d63b7dSRichard Lowe /* 50*10d63b7dSRichard Lowe * This code stolen from the NSE library and changed to not depend 51*10d63b7dSRichard Lowe * upon any NSE routines or header files. 52*10d63b7dSRichard Lowe * 53*10d63b7dSRichard Lowe * Simple file locking. 54*10d63b7dSRichard Lowe * Create a symlink to a file. The "test and set" will be 55*10d63b7dSRichard Lowe * atomic as creating the symlink provides both functions. 56*10d63b7dSRichard Lowe * 57*10d63b7dSRichard Lowe * The timeout value specifies how long to wait for stale locks 58*10d63b7dSRichard Lowe * to disappear. If the lock is more than 'timeout' seconds old 59*10d63b7dSRichard Lowe * then it is ok to blow it away. This part has a small window 60*10d63b7dSRichard Lowe * of vunerability as the operations of testing the time, 61*10d63b7dSRichard Lowe * removing the lock and creating a new one are not atomic. 62*10d63b7dSRichard Lowe * It would be possible for two processes to both decide to blow 63*10d63b7dSRichard Lowe * away the lock and then have process A remove the lock and establish 64*10d63b7dSRichard Lowe * its own, and then then have process B remove the lock which accidentily 65*10d63b7dSRichard Lowe * removes A's lock rather than the stale one. 66*10d63b7dSRichard Lowe * 67*10d63b7dSRichard Lowe * A further complication is with the NFS. If the file in question is 68*10d63b7dSRichard Lowe * being served by an NFS server, then its time is set by that server. 69*10d63b7dSRichard Lowe * We can not use the time on the client machine to check for a stale 70*10d63b7dSRichard Lowe * lock. Therefore, a temp file on the server is created to get 71*10d63b7dSRichard Lowe * the servers current time. 72*10d63b7dSRichard Lowe * 73*10d63b7dSRichard Lowe * Returns an error message. NULL return means the lock was obtained. 74*10d63b7dSRichard Lowe * 75*10d63b7dSRichard Lowe */ 76*10d63b7dSRichard Lowe char * 77*10d63b7dSRichard Lowe file_lock(char * name, char * lockname, int timeout) 78*10d63b7dSRichard Lowe { 79*10d63b7dSRichard Lowe int r; 80*10d63b7dSRichard Lowe int fd; 81*10d63b7dSRichard Lowe struct stat statb; 82*10d63b7dSRichard Lowe struct stat fs_statb; 83*10d63b7dSRichard Lowe char tmpname[MAXPATHLEN]; 84*10d63b7dSRichard Lowe static char msg[MAXPATHLEN]; 85*10d63b7dSRichard Lowe 86*10d63b7dSRichard Lowe if (timeout <= 0) { 87*10d63b7dSRichard Lowe timeout = 15; 88*10d63b7dSRichard Lowe } 89*10d63b7dSRichard Lowe for (;;) { 90*10d63b7dSRichard Lowe r = symlink(name, lockname); 91*10d63b7dSRichard Lowe if (r == 0) { 92*10d63b7dSRichard Lowe return (NULL); 93*10d63b7dSRichard Lowe } 94*10d63b7dSRichard Lowe if (errno != EEXIST) { 95*10d63b7dSRichard Lowe file_lock_error(msg, name, 96*10d63b7dSRichard Lowe (const char *)"symlink(%s, %s)", name, lockname); 97*10d63b7dSRichard Lowe return (msg); 98*10d63b7dSRichard Lowe } 99*10d63b7dSRichard Lowe for (;;) { 100*10d63b7dSRichard Lowe (void) sleep(1); 101*10d63b7dSRichard Lowe r = lstat(lockname, &statb); 102*10d63b7dSRichard Lowe if (r == -1) { 103*10d63b7dSRichard Lowe /* 104*10d63b7dSRichard Lowe * The lock must have just gone away - try 105*10d63b7dSRichard Lowe * again. 106*10d63b7dSRichard Lowe */ 107*10d63b7dSRichard Lowe break; 108*10d63b7dSRichard Lowe } 109*10d63b7dSRichard Lowe 110*10d63b7dSRichard Lowe /* 111*10d63b7dSRichard Lowe * With the NFS the time given a file is the time on 112*10d63b7dSRichard Lowe * the file server. This time may vary from the 113*10d63b7dSRichard Lowe * client's time. Therefore, we create a tmpfile in 114*10d63b7dSRichard Lowe * the same directory to establish the time on the 115*10d63b7dSRichard Lowe * server and use this time to see if the lock has 116*10d63b7dSRichard Lowe * expired. 117*10d63b7dSRichard Lowe */ 118*10d63b7dSRichard Lowe (void) sprintf(tmpname, "%s.XXXXXX", lockname); 119*10d63b7dSRichard Lowe (void) mktemp(tmpname); 120*10d63b7dSRichard Lowe fd = creat(tmpname, 0666); 121*10d63b7dSRichard Lowe if (fd != -1) { 122*10d63b7dSRichard Lowe (void) close(fd); 123*10d63b7dSRichard Lowe } else { 124*10d63b7dSRichard Lowe file_lock_error(msg, name, 125*10d63b7dSRichard Lowe (const char *)"creat(%s)", tmpname); 126*10d63b7dSRichard Lowe return (msg); 127*10d63b7dSRichard Lowe } 128*10d63b7dSRichard Lowe if (stat(tmpname, &fs_statb) == -1) { 129*10d63b7dSRichard Lowe file_lock_error(msg, name, 130*10d63b7dSRichard Lowe (const char *)"stat(%s)", tmpname); 131*10d63b7dSRichard Lowe return (msg); 132*10d63b7dSRichard Lowe } 133*10d63b7dSRichard Lowe (void) unlink(tmpname); 134*10d63b7dSRichard Lowe if (statb.st_mtime + timeout < fs_statb.st_mtime) { 135*10d63b7dSRichard Lowe /* 136*10d63b7dSRichard Lowe * The lock has expired - blow it away. 137*10d63b7dSRichard Lowe */ 138*10d63b7dSRichard Lowe (void) unlink(lockname); 139*10d63b7dSRichard Lowe break; 140*10d63b7dSRichard Lowe } 141*10d63b7dSRichard Lowe } 142*10d63b7dSRichard Lowe } 143*10d63b7dSRichard Lowe /* NOTREACHED */ 144*10d63b7dSRichard Lowe } 145*10d63b7dSRichard Lowe 146*10d63b7dSRichard Lowe /* 147*10d63b7dSRichard Lowe * Format a message telling why the lock could not be created. 148*10d63b7dSRichard Lowe */ 149*10d63b7dSRichard Lowe /* VARARGS4 */ 150*10d63b7dSRichard Lowe static void 151*10d63b7dSRichard Lowe file_lock_error(char * msg, char * file, const char * str, char * arg1, 152*10d63b7dSRichard Lowe char * arg2) 153*10d63b7dSRichard Lowe { 154*10d63b7dSRichard Lowe int len; 155*10d63b7dSRichard Lowe 156*10d63b7dSRichard Lowe (void) sprintf(msg, "Could not lock file `%s'; ", file); 157*10d63b7dSRichard Lowe len = strlen(msg); 158*10d63b7dSRichard Lowe (void) sprintf(&msg[len], str, arg1, arg2); 159*10d63b7dSRichard Lowe (void) strcat(msg, " failed - "); 160*10d63b7dSRichard Lowe #if defined(_LP64) 161*10d63b7dSRichard Lowe /* Needs to be changed to use strerror(3C) instead. */ 162*10d63b7dSRichard Lowe len = strlen(msg); 163*10d63b7dSRichard Lowe (void) sprintf(&msg[len], "errno %d", errno); 164*10d63b7dSRichard Lowe #else /* #_LP64 */ 165*10d63b7dSRichard Lowe if (errno < sys_nerr) { 166*10d63b7dSRichard Lowe (void) strcat(msg, sys_errlist[errno]); 167*10d63b7dSRichard Lowe } else { 168*10d63b7dSRichard Lowe len = strlen(msg); 169*10d63b7dSRichard Lowe (void) sprintf(&msg[len], "errno %d", errno); 170*10d63b7dSRichard Lowe } 171*10d63b7dSRichard Lowe #endif /* #_LP64 */ 172*10d63b7dSRichard Lowe } 173