/*
+ * Copyright notice from original mutt:
* Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
* Copyright (C) 1998-2000 Thomas Roessler <roessler@does-not-exist.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- */
+ *
+ * This file is part of mutt-ng, see http://www.muttng.org/.
+ * It's licensed under the GNU General Public License,
+ * please see the file GPL in the top level source directory.
+ */
/*
* This module either be compiled into Mutt, or it can be
# include "reldate.h"
#endif
-#define MAXLINKS 1024 /* maximum link depth */
+#define MAXLINKS 1024 /* maximum link depth */
#ifdef DL_STANDALONE
extern int snprintf (char *, size_t, const char *, ...);
# endif
-#else /* DL_STANDALONE */
+#else /* DL_STANDALONE */
# ifdef USE_SETGID
# error Do not try to compile dotlock as a mutt module when requiring egid switching!
#define check_flags(a) if (a & DL_FL_ACTIONS) usage (argv[0])
+size_t str_len (const char* s) {
+ return (s ? strlen (s) : 0);
+}
+
int main (int argc, char **argv)
{
int i;
struct utsname utsname;
/* first, drop privileges */
-
+
if (dotlock_init_privs () == -1)
return DL_EX_ERROR;
/* determine the system's host name */
-
+
uname (&utsname);
- if (!(Hostname = strdup (utsname.nodename))) /* __MEM_CHECKED__ */
+ if (!(Hostname = strdup (utsname.nodename))) /* __MEM_CHECKED__ */
return DL_EX_ERROR;
if ((p = strchr (Hostname, '.')))
*p = '\0';
/* parse the command line options. */
DotlockFlags = 0;
-
- while ((i = getopt (argc, argv, "dtfupr:")) != EOF)
- {
- switch (i)
- {
+
+ while ((i = getopt (argc, argv, "dtfupr:")) != EOF) {
+ switch (i) {
/* actions, mutually exclusive */
- case 't': check_flags (DotlockFlags); DotlockFlags |= DL_FL_TRY; break;
- case 'd': check_flags (DotlockFlags); DotlockFlags |= DL_FL_UNLINK; break;
- case 'u': check_flags (DotlockFlags); DotlockFlags |= DL_FL_UNLOCK; break;
+ case 't':
+ check_flags (DotlockFlags);
+ DotlockFlags |= DL_FL_TRY;
+ break;
+ case 'd':
+ check_flags (DotlockFlags);
+ DotlockFlags |= DL_FL_UNLINK;
+ break;
+ case 'u':
+ check_flags (DotlockFlags);
+ DotlockFlags |= DL_FL_UNLOCK;
+ break;
/* other flags */
- case 'f': DotlockFlags |= DL_FL_FORCE; break;
- case 'p': DotlockFlags |= DL_FL_USEPRIV; break;
- case 'r': DotlockFlags |= DL_FL_RETRY; Retry = atoi (optarg); break;
-
- default: usage (argv[0]);
+ case 'f':
+ DotlockFlags |= DL_FL_FORCE;
+ break;
+ case 'p':
+ DotlockFlags |= DL_FL_USEPRIV;
+ break;
+ case 'r':
+ DotlockFlags |= DL_FL_RETRY;
+ Retry = atoi (optarg);
+ break;
+
+ default:
+ usage (argv[0]);
}
}
*/
-static int
-dotlock_init_privs (void)
+static int dotlock_init_privs (void)
{
# ifdef USE_SETGID
-
+
UserGid = getgid ();
MailGid = getegid ();
return 0;
}
-
-#else /* DL_STANDALONE */
+
+#else /* DL_STANDALONE */
/*
* This function is intended to be invoked from within
int r;
DotlockFlags = flags;
-
+
if ((currdir = open (".", O_RDONLY)) == -1)
return DL_EX_ERROR;
Retry = MAXLOCKATTEMPT;
else
Retry = 0;
-
+
r = dotlock_dispatch (path, fd);
-
+
fchdir (currdir);
close (currdir);
-
+
return r;
}
-#endif /* DL_STANDALONE */
+#endif /* DL_STANDALONE */
static int dotlock_dispatch (const char *f, int fd)
return dotlock_unlock (realpath);
else if (DotlockFlags & DL_FL_UNLINK)
return dotlock_unlink (realpath);
- else /* lock */
+ else /* lock */
return dotlock_lock (realpath);
}
-
+
/*
* Get privileges
*
*
*/
-static void
-BEGIN_PRIVILEGED (void)
+static void BEGIN_PRIVILEGED (void)
{
#ifdef USE_SETGID
- if (DotlockFlags & DL_FL_USEPRIV)
- {
- if (SETEGID (MailGid) != 0)
- {
+ if (DotlockFlags & DL_FL_USEPRIV) {
+ if (SETEGID (MailGid) != 0) {
/* perror ("setegid"); */
exit (DL_EX_ERROR);
}
*
*/
-static void
-END_PRIVILEGED (void)
+static void END_PRIVILEGED (void)
{
#ifdef USE_SETGID
- if (DotlockFlags & DL_FL_USEPRIV)
- {
- if (SETEGID (UserGid) != 0)
- {
+ if (DotlockFlags & DL_FL_USEPRIV) {
+ if (SETEGID (UserGid) != 0) {
/* perror ("setegid"); */
exit (DL_EX_ERROR);
}
*
*/
-static void
-usage (const char *av0)
+static void usage (const char *av0)
{
fprintf (stderr, "dotlock [Mutt-ng %s (%s)]\n", VERSION, ReleaseDate);
- fprintf (stderr, "usage: %s [-t|-f|-u|-d] [-p] [-r <retries>] file\n",
- av0);
+ fprintf (stderr, "usage: %s [-t|-f|-u|-d] [-p] [-r <retries>] file\n", av0);
fputs ("\noptions:"
- "\n -t\t\ttry"
- "\n -f\t\tforce"
- "\n -u\t\tunlock"
- "\n -d\t\tunlink"
- "\n -p\t\tprivileged"
+ "\n -t\t\ttry"
+ "\n -f\t\tforce"
+ "\n -u\t\tunlock" "\n -d\t\tunlink" "\n -p\t\tprivileged"
#ifndef USE_SETGID
- " (ignored)"
+ " (ignored)"
#endif
- "\n -r <retries>\tRetry locking"
- "\n", stderr);
-
+ "\n -r <retries>\tRetry locking" "\n", stderr);
+
exit (DL_EX_ERROR);
}
* tlr, Jul 15 1998
*/
-static int
-dotlock_check_stats (struct stat *fsb, struct stat *lsb)
+static int dotlock_check_stats (struct stat *fsb, struct stat *lsb)
{
/* S_ISLNK (fsb->st_mode) should actually be impossible,
* but we may have mixed up the parameters somewhere.
if (S_ISLNK (lsb->st_mode) || S_ISLNK (fsb->st_mode))
return -1;
-
+
if ((lsb->st_dev != fsb->st_dev) ||
- (lsb->st_ino != fsb->st_ino) ||
- (lsb->st_mode != fsb->st_mode) ||
- (lsb->st_nlink != fsb->st_nlink) ||
- (lsb->st_uid != fsb->st_uid) ||
- (lsb->st_gid != fsb->st_gid) ||
- (lsb->st_rdev != fsb->st_rdev) ||
- (lsb->st_size != fsb->st_size))
- {
+ (lsb->st_ino != fsb->st_ino) ||
+ (lsb->st_mode != fsb->st_mode) ||
+ (lsb->st_nlink != fsb->st_nlink) ||
+ (lsb->st_uid != fsb->st_uid) ||
+ (lsb->st_gid != fsb->st_gid) ||
+ (lsb->st_rdev != fsb->st_rdev) || (lsb->st_size != fsb->st_size)) {
/* something's fishy */
return -1;
}
-
+
return 0;
}
-static int
-dotlock_prepare (char *bn, size_t l, const char *f, int _fd)
+static int dotlock_prepare (char *bn, size_t l, const char *f, int _fd)
{
struct stat fsb, lsb;
char realpath[_POSIX_PATH_MAX];
char *p;
int fd;
int r;
-
+
if (dotlock_deference_symlink (realpath, sizeof (realpath), f) == -1)
return -1;
-
- if ((p = strrchr (realpath, '/')))
- {
+
+ if ((p = strrchr (realpath, '/'))) {
*p = '\0';
basename = p + 1;
dirname = realpath;
}
- else
- {
+ else {
basename = realpath;
dirname = ".";
}
- if (strlen (basename) + 1 > l)
+ if (str_len (basename) + 1 > l)
return -1;
-
+
strfcpy (bn, basename, l);
-
+
if (chdir (dirname) == -1)
return -1;
fd = _fd;
else if ((fd = open (basename, O_RDONLY)) == -1)
return -1;
-
+
r = fstat (fd, &fsb);
-
+
if (_fd == -1)
close (fd);
-
+
if (r == -1)
return -1;
-
+
if (lstat (basename, &lsb) == -1)
return -1;
*
*/
-static void
+static void
dotlock_expand_link (char *newpath, const char *path, const char *link)
{
const char *lb = NULL;
size_t len;
/* link is full path */
- if (*link == '/')
- {
+ if (*link == '/') {
strfcpy (newpath, link, _POSIX_PATH_MAX);
return;
}
- if ((lb = strrchr (path, '/')) == NULL)
- {
+ if ((lb = strrchr (path, '/')) == NULL) {
/* no path in link */
strfcpy (newpath, link, _POSIX_PATH_MAX);
return;
*
*/
-static int
-dotlock_deference_symlink (char *d, size_t l, const char *path)
+static int dotlock_deference_symlink (char *d, size_t l, const char *path)
{
struct stat sb;
char realpath[_POSIX_PATH_MAX];
const char *pathptr = path;
int count = 0;
-
- while (count++ < MAXLINKS)
- {
- if (lstat (pathptr, &sb) == -1)
- {
+
+ while (count++ < MAXLINKS) {
+ if (lstat (pathptr, &sb) == -1) {
/* perror (pathptr); */
return -1;
}
-
- if (S_ISLNK (sb.st_mode))
- {
+
+ if (S_ISLNK (sb.st_mode)) {
char linkfile[_POSIX_PATH_MAX];
char linkpath[_POSIX_PATH_MAX];
int len;
- if ((len = readlink (pathptr, linkfile, sizeof (linkfile))) == -1)
- {
- /* perror (pathptr); */
- return -1;
+ if ((len = readlink (pathptr, linkfile, sizeof (linkfile))) == -1) {
+ /* perror (pathptr); */
+ return -1;
}
-
+
linkfile[len] = '\0';
dotlock_expand_link (linkpath, pathptr, linkfile);
strfcpy (realpath, linkpath, sizeof (realpath));
#define HARDMAXATTEMPTS 10
-static int
-dotlock_lock (const char *realpath)
+static int dotlock_lock (const char *realpath)
{
char lockfile[_POSIX_PATH_MAX + LONG_STRING];
char nfslockfile[_POSIX_PATH_MAX + LONG_STRING];
int hard_count = 0;
struct stat sb;
time_t t;
-
+
snprintf (nfslockfile, sizeof (nfslockfile), "%s.%s.%d",
- realpath, Hostname, (int) getpid ());
+ realpath, Hostname, (int) getpid ());
snprintf (lockfile, sizeof (lockfile), "%s.lock", realpath);
-
+
BEGIN_PRIVILEGED ();
unlink (nfslockfile);
- while ((fd = open (nfslockfile, O_WRONLY | O_EXCL | O_CREAT, 0)) < 0)
- {
+ while ((fd = open (nfslockfile, O_WRONLY | O_EXCL | O_CREAT, 0)) < 0) {
END_PRIVILEGED ();
-
- if (errno != EAGAIN)
- {
+
+ if (errno != EAGAIN) {
/* perror ("cannot open NFS lock file"); */
return DL_EX_ERROR;
}
-
+
BEGIN_PRIVILEGED ();
}
END_PRIVILEGED ();
-
+
close (fd);
-
- while (hard_count++ < HARDMAXATTEMPTS)
- {
+
+ while (hard_count++ < HARDMAXATTEMPTS) {
BEGIN_PRIVILEGED ();
link (nfslockfile, lockfile);
END_PRIVILEGED ();
- if (stat (nfslockfile, &sb) != 0)
- {
+ if (stat (nfslockfile, &sb) != 0) {
/* perror ("stat"); */
return DL_EX_ERROR;
}
if (count == 0)
prev_size = sb.st_size;
- if (prev_size == sb.st_size && ++count > Retry)
- {
- if (DotlockFlags & DL_FL_FORCE)
- {
- BEGIN_PRIVILEGED ();
- unlink (lockfile);
- END_PRIVILEGED ();
+ if (prev_size == sb.st_size && ++count > Retry) {
+ if (DotlockFlags & DL_FL_FORCE) {
+ BEGIN_PRIVILEGED ();
+ unlink (lockfile);
+ END_PRIVILEGED ();
- count = 0;
- continue;
+ count = 0;
+ continue;
}
- else
- {
- BEGIN_PRIVILEGED ();
- unlink (nfslockfile);
- END_PRIVILEGED ();
- return DL_EX_EXIST;
+ else {
+ BEGIN_PRIVILEGED ();
+ unlink (nfslockfile);
+ END_PRIVILEGED ();
+ return DL_EX_EXIST;
}
}
-
+
prev_size = sb.st_size;
-
+
/* don't trust sleep (3) as it may be interrupted
* by users sending signals.
*/
-
+
t = time (NULL);
do {
sleep (1);
*
*/
-static int
-dotlock_unlock (const char *realpath)
+static int dotlock_unlock (const char *realpath)
{
char lockfile[_POSIX_PATH_MAX + LONG_STRING];
int i;
- snprintf (lockfile, sizeof (lockfile), "%s.lock",
- realpath);
-
+ snprintf (lockfile, sizeof (lockfile), "%s.lock", realpath);
+
BEGIN_PRIVILEGED ();
i = unlink (lockfile);
END_PRIVILEGED ();
-
+
if (i == -1)
return DL_EX_ERROR;
-
+
return DL_EX_OK;
}
/* remove an empty file */
-static int
-dotlock_unlink (const char *realpath)
+static int dotlock_unlink (const char *realpath)
{
struct stat lsb;
int i = -1;
dotlock_unlock (realpath);
- return (i == 0) ? DL_EX_OK : DL_EX_ERROR;
+ return (i == 0) ? DL_EX_OK : DL_EX_ERROR;
}
*
*/
-static int
-dotlock_try (void)
+static int dotlock_try (void)
{
#ifdef USE_SETGID
struct stat sb;
return DL_EX_OK;
#ifdef USE_SETGID
- if (stat (".", &sb) == 0)
- {
+ if (stat (".", &sb) == 0) {
if ((sb.st_mode & S_IWGRP) == S_IWGRP && sb.st_gid == MailGid)
return DL_EX_NEED_PRIVS;
}