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