1 /* $NetBSD: dot_lockfile.c,v 1.1.1.2 2013/01/02 18:58:57 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* dot_lockfile 3 6 /* SUMMARY 7 /* dotlock file management 8 /* SYNOPSIS 9 /* #include <dot_lockfile.h> 10 /* 11 /* int dot_lockfile(path, why) 12 /* const char *path; 13 /* VSTRING *why; 14 /* 15 /* void dot_unlockfile(path) 16 /* const char *path; 17 /* DESCRIPTION 18 /* dot_lockfile() constructs a lock file name by appending ".lock" to 19 /* \fIpath\fR and creates the named file exclusively. It tries several 20 /* times and attempts to break stale locks. A negative result value 21 /* means no lock file could be created. 22 /* 23 /* dot_unlockfile() attempts to remove the lock file created by 24 /* dot_lockfile(). The operation always succeeds, and therefore 25 /* it preserves the errno value. 26 /* 27 /* Arguments: 28 /* .IP path 29 /* Name of the file to be locked or unlocked. 30 /* .IP why 31 /* A null pointer, or storage for the reason why a lock file could 32 /* not be created. 33 /* DIAGNOSTICS 34 /* dot_lockfile() returns 0 upon success. In case of failure, the 35 /* result is -1, and the errno variable is set appropriately: 36 /* EEXIST when a "fresh" lock file already exists; other values as 37 /* appropriate. 38 /* CONFIGURATION PARAMETERS 39 /* deliver_lock_attempts, how many times to try to create a lock 40 /* deliver_lock_delay, how long to wait between attempts 41 /* stale_lock_time, when to break a stale lock 42 /* LICENSE 43 /* .ad 44 /* .fi 45 /* The Secure Mailer license must be distributed with this software. 46 /* AUTHOR(S) 47 /* Wietse Venema 48 /* IBM T.J. Watson Research 49 /* P.O. Box 704 50 /* Yorktown Heights, NY 10598, USA 51 /*--*/ 52 53 /* System library. */ 54 55 #include "sys_defs.h" 56 #include <sys/stat.h> 57 #include <stdlib.h> 58 #include <unistd.h> 59 #include <fcntl.h> 60 #include <errno.h> 61 #include <time.h> 62 63 /* Utility library. */ 64 65 #include <vstring.h> 66 #include <stringops.h> 67 #include <mymalloc.h> 68 #include <iostuff.h> 69 #include <warn_stat.h> 70 71 /* Global library. */ 72 73 #include "mail_params.h" 74 #include "dot_lockfile.h" 75 76 /* Application-specific. */ 77 78 #define MILLION 1000000 79 80 /* dot_lockfile - create user.lock file */ 81 82 int dot_lockfile(const char *path, VSTRING *why) 83 { 84 char *lock_file; 85 int count; 86 struct stat st; 87 int fd; 88 int status = -1; 89 90 lock_file = concatenate(path, ".lock", (char *) 0); 91 92 for (count = 1; /* void */ ; count++) { 93 94 /* 95 * Attempt to create the lock. This code relies on O_EXCL | O_CREAT 96 * to not follow symlinks. With NFS file systems this operation can 97 * at the same time succeed and fail with errno of EEXIST. 98 */ 99 if ((fd = open(lock_file, O_WRONLY | O_EXCL | O_CREAT, 0)) >= 0) { 100 close(fd); 101 status = 0; 102 break; 103 } 104 if (count >= var_flock_tries) 105 break; 106 107 /* 108 * We can deal only with "file exists" errors. Any other error means 109 * we better give up trying. 110 */ 111 if (errno != EEXIST) 112 break; 113 114 /* 115 * Break the lock when it is too old. Give up when we are unable to 116 * remove a stale lock. 117 */ 118 if (stat(lock_file, &st) == 0) 119 if (time((time_t *) 0) > st.st_ctime + var_flock_stale) 120 if (unlink(lock_file) < 0) 121 if (errno != ENOENT) 122 break; 123 124 rand_sleep(var_flock_delay * MILLION, var_flock_delay * MILLION / 2); 125 } 126 if (status && why) 127 vstring_sprintf(why, "unable to create lock file %s: %m", lock_file); 128 129 myfree(lock_file); 130 return (status); 131 } 132 133 /* dot_unlockfile - remove .lock file */ 134 135 void dot_unlockfile(const char *path) 136 { 137 char *lock_file; 138 int saved_errno = errno; 139 140 lock_file = concatenate(path, ".lock", (char *) 0); 141 (void) unlink(lock_file); 142 myfree(lock_file); 143 errno = saved_errno; 144 } 145 146 #ifdef TEST 147 148 /* 149 * Test program for setting a .lock file. 150 * 151 * Usage: dot_lockfile filename 152 * 153 * Creates filename.lock and removes it. 154 */ 155 #include <msg.h> 156 #include <vstream.h> 157 #include <msg_vstream.h> 158 #include <mail_conf.h> 159 160 int main(int argc, char **argv) 161 { 162 VSTRING *why = vstring_alloc(100); 163 164 msg_vstream_init(argv[0], VSTREAM_ERR); 165 if (argc != 2) 166 msg_fatal("usage: %s file-to-be-locked", argv[0]); 167 mail_conf_read(); 168 if (dot_lockfile(argv[1], why) < 0) 169 msg_fatal("%s", vstring_str(why)); 170 dot_unlockfile(argv[1]); 171 vstring_free(why); 172 return (0); 173 } 174 175 #endif 176