imapext-2007

annotate src/mlock/mlock.c @ 0:ada5e610ab86

imap-2007e
author yuuji@gentei.org
date Mon, 14 Sep 2009 15:17:45 +0900
parents
children
rev   line source
yuuji@0 1 /* ========================================================================
yuuji@0 2 * Copyright 1988-2008 University of Washington
yuuji@0 3 *
yuuji@0 4 * Licensed under the Apache License, Version 2.0 (the "License");
yuuji@0 5 * you may not use this file except in compliance with the License.
yuuji@0 6 * You may obtain a copy of the License at
yuuji@0 7 *
yuuji@0 8 * http://www.apache.org/licenses/LICENSE-2.0
yuuji@0 9 *
yuuji@0 10 *
yuuji@0 11 * ========================================================================
yuuji@0 12 */
yuuji@0 13
yuuji@0 14 /*
yuuji@0 15 * Program: Standalone Mailbox Lock program
yuuji@0 16 *
yuuji@0 17 * Author: Mark Crispin
yuuji@0 18 * Networks and Distributed Computing
yuuji@0 19 * Computing & Communications
yuuji@0 20 * University of Washington
yuuji@0 21 * Administration Building, AG-44
yuuji@0 22 * Seattle, WA 98195
yuuji@0 23 * Internet: MRC@CAC.Washington.EDU
yuuji@0 24 *
yuuji@0 25 * Date: 8 February 1999
yuuji@0 26 * Last Edited: 3 March 2008
yuuji@0 27 */
yuuji@0 28
yuuji@0 29 #include <errno.h>
yuuji@0 30 #include <fcntl.h>
yuuji@0 31 #include <stdio.h>
yuuji@0 32 #include <sysexits.h>
yuuji@0 33 #include <syslog.h>
yuuji@0 34 #include <grp.h>
yuuji@0 35 #include <sys/types.h>
yuuji@0 36 #include <sys/file.h>
yuuji@0 37 #include <sys/stat.h>
yuuji@0 38 #include <sys/param.h>
yuuji@0 39 #include <stdlib.h>
yuuji@0 40 #include <netdb.h>
yuuji@0 41 #include <ctype.h>
yuuji@0 42 #include <string.h>
yuuji@0 43
yuuji@0 44 #define LOCKTIMEOUT 5 /* lock timeout in minutes */
yuuji@0 45 #define LOCKPROTECTION 0664
yuuji@0 46
yuuji@0 47 #ifndef MAXHOSTNAMELEN /* Solaris still sucks */
yuuji@0 48 #define MAXHOSTNAMELEN 256
yuuji@0 49 #endif
yuuji@0 50
yuuji@0 51 /* Fatal error
yuuji@0 52 * Accepts: Message string
yuuji@0 53 * exit code
yuuji@0 54 * Returns: code
yuuji@0 55 */
yuuji@0 56
yuuji@0 57 int die (char *msg,int code)
yuuji@0 58 {
yuuji@0 59 syslog (LOG_NOTICE,"(%u) %s",code,msg);
yuuji@0 60 write (1,"?",1); /* indicate "impossible" failure */
yuuji@0 61 return code;
yuuji@0 62 }
yuuji@0 63
yuuji@0 64
yuuji@0 65 int main (int argc,char *argv[])
yuuji@0 66 {
yuuji@0 67 int ld,i;
yuuji@0 68 int tries = LOCKTIMEOUT * 60 - 1;
yuuji@0 69 char *s,*dir,*file,*lock,*hitch,tmp[1024];
yuuji@0 70 size_t dlen,len;
yuuji@0 71 struct stat sb,fsb;
yuuji@0 72 struct group *grp = getgrnam ("mail");
yuuji@0 73 /* get syslog */
yuuji@0 74 openlog (argv[0],LOG_PID,LOG_MAIL);
yuuji@0 75 if (!grp || (grp->gr_gid != getegid ()))
yuuji@0 76 return die ("not setgid mail",EX_USAGE);
yuuji@0 77 if (argc != 3) return die ("invalid arguments",EX_USAGE);
yuuji@0 78 for (s = argv[1]; *s; s++)
yuuji@0 79 if (!isdigit (*s)) return die ("invalid fd",EX_USAGE);
yuuji@0 80 /* find directory */
yuuji@0 81 if ((*argv[2] != '/') || !(file = strrchr (argv[2],'/')) || !file[1])
yuuji@0 82 return die ("invalid path",EX_USAGE);
yuuji@0 83 /* calculate lengths of directory and file */
yuuji@0 84 if (!(dlen = file - argv[2])) dlen = 1;
yuuji@0 85 len = strlen (++file);
yuuji@0 86 /* make buffers */
yuuji@0 87 dir = (char *) malloc (dlen + 1);
yuuji@0 88 lock = (char *) malloc (len + 6);
yuuji@0 89 hitch = (char *) malloc (len + 6 + 40 + MAXHOSTNAMELEN);
yuuji@0 90 if (!dir || !lock || !hitch) return die ("malloc failure",errno);
yuuji@0 91 strncpy (dir,argv[2],dlen); /* connect to desired directory */
yuuji@0 92 dir[dlen] = '\0';
yuuji@0 93 printf ("dir=%s, file=%s\n",dir,file);
yuuji@0 94 chdir (dir);
yuuji@0 95 /* get device/inode of file descriptor */
yuuji@0 96 if (fstat (atoi (argv[1]),&fsb)) return die ("fstat failure",errno);
yuuji@0 97 /* better be a regular file */
yuuji@0 98 if ((fsb.st_mode & S_IFMT) != S_IFREG)
yuuji@0 99 return die ("fd not regular file",EX_USAGE);
yuuji@0 100 /* now get device/inode of file */
yuuji@0 101 if (lstat (file,&sb)) return die ("lstat failure",errno);
yuuji@0 102 /* does it match? */
yuuji@0 103 if ((sb.st_mode & S_IFMT) != S_IFREG)
yuuji@0 104 return die ("name not regular file",EX_USAGE);
yuuji@0 105 if ((sb.st_dev != fsb.st_dev) || (sb.st_ino != fsb.st_ino))
yuuji@0 106 return die ("fd and name different",EX_USAGE);
yuuji@0 107 /* build lock filename */
yuuji@0 108 sprintf (lock,"%s.lock",file);
yuuji@0 109 if (!lstat (lock,&sb) && ((sb.st_mode & S_IFMT) != S_IFREG))
yuuji@0 110 return die ("existing lock not regular file",EX_NOPERM);
yuuji@0 111
yuuji@0 112 do { /* until OK or out of tries */
yuuji@0 113 if (!stat (lock,&sb) && (time (0) > (sb.st_ctime + LOCKTIMEOUT * 60)))
yuuji@0 114 unlink (lock); /* time out lock if enough time has passed */
yuuji@0 115 /* SUN-OS had an NFS
yuuji@0 116 * As kludgy as an albatross;
yuuji@0 117 * And everywhere that it was installed,
yuuji@0 118 * It was a total loss.
yuuji@0 119 * -- MRC 9/25/91
yuuji@0 120 */
yuuji@0 121 /* build hitching post file name */
yuuji@0 122 sprintf (hitch,"%s.%lu.%lu.",lock,(unsigned long) time (0),
yuuji@0 123 (unsigned long) getpid ());
yuuji@0 124 len = strlen (hitch); /* append local host name */
yuuji@0 125 gethostname (hitch + len,MAXHOSTNAMELEN);
yuuji@0 126 /* try to get hitching-post file */
yuuji@0 127 if ((ld = open (hitch,O_WRONLY|O_CREAT|O_EXCL,LOCKPROTECTION)) >= 0) {
yuuji@0 128 /* make sure others can break the lock */
yuuji@0 129 chmod (hitch,LOCKPROTECTION);
yuuji@0 130 /* get device/inode of hitch file */
yuuji@0 131 if (fstat (ld,&fsb)) return die ("hitch fstat failure",errno);
yuuji@0 132 close (ld); /* close the hitching-post */
yuuji@0 133 /* Note: link() may return an error even if it actually succeeded. So we
yuuji@0 134 * always check for success via the link count, and ignore the error if
yuuji@0 135 * the link count is right.
yuuji@0 136 */
yuuji@0 137 /* tie hitching-post to lock */
yuuji@0 138 i = link (hitch,lock) ? errno : 0;
yuuji@0 139 /* success if link count now 2 */
yuuji@0 140 if (stat (hitch,&sb) || (sb.st_nlink != 2) ||
yuuji@0 141 (fsb.st_dev != sb.st_dev) || (fsb.st_ino != sb.st_ino)) {
yuuji@0 142 ld = -1; /* failed to hitch */
yuuji@0 143 if (i == EPERM) { /* was it because links not allowed? */
yuuji@0 144 /* Probably a FAT filesystem on Linux. It can't be NFS, so try
yuuji@0 145 * creating the lock file directly.
yuuji@0 146 */
yuuji@0 147 if ((ld = open (lock,O_WRONLY|O_CREAT|O_EXCL,LOCKPROTECTION)) >= 0) {
yuuji@0 148 /* get device/inode of lock file */
yuuji@0 149 if (fstat (ld,&fsb)) return die ("lock fstat failure",errno);
yuuji@0 150 close (ld); /* close the file */
yuuji@0 151 }
yuuji@0 152 /* give up immediately if protection failure */
yuuji@0 153 else if (errno != EEXIST) tries = 0;
yuuji@0 154 }
yuuji@0 155 }
yuuji@0 156 unlink (hitch); /* flush hitching post */
yuuji@0 157 }
yuuji@0 158 /* give up immediately if protection failure */
yuuji@0 159 else if (errno == EACCES) tries = 0;
yuuji@0 160 if (ld < 0) { /* lock failed */
yuuji@0 161 if (tries--) sleep (1); /* sleep 1 second and try again */
yuuji@0 162 else {
yuuji@0 163 write (1,"-",1); /* hard failure */
yuuji@0 164 return EX_CANTCREAT;
yuuji@0 165 }
yuuji@0 166 }
yuuji@0 167 } while (ld < 0);
yuuji@0 168 write (1,"+",1); /* indicate that all is well */
yuuji@0 169 read (0,tmp,1); /* read continue signal from parent */
yuuji@0 170 /* flush the lock file */
yuuji@0 171 if (!stat (lock,&sb) && (fsb.st_dev == sb.st_dev) &&
yuuji@0 172 (fsb.st_ino == sb.st_ino)) unlink (lock);
yuuji@0 173 else syslog (LOG_NOTICE,"lock file %s/%s changed dev/inode",dir,lock);
yuuji@0 174 return EX_OK;
yuuji@0 175 }

UW-IMAP'd extensions by yuuji