uucplock.c revision 1.8
1/* * $OpenBSD: uucplock.c,v 1.8 2002/02/16 21:27:29 millert Exp $*/ 2/* 3 * Copyright (c) 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by the University of 17 * California, Berkeley and its contributors. 18 * 4. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * 35 */ 36 37#ifndef lint 38static const char sccsid[] = "@(#)uucplock.c 8.1 (Berkeley) 6/6/93"; 39#endif /* not lint */ 40 41#include <sys/types.h> 42#include <dirent.h> 43#include <errno.h> 44#include <fcntl.h> 45#include <unistd.h> 46#include <signal.h> 47#include <stdio.h> 48#include <stdlib.h> 49#include <paths.h> 50#include <string.h> 51#include "util.h" 52 53#define MAXTRIES 5 54 55#define LOCKTMP "LCKTMP..%d" 56#define LOCKFMT "LCK..%s" 57 58#define GORET(level, val) { err = errno; uuerr = (val); \ 59 goto __CONCAT(ret, level); } 60 61/* Forward declarations */ 62static int put_pid(int fd, pid_t pid); 63static pid_t get_pid(int fd,int *err); 64 65/* 66 * uucp style locking routines 67 */ 68 69int 70uu_lock(ttyname) 71 const char *ttyname; 72{ 73 int fd, tmpfd, i; 74 pid_t pid, pid_old; 75 char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN], 76 lcktmpname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN]; 77 int err, uuerr; 78 79 pid = getpid(); 80 (void)snprintf(lcktmpname, sizeof(lcktmpname), _PATH_UUCPLOCK LOCKTMP, 81 pid); 82 (void)snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT, 83 ttyname); 84 if ((tmpfd = creat(lcktmpname, 0664)) < 0) 85 GORET(0, UU_LOCK_CREAT_ERR); 86 87 for (i = 0; i < MAXTRIES; i++) { 88 if (link (lcktmpname, lckname) < 0) { 89 if (errno != EEXIST) 90 GORET(1, UU_LOCK_LINK_ERR); 91 /* 92 * file is already locked 93 * check to see if the process holding the lock 94 * still exists 95 */ 96 if ((fd = open(lckname, O_RDONLY)) < 0) 97 GORET(1, UU_LOCK_OPEN_ERR); 98 99 if ((pid_old = get_pid (fd, &err)) == -1) 100 GORET(2, UU_LOCK_READ_ERR); 101 102 close(fd); 103 104 if (kill(pid_old, 0) == 0 || errno != ESRCH) 105 GORET(1, UU_LOCK_INUSE); 106 /* 107 * The process that locked the file isn't running, so 108 * we'll lock it ourselves 109 */ 110 (void)unlink(lckname); 111 } else { 112 if (!put_pid (tmpfd, pid)) 113 GORET(3, UU_LOCK_WRITE_ERR); 114 break; 115 } 116 } 117 GORET(1, (i >= MAXTRIES) ? UU_LOCK_TRY_ERR : UU_LOCK_OK); 118 119ret3: 120 (void)unlink(lckname); 121 goto ret1; 122ret2: 123 (void)close(fd); 124ret1: 125 (void)close(tmpfd); 126 (void)unlink(lcktmpname); 127ret0: 128 errno = err; 129 return uuerr; 130} 131 132int 133uu_lock_txfr(ttyname, pid) 134 const char *ttyname; 135 pid_t pid; 136{ 137 int fd, err; 138 char lckname[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN]; 139 140 snprintf(lckname, sizeof(lckname), _PATH_UUCPLOCK LOCKFMT, ttyname); 141 142 if ((fd = open(lckname, O_RDWR)) < 0) 143 return UU_LOCK_OWNER_ERR; 144 if (get_pid(fd, &err) != getpid()) 145 return UU_LOCK_OWNER_ERR; 146 lseek(fd, 0, SEEK_SET); 147 if (put_pid(fd, pid)) 148 return UU_LOCK_WRITE_ERR; 149 close(fd); 150 151 return UU_LOCK_OK; 152} 153 154int 155uu_unlock(ttyname) 156 const char *ttyname; 157{ 158 char tbuf[sizeof(_PATH_UUCPLOCK) + MAXNAMLEN]; 159 160 (void)snprintf(tbuf, sizeof(tbuf), _PATH_UUCPLOCK LOCKFMT, ttyname); 161 return unlink(tbuf); 162} 163 164const char * 165uu_lockerr(uu_lockresult) 166 int uu_lockresult; 167{ 168 static char errbuf[128]; 169 char *fmt; 170 171 switch (uu_lockresult) { 172 case UU_LOCK_INUSE: 173 return "device in use"; 174 case UU_LOCK_OK: 175 return ""; 176 case UU_LOCK_OPEN_ERR: 177 fmt = "open error: %s"; 178 break; 179 case UU_LOCK_READ_ERR: 180 fmt = "read error: %s"; 181 break; 182 case UU_LOCK_CREAT_ERR: 183 fmt = "creat error: %s"; 184 break; 185 case UU_LOCK_WRITE_ERR: 186 fmt = "write error: %s"; 187 break; 188 case UU_LOCK_LINK_ERR: 189 fmt = "link error: %s"; 190 break; 191 case UU_LOCK_TRY_ERR: 192 fmt = "too many tries: %s"; 193 break; 194 case UU_LOCK_OWNER_ERR: 195 fmt = "not locking process: %s"; 196 break; 197 default: 198 fmt = "undefined error: %s"; 199 break; 200 } 201 202 (void)snprintf(errbuf, sizeof(errbuf), fmt, strerror(errno)); 203 return errbuf; 204} 205 206static int 207put_pid(fd, pid) 208 int fd; 209 pid_t pid; 210{ 211 char buf[32]; 212 int len; 213 214 len = sprintf (buf, "%10d\n", (int)pid); 215 216 if (write (fd, buf, len) == len) { 217 /* We don't mind too much if ftruncate() fails - see get_pid */ 218 ftruncate(fd, len); 219 return 1; 220 } 221 return 0; 222} 223 224static pid_t 225get_pid(fd, err) 226 int fd; 227 int *err; 228{ 229 int bytes_read; 230 char buf[32]; 231 pid_t pid; 232 233 bytes_read = read (fd, buf, sizeof (buf) - 1); 234 if (bytes_read > 0) { 235 buf[bytes_read] = '\0'; 236 pid = strtoul (buf, (char **) NULL, 10); 237 } else { 238 pid = -1; 239 *err = bytes_read ? errno : EINVAL; 240 } 241 return pid; 242} 243