1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 #include "maillock.h" 31 #include <sys/types.h> 32 #include <fcntl.h> 33 #include <stdio.h> 34 #include <string.h> 35 #include <unistd.h> 36 #include <stdlib.h> 37 #include <utime.h> 38 39 #include <sys/stat.h> 40 41 static char *lockext = ".lock"; /* Lock suffix for mailname */ 42 static char curlock[PATHSIZE]; /* Last used name of lock */ 43 static int locked; /* To note that we locked it */ 44 static time_t locktime; /* time lock file was touched */ 45 static time_t lock1(char *, char *); 46 47 /* 48 * Lock the specified mail file by setting the file mailfile.lock. 49 * We must, of course, be careful to remove the lock file by a call 50 * to unlock before we stop. The algorithm used here is to see if 51 * the lock exists, and if it does, to check its modify time. If it 52 * is older than 5 minutes, we assume error and set our own file. 53 * Otherwise, we wait for 5 seconds and try again. 54 */ 55 56 /*ARGSUSED*/ 57 int 58 maillock(char *user, int retrycnt) 59 { 60 time_t t; 61 struct stat sbuf; 62 int statfailed; 63 char locktmp[PATHSIZE]; /* Usable lock temporary */ 64 char file[PATHSIZE]; 65 66 if (locked) 67 return (0); 68 (void) strcpy(file, MAILDIR); 69 (void) strcat(file, user); 70 (void) strcpy(curlock, file); 71 (void) strcat(curlock, lockext); 72 (void) strcpy(locktmp, file); 73 (void) strcat(locktmp, "XXXXXX"); 74 (void) mktemp(locktmp); 75 (void) remove(locktmp); 76 statfailed = 0; 77 for (;;) { 78 t = lock1(locktmp, curlock); 79 if (t == (time_t)0) { 80 locked = 1; 81 locktime = time(0); 82 return (0); 83 } 84 if (stat(curlock, &sbuf) < 0) { 85 if (statfailed++ > 5) 86 return (-1); 87 (void) sleep(5); 88 continue; 89 } 90 statfailed = 0; 91 92 /* 93 * Compare the time of the temp file with the time 94 * of the lock file, rather than with the current 95 * time of day, since the files may reside on 96 * another machine whose time of day differs from 97 * ours. If the lock file is less than 5 minutes 98 * old, keep trying. 99 */ 100 if (t < sbuf.st_ctime + 300) { 101 (void) sleep(5); 102 continue; 103 } 104 (void) remove(curlock); 105 } 106 } 107 108 /* 109 * Remove the mail lock, and note that we no longer 110 * have it locked. 111 */ 112 void 113 mailunlock(void) 114 { 115 (void) remove(curlock); 116 locked = 0; 117 } 118 119 /* 120 * Attempt to set the lock by creating the temporary file, 121 * then doing a link/unlink. If it succeeds, return 0, 122 * else return a guess of the current time on the machine 123 * holding the file. 124 */ 125 static time_t 126 lock1(char tempfile[], char name[]) 127 { 128 int fd; 129 struct stat sbuf; 130 131 fd = open(tempfile, O_RDWR|O_CREAT|O_EXCL, 0600); 132 if (fd < 0) 133 return (time(0)); 134 (void) fstat(fd, &sbuf); 135 /* 136 * Write the string "0" into the lock file to give us some 137 * interoperability with SVR4 mailers. SVR4 mailers expect 138 * a process ID to be written into the lock file and then 139 * use kill() to see if the process is alive or not. We write 140 * 0 into it so that SVR4 mailers will always think our lock file 141 * is valid. 142 */ 143 (void) write(fd, "0", 2); 144 (void) close(fd); 145 if (link(tempfile, name) < 0) { 146 (void) remove(tempfile); 147 return (sbuf.st_ctime); 148 } 149 (void) remove(tempfile); 150 return ((time_t)0); 151 } 152 153 /* 154 * Update the change time on the lock file so 155 * others will know we're still using it. 156 */ 157 void 158 touchlock(void) 159 { 160 struct stat sbuf; 161 time_t t; 162 struct utimbuf tp; 163 164 if (!locked) 165 return; 166 167 /* if it hasn't been at least 3 minutes, don't bother */ 168 if (time(&t) < locktime + 180) 169 return; 170 locktime = t; 171 172 if (stat(curlock, &sbuf) < 0) 173 return; 174 /* 175 * Don't actually change the times, we just want the 176 * side effect that utime causes st_ctime to be set 177 * to the current time. 178 */ 179 tp.actime = sbuf.st_atime; 180 tp.modtime = sbuf.st_mtime; 181 (void) utime(curlock, &tp); 182 } 183