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 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 #include "maillock.h" 33 #include <sys/types.h> 34 #include <fcntl.h> 35 #include <stdio.h> 36 #include <string.h> 37 #include <unistd.h> 38 #include <stdlib.h> 39 #include <utime.h> 40 41 #include <sys/stat.h> 42 43 static char *lockext = ".lock"; /* Lock suffix for mailname */ 44 static char curlock[PATHSIZE]; /* Last used name of lock */ 45 static int locked; /* To note that we locked it */ 46 static time_t locktime; /* time lock file was touched */ 47 static time_t lock1(char *, char *); 48 49 /* 50 * Lock the specified mail file by setting the file mailfile.lock. 51 * We must, of course, be careful to remove the lock file by a call 52 * to unlock before we stop. The algorithm used here is to see if 53 * the lock exists, and if it does, to check its modify time. If it 54 * is older than 5 minutes, we assume error and set our own file. 55 * Otherwise, we wait for 5 seconds and try again. 56 */ 57 58 /*ARGSUSED*/ 59 int 60 maillock(char *user, int retrycnt) 61 { 62 time_t t; 63 struct stat sbuf; 64 int statfailed; 65 char locktmp[PATHSIZE]; /* Usable lock temporary */ 66 char file[PATHSIZE]; 67 68 if (locked) 69 return (0); 70 (void) strcpy(file, MAILDIR); 71 (void) strcat(file, user); 72 (void) strcpy(curlock, file); 73 (void) strcat(curlock, lockext); 74 (void) strcpy(locktmp, file); 75 (void) strcat(locktmp, "XXXXXX"); 76 (void) mktemp(locktmp); 77 (void) remove(locktmp); 78 statfailed = 0; 79 for (;;) { 80 t = lock1(locktmp, curlock); 81 if (t == (time_t)0) { 82 locked = 1; 83 locktime = time(0); 84 return (0); 85 } 86 if (stat(curlock, &sbuf) < 0) { 87 if (statfailed++ > 5) 88 return (-1); 89 (void) sleep(5); 90 continue; 91 } 92 statfailed = 0; 93 94 /* 95 * Compare the time of the temp file with the time 96 * of the lock file, rather than with the current 97 * time of day, since the files may reside on 98 * another machine whose time of day differs from 99 * ours. If the lock file is less than 5 minutes 100 * old, keep trying. 101 */ 102 if (t < sbuf.st_ctime + 300) { 103 (void) sleep(5); 104 continue; 105 } 106 (void) remove(curlock); 107 } 108 } 109 110 /* 111 * Remove the mail lock, and note that we no longer 112 * have it locked. 113 */ 114 void 115 mailunlock(void) 116 { 117 (void) remove(curlock); 118 locked = 0; 119 } 120 121 /* 122 * Attempt to set the lock by creating the temporary file, 123 * then doing a link/unlink. If it succeeds, return 0, 124 * else return a guess of the current time on the machine 125 * holding the file. 126 */ 127 static time_t 128 lock1(char tempfile[], char name[]) 129 { 130 int fd; 131 struct stat sbuf; 132 133 fd = open(tempfile, O_RDWR|O_CREAT|O_EXCL, 0600); 134 if (fd < 0) 135 return (time(0)); 136 (void) fstat(fd, &sbuf); 137 /* 138 * Write the string "0" into the lock file to give us some 139 * interoperability with SVR4 mailers. SVR4 mailers expect 140 * a process ID to be written into the lock file and then 141 * use kill() to see if the process is alive or not. We write 142 * 0 into it so that SVR4 mailers will always think our lock file 143 * is valid. 144 */ 145 (void) write(fd, "0", 2); 146 (void) close(fd); 147 if (link(tempfile, name) < 0) { 148 (void) remove(tempfile); 149 return (sbuf.st_ctime); 150 } 151 (void) remove(tempfile); 152 return ((time_t)0); 153 } 154 155 /* 156 * Update the change time on the lock file so 157 * others will know we're still using it. 158 */ 159 void 160 touchlock(void) 161 { 162 struct stat sbuf; 163 time_t t; 164 struct utimbuf tp; 165 166 if (!locked) 167 return; 168 169 /* if it hasn't been at least 3 minutes, don't bother */ 170 if (time(&t) < locktime + 180) 171 return; 172 locktime = t; 173 174 if (stat(curlock, &sbuf) < 0) 175 return; 176 /* 177 * Don't actually change the times, we just want the 178 * side effect that utime causes st_ctime to be set 179 * to the current time. 180 */ 181 tp.actime = sbuf.st_atime; 182 tp.modtime = sbuf.st_mtime; 183 (void) utime(curlock, &tp); 184 } 185