summaryrefslogtreecommitdiff
path: root/imap/src/mlock/mlock.c
diff options
context:
space:
mode:
authorEduardo Chappa <echappa@gmx.com>2013-02-03 00:59:38 -0700
committerEduardo Chappa <echappa@gmx.com>2013-02-03 00:59:38 -0700
commit094ca96844842928810f14844413109fc6cdd890 (patch)
treee60efbb980f38ba9308ccb4fb2b77b87bbc115f3 /imap/src/mlock/mlock.c
downloadalpine-094ca96844842928810f14844413109fc6cdd890.tar.xz
Initial Alpine Version
Diffstat (limited to 'imap/src/mlock/mlock.c')
-rw-r--r--imap/src/mlock/mlock.c175
1 files changed, 175 insertions, 0 deletions
diff --git a/imap/src/mlock/mlock.c b/imap/src/mlock/mlock.c
new file mode 100644
index 00000000..1dca40ed
--- /dev/null
+++ b/imap/src/mlock/mlock.c
@@ -0,0 +1,175 @@
+/* ========================================================================
+ * Copyright 1988-2008 University of Washington
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *
+ * ========================================================================
+ */
+
+/*
+ * Program: Standalone Mailbox Lock program
+ *
+ * Author: Mark Crispin
+ * Networks and Distributed Computing
+ * Computing & Communications
+ * University of Washington
+ * Administration Building, AG-44
+ * Seattle, WA 98195
+ * Internet: MRC@CAC.Washington.EDU
+ *
+ * Date: 8 February 1999
+ * Last Edited: 3 March 2008
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sysexits.h>
+#include <syslog.h>
+#include <grp.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <string.h>
+
+#define LOCKTIMEOUT 5 /* lock timeout in minutes */
+#define LOCKPROTECTION 0664
+
+#ifndef MAXHOSTNAMELEN /* Solaris still sucks */
+#define MAXHOSTNAMELEN 256
+#endif
+
+/* Fatal error
+ * Accepts: Message string
+ * exit code
+ * Returns: code
+ */
+
+int die (char *msg,int code)
+{
+ syslog (LOG_NOTICE,"(%u) %s",code,msg);
+ write (1,"?",1); /* indicate "impossible" failure */
+ return code;
+}
+
+
+int main (int argc,char *argv[])
+{
+ int ld,i;
+ int tries = LOCKTIMEOUT * 60 - 1;
+ char *s,*dir,*file,*lock,*hitch,tmp[1024];
+ size_t dlen,len;
+ struct stat sb,fsb;
+ struct group *grp = getgrnam ("mail");
+ /* get syslog */
+ openlog (argv[0],LOG_PID,LOG_MAIL);
+ if (!grp || (grp->gr_gid != getegid ()))
+ return die ("not setgid mail",EX_USAGE);
+ if (argc != 3) return die ("invalid arguments",EX_USAGE);
+ for (s = argv[1]; *s; s++)
+ if (!isdigit (*s)) return die ("invalid fd",EX_USAGE);
+ /* find directory */
+ if ((*argv[2] != '/') || !(file = strrchr (argv[2],'/')) || !file[1])
+ return die ("invalid path",EX_USAGE);
+ /* calculate lengths of directory and file */
+ if (!(dlen = file - argv[2])) dlen = 1;
+ len = strlen (++file);
+ /* make buffers */
+ dir = (char *) malloc (dlen + 1);
+ lock = (char *) malloc (len + 6);
+ hitch = (char *) malloc (len + 6 + 40 + MAXHOSTNAMELEN);
+ if (!dir || !lock || !hitch) return die ("malloc failure",errno);
+ strncpy (dir,argv[2],dlen); /* connect to desired directory */
+ dir[dlen] = '\0';
+ printf ("dir=%s, file=%s\n",dir,file);
+ chdir (dir);
+ /* get device/inode of file descriptor */
+ if (fstat (atoi (argv[1]),&fsb)) return die ("fstat failure",errno);
+ /* better be a regular file */
+ if ((fsb.st_mode & S_IFMT) != S_IFREG)
+ return die ("fd not regular file",EX_USAGE);
+ /* now get device/inode of file */
+ if (lstat (file,&sb)) return die ("lstat failure",errno);
+ /* does it match? */
+ if ((sb.st_mode & S_IFMT) != S_IFREG)
+ return die ("name not regular file",EX_USAGE);
+ if ((sb.st_dev != fsb.st_dev) || (sb.st_ino != fsb.st_ino))
+ return die ("fd and name different",EX_USAGE);
+ /* build lock filename */
+ sprintf (lock,"%s.lock",file);
+ if (!lstat (lock,&sb) && ((sb.st_mode & S_IFMT) != S_IFREG))
+ return die ("existing lock not regular file",EX_NOPERM);
+
+ do { /* until OK or out of tries */
+ if (!stat (lock,&sb) && (time (0) > (sb.st_ctime + LOCKTIMEOUT * 60)))
+ unlink (lock); /* time out lock if enough time has passed */
+ /* SUN-OS had an NFS
+ * As kludgy as an albatross;
+ * And everywhere that it was installed,
+ * It was a total loss.
+ * -- MRC 9/25/91
+ */
+ /* build hitching post file name */
+ sprintf (hitch,"%s.%lu.%lu.",lock,(unsigned long) time (0),
+ (unsigned long) getpid ());
+ len = strlen (hitch); /* append local host name */
+ gethostname (hitch + len,MAXHOSTNAMELEN);
+ /* try to get hitching-post file */
+ if ((ld = open (hitch,O_WRONLY|O_CREAT|O_EXCL,LOCKPROTECTION)) >= 0) {
+ /* make sure others can break the lock */
+ chmod (hitch,LOCKPROTECTION);
+ /* get device/inode of hitch file */
+ if (fstat (ld,&fsb)) return die ("hitch fstat failure",errno);
+ close (ld); /* close the hitching-post */
+ /* Note: link() may return an error even if it actually succeeded. So we
+ * always check for success via the link count, and ignore the error if
+ * the link count is right.
+ */
+ /* tie hitching-post to lock */
+ i = link (hitch,lock) ? errno : 0;
+ /* success if link count now 2 */
+ if (stat (hitch,&sb) || (sb.st_nlink != 2) ||
+ (fsb.st_dev != sb.st_dev) || (fsb.st_ino != sb.st_ino)) {
+ ld = -1; /* failed to hitch */
+ if (i == EPERM) { /* was it because links not allowed? */
+ /* Probably a FAT filesystem on Linux. It can't be NFS, so try
+ * creating the lock file directly.
+ */
+ if ((ld = open (lock,O_WRONLY|O_CREAT|O_EXCL,LOCKPROTECTION)) >= 0) {
+ /* get device/inode of lock file */
+ if (fstat (ld,&fsb)) return die ("lock fstat failure",errno);
+ close (ld); /* close the file */
+ }
+ /* give up immediately if protection failure */
+ else if (errno != EEXIST) tries = 0;
+ }
+ }
+ unlink (hitch); /* flush hitching post */
+ }
+ /* give up immediately if protection failure */
+ else if (errno == EACCES) tries = 0;
+ if (ld < 0) { /* lock failed */
+ if (tries--) sleep (1); /* sleep 1 second and try again */
+ else {
+ write (1,"-",1); /* hard failure */
+ return EX_CANTCREAT;
+ }
+ }
+ } while (ld < 0);
+ write (1,"+",1); /* indicate that all is well */
+ read (0,tmp,1); /* read continue signal from parent */
+ /* flush the lock file */
+ if (!stat (lock,&sb) && (fsb.st_dev == sb.st_dev) &&
+ (fsb.st_ino == sb.st_ino)) unlink (lock);
+ else syslog (LOG_NOTICE,"lock file %s/%s changed dev/inode",dir,lock);
+ return EX_OK;
+}