imapext-2007
diff src/mlock/mlock.c @ 0:ada5e610ab86
imap-2007e
author | yuuji@gentei.org |
---|---|
date | Mon, 14 Sep 2009 15:17:45 +0900 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/mlock/mlock.c Mon Sep 14 15:17:45 2009 +0900 1.3 @@ -0,0 +1,175 @@ 1.4 +/* ======================================================================== 1.5 + * Copyright 1988-2008 University of Washington 1.6 + * 1.7 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.8 + * you may not use this file except in compliance with the License. 1.9 + * You may obtain a copy of the License at 1.10 + * 1.11 + * http://www.apache.org/licenses/LICENSE-2.0 1.12 + * 1.13 + * 1.14 + * ======================================================================== 1.15 + */ 1.16 + 1.17 +/* 1.18 + * Program: Standalone Mailbox Lock program 1.19 + * 1.20 + * Author: Mark Crispin 1.21 + * Networks and Distributed Computing 1.22 + * Computing & Communications 1.23 + * University of Washington 1.24 + * Administration Building, AG-44 1.25 + * Seattle, WA 98195 1.26 + * Internet: MRC@CAC.Washington.EDU 1.27 + * 1.28 + * Date: 8 February 1999 1.29 + * Last Edited: 3 March 2008 1.30 + */ 1.31 + 1.32 +#include <errno.h> 1.33 +#include <fcntl.h> 1.34 +#include <stdio.h> 1.35 +#include <sysexits.h> 1.36 +#include <syslog.h> 1.37 +#include <grp.h> 1.38 +#include <sys/types.h> 1.39 +#include <sys/file.h> 1.40 +#include <sys/stat.h> 1.41 +#include <sys/param.h> 1.42 +#include <stdlib.h> 1.43 +#include <netdb.h> 1.44 +#include <ctype.h> 1.45 +#include <string.h> 1.46 + 1.47 +#define LOCKTIMEOUT 5 /* lock timeout in minutes */ 1.48 +#define LOCKPROTECTION 0664 1.49 + 1.50 +#ifndef MAXHOSTNAMELEN /* Solaris still sucks */ 1.51 +#define MAXHOSTNAMELEN 256 1.52 +#endif 1.53 + 1.54 +/* Fatal error 1.55 + * Accepts: Message string 1.56 + * exit code 1.57 + * Returns: code 1.58 + */ 1.59 + 1.60 +int die (char *msg,int code) 1.61 +{ 1.62 + syslog (LOG_NOTICE,"(%u) %s",code,msg); 1.63 + write (1,"?",1); /* indicate "impossible" failure */ 1.64 + return code; 1.65 +} 1.66 + 1.67 + 1.68 +int main (int argc,char *argv[]) 1.69 +{ 1.70 + int ld,i; 1.71 + int tries = LOCKTIMEOUT * 60 - 1; 1.72 + char *s,*dir,*file,*lock,*hitch,tmp[1024]; 1.73 + size_t dlen,len; 1.74 + struct stat sb,fsb; 1.75 + struct group *grp = getgrnam ("mail"); 1.76 + /* get syslog */ 1.77 + openlog (argv[0],LOG_PID,LOG_MAIL); 1.78 + if (!grp || (grp->gr_gid != getegid ())) 1.79 + return die ("not setgid mail",EX_USAGE); 1.80 + if (argc != 3) return die ("invalid arguments",EX_USAGE); 1.81 + for (s = argv[1]; *s; s++) 1.82 + if (!isdigit (*s)) return die ("invalid fd",EX_USAGE); 1.83 + /* find directory */ 1.84 + if ((*argv[2] != '/') || !(file = strrchr (argv[2],'/')) || !file[1]) 1.85 + return die ("invalid path",EX_USAGE); 1.86 + /* calculate lengths of directory and file */ 1.87 + if (!(dlen = file - argv[2])) dlen = 1; 1.88 + len = strlen (++file); 1.89 + /* make buffers */ 1.90 + dir = (char *) malloc (dlen + 1); 1.91 + lock = (char *) malloc (len + 6); 1.92 + hitch = (char *) malloc (len + 6 + 40 + MAXHOSTNAMELEN); 1.93 + if (!dir || !lock || !hitch) return die ("malloc failure",errno); 1.94 + strncpy (dir,argv[2],dlen); /* connect to desired directory */ 1.95 + dir[dlen] = '\0'; 1.96 + printf ("dir=%s, file=%s\n",dir,file); 1.97 + chdir (dir); 1.98 + /* get device/inode of file descriptor */ 1.99 + if (fstat (atoi (argv[1]),&fsb)) return die ("fstat failure",errno); 1.100 + /* better be a regular file */ 1.101 + if ((fsb.st_mode & S_IFMT) != S_IFREG) 1.102 + return die ("fd not regular file",EX_USAGE); 1.103 + /* now get device/inode of file */ 1.104 + if (lstat (file,&sb)) return die ("lstat failure",errno); 1.105 + /* does it match? */ 1.106 + if ((sb.st_mode & S_IFMT) != S_IFREG) 1.107 + return die ("name not regular file",EX_USAGE); 1.108 + if ((sb.st_dev != fsb.st_dev) || (sb.st_ino != fsb.st_ino)) 1.109 + return die ("fd and name different",EX_USAGE); 1.110 + /* build lock filename */ 1.111 + sprintf (lock,"%s.lock",file); 1.112 + if (!lstat (lock,&sb) && ((sb.st_mode & S_IFMT) != S_IFREG)) 1.113 + return die ("existing lock not regular file",EX_NOPERM); 1.114 + 1.115 + do { /* until OK or out of tries */ 1.116 + if (!stat (lock,&sb) && (time (0) > (sb.st_ctime + LOCKTIMEOUT * 60))) 1.117 + unlink (lock); /* time out lock if enough time has passed */ 1.118 + /* SUN-OS had an NFS 1.119 + * As kludgy as an albatross; 1.120 + * And everywhere that it was installed, 1.121 + * It was a total loss. 1.122 + * -- MRC 9/25/91 1.123 + */ 1.124 + /* build hitching post file name */ 1.125 + sprintf (hitch,"%s.%lu.%lu.",lock,(unsigned long) time (0), 1.126 + (unsigned long) getpid ()); 1.127 + len = strlen (hitch); /* append local host name */ 1.128 + gethostname (hitch + len,MAXHOSTNAMELEN); 1.129 + /* try to get hitching-post file */ 1.130 + if ((ld = open (hitch,O_WRONLY|O_CREAT|O_EXCL,LOCKPROTECTION)) >= 0) { 1.131 + /* make sure others can break the lock */ 1.132 + chmod (hitch,LOCKPROTECTION); 1.133 + /* get device/inode of hitch file */ 1.134 + if (fstat (ld,&fsb)) return die ("hitch fstat failure",errno); 1.135 + close (ld); /* close the hitching-post */ 1.136 + /* Note: link() may return an error even if it actually succeeded. So we 1.137 + * always check for success via the link count, and ignore the error if 1.138 + * the link count is right. 1.139 + */ 1.140 + /* tie hitching-post to lock */ 1.141 + i = link (hitch,lock) ? errno : 0; 1.142 + /* success if link count now 2 */ 1.143 + if (stat (hitch,&sb) || (sb.st_nlink != 2) || 1.144 + (fsb.st_dev != sb.st_dev) || (fsb.st_ino != sb.st_ino)) { 1.145 + ld = -1; /* failed to hitch */ 1.146 + if (i == EPERM) { /* was it because links not allowed? */ 1.147 + /* Probably a FAT filesystem on Linux. It can't be NFS, so try 1.148 + * creating the lock file directly. 1.149 + */ 1.150 + if ((ld = open (lock,O_WRONLY|O_CREAT|O_EXCL,LOCKPROTECTION)) >= 0) { 1.151 + /* get device/inode of lock file */ 1.152 + if (fstat (ld,&fsb)) return die ("lock fstat failure",errno); 1.153 + close (ld); /* close the file */ 1.154 + } 1.155 + /* give up immediately if protection failure */ 1.156 + else if (errno != EEXIST) tries = 0; 1.157 + } 1.158 + } 1.159 + unlink (hitch); /* flush hitching post */ 1.160 + } 1.161 + /* give up immediately if protection failure */ 1.162 + else if (errno == EACCES) tries = 0; 1.163 + if (ld < 0) { /* lock failed */ 1.164 + if (tries--) sleep (1); /* sleep 1 second and try again */ 1.165 + else { 1.166 + write (1,"-",1); /* hard failure */ 1.167 + return EX_CANTCREAT; 1.168 + } 1.169 + } 1.170 + } while (ld < 0); 1.171 + write (1,"+",1); /* indicate that all is well */ 1.172 + read (0,tmp,1); /* read continue signal from parent */ 1.173 + /* flush the lock file */ 1.174 + if (!stat (lock,&sb) && (fsb.st_dev == sb.st_dev) && 1.175 + (fsb.st_ino == sb.st_ino)) unlink (lock); 1.176 + else syslog (LOG_NOTICE,"lock file %s/%s changed dev/inode",dir,lock); 1.177 + return EX_OK; 1.178 +}