Blame view

dotlock/dotlock.c 4.65 KB
Wojciech Polak authored
1
/* GNU Mailutils -- a suite of utilities for electronic mail
2
   Copyright (C) 1999-2002, 2005, 2007-2012, 2014-2016 Free Software
3
   Foundation, Inc.
4

Wojciech Polak authored
5
   GNU Mailutils is free software; you can redistribute it and/or modify
6
   it under the terms of the GNU General Public License as published by
7
   the Free Software Foundation; either version 3, or (at your option)
8 9
   any later version.

Wojciech Polak authored
10
   GNU Mailutils is distributed in the hope that it will be useful,
11 12 13 14 15
   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
16
   along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
17 18 19 20 21 22

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include <stdlib.h>
23
#include <unistd.h>
24 25 26

#include <mailutils/errno.h>
#include <mailutils/locker.h>
Wojciech Polak authored
27
#include <mailutils/nls.h>
28
#include "mailutils/cli.h"
29 30 31 32 33

static const char *file;
static int unlock;
static int flags;
static int retries;
34
static unsigned force;
35 36
static int debug;

37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
static void
cli_force (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
{
  if (arg)
    {
      int rc;
      char *errmsg;
      rc = mu_str_to_c (arg, opt->opt_type, opt->opt_ptr, &errmsg);
      if (rc)
	{
	  if (opt->opt_long)
	    mu_parseopt_error (po, "--%s: %s", opt->opt_long,
			       errmsg ? errmsg : mu_strerror (rc));
	  else
	    mu_parseopt_error (po, "-%c: %s", opt->opt_short,
			       errmsg ? errmsg : mu_strerror (rc));
	  free (errmsg);
	  exit (po->po_exit_error);
	}
    }
  else
    *(unsigned*)opt->opt_ptr = 1;
}

61 62 63 64 65 66 67
static struct mu_option dotlock_options[] = {
  { "unlock", 'u', NULL, MU_OPTION_DEFAULT,
    N_("unlock"),
    mu_c_bool, &unlock },

  { "force",  'f', N_("MINUTES"), MU_OPTION_ARG_OPTIONAL,
    N_("forcibly break an existing lock older than a certain time"),
68
    mu_c_uint, &force, cli_force },
69 70 71 72 73 74 75 76 77 78 79
 
  { "retry",  'r', N_("RETRIES"), MU_OPTION_ARG_OPTIONAL,
    N_("retry the lock a few times"),
    mu_c_int, &retries },

  { "debug",  'd', NULL, MU_OPTION_DEFAULT,
    N_("print details of failure reasons to stderr"), 
    mu_c_bool, &debug },

  MU_OPTION_END
}, *options[] = { dotlock_options, NULL };
80 81

struct mu_cfg_param dotlock_cfg_param[] = {
82
  { "force", mu_c_time, &force, 0, NULL,
83
    N_("Forcibly break an existing lock older than the specified time.") },
84
  { "retry", mu_c_int, &retries, 0, NULL,
85
    N_("Number of times to retry acquiring the lock.") },
86
  { "debug", mu_c_bool, &debug, 0, NULL,
87
    N_("Print details of failure reasons to stderr.") },
88 89
  { NULL }
};
90 91 92 93 94

static struct mu_cli_setup cli = {
  options,
  dotlock_cfg_param,
  N_("GNU dotlock -- lock mail spool files."),
95
  N_("FILE"),
96
  NULL,
97
  N_("Returns 0 on success, 3 if locking the file fails because\
98 99 100
 it's already locked, and 1 if some other kind of error occurred."),
  MU_DL_EX_ERROR,
  MU_DL_EX_ERROR
101
};
102 103 104



105
char *capa[] = {
106
  "debug",
107 108 109
  NULL
};

110 111 112
int
main (int argc, char *argv[])
{
113
  mu_locker_t locker = 0;
114
  int err = 0;
115 116
  pid_t usergid = getgid ();
  pid_t mailgid = getegid ();
117

Wojciech Polak authored
118
  /* Native Language Support */
Sergey Poznyakoff authored
119
  MU_APP_INIT_NLS ();
Wojciech Polak authored
120

121 122
  /* Drop permissions during argument parsing. */

123
  if (setegid (usergid) < 0)
124
    return MU_DL_EX_ERROR;
125

126 127 128 129 130 131 132
  mu_cli (argc, argv, &cli, capa, NULL, &argc, &argv);

  switch (argc)
    {
    case 0:
      mu_error (_("FILE must be specified"));
      exit (MU_DL_EX_ERROR);
133

134 135 136 137 138 139 140 141
    case 1:
      file = argv[0];
      break;

    default:
      mu_error (_("only one FILE can be specified"));
    }
  
142 143 144 145 146
  if (force)
    {
      force *= 60;
      flags |= MU_LOCKER_TIME;
    }
147 148 149

  if (retries != 0)
    flags |= MU_LOCKER_RETRY;
150
  
151
  if ((err = mu_locker_create (&locker, file, flags)))
152 153
    {
      if (debug)
154
	mu_diag_funcall (MU_DIAG_ERROR, "mu_locker_create", NULL, err);
155 156 157 158
      return MU_DL_EX_ERROR;
    }

  if (force != 0)
159
    mu_locker_set_expire_time (locker, force);
160 161

  if (retries != 0)
162
    mu_locker_set_retries (locker, retries);
163

164
  if (setegid (mailgid) < 0)
165 166
    return MU_DL_EX_ERROR;

167
  if (unlock)
168
    err = mu_locker_remove_lock (locker);
169
  else
170
    err = mu_locker_lock (locker);
171

172 173
  setegid(usergid);

174
  mu_locker_destroy (&locker);
175 176

  if (debug && err)
177 178 179
    mu_error (unlock ? _("unlocking the file %s failed: %s") :
	      _("locking the file %s failed: %s"),
	      file, mu_strerror (err));
180 181 182 183 184 185

  switch (err)
    {
    case 0:
      err = MU_DL_EX_OK;
      break;
186 187 188 189 190 191
    case EPERM:
      err = MU_DL_EX_PERM;
      break;
    case MU_ERR_LOCK_NOT_HELD:
      err = MU_DL_EX_NEXIST;
      break;
192 193 194 195 196 197 198 199 200 201
    case MU_ERR_LOCK_CONFLICT:
      err = MU_DL_EX_EXIST;
      break;
    default:
      err = MU_DL_EX_ERROR;
      break;
    }

  return err;
}
202