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 +}

UW-IMAP'd extensions by yuuji