Blame view

comsat/comsat.c 15.3 KB
1
/* GNU Mailutils -- a suite of utilities for electronic mail
2 3
   Copyright (C) 1999, 2000, 2001, 2002, 2005, 2007, 2008, 2009, 2010
   Free Software Foundation, Inc.
Sergey Poznyakoff authored
4

5
   GNU Mailutils is free software; you can redistribute it and/or modify
Sergey Poznyakoff authored
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)
Sergey Poznyakoff authored
8 9
   any later version.

10
   GNU Mailutils is distributed in the hope that it will be useful,
Sergey Poznyakoff authored
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/>. */
Sergey Poznyakoff authored
17 18

#include "comsat.h"
19 20
#define MU_CFG_COMPATIBILITY /* This source uses deprecated cfg interfaces */
#include "mailutils/libcfg.h"
21
#include "mailutils/libargp.h"
Sergey Poznyakoff authored
22 23 24

#ifndef PATH_DEV
# define PATH_DEV "/dev"
25
#endif
Sergey Poznyakoff authored
26 27 28 29 30 31 32 33
#ifndef PATH_TTY_PFX
# define PATH_TTY_PFX PATH_DEV
#endif

#ifdef HAVE_UTMP_H
# include <utmp.h>
#endif

34
#ifndef HAVE_GETUTENT_CALLS
35 36
extern void setutent (void);
extern struct utmp *getutent (void);
37 38
#endif

Sergey Poznyakoff authored
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
#ifdef UTMPX
# ifdef HAVE_UTMPX_H
#  include <utmpx.h>
# endif
typedef struct utmpx UTMP;
# define SETUTENT() setutxent()
# define GETUTENT() getutxent()
# define ENDUTENT() endutxent()
#else
typedef struct utmp UTMP;
# define SETUTENT() setutent()
# define GETUTENT() getutent()
# define ENDUTENT() endutent()
#endif

#define MAX_TTY_SIZE (sizeof (PATH_TTY_PFX) + sizeof (((UTMP*)0)->ut_line))

56
const char *program_version = "comsatd (" PACKAGE_STRING ")";
57
static char doc[] = N_("GNU comsatd -- notify users about incoming mail");
58
static char args_doc[] = N_("\n--test MBOX-URL MSG-QID");
59

Sergey Poznyakoff authored
60 61
#define OPT_FOREGROUND 256

62
static struct argp_option options[] = 
Sergey Poznyakoff authored
63
{
Sergey Poznyakoff authored
64 65 66
  { "test", 't', NULL, 0, N_("run in test mode"), 0 },
  { "foreground", OPT_FOREGROUND, 0, 0, N_("remain in foreground"), 0},
  { "inetd",  'i', 0, 0, N_("run in inetd mode"), 0 },
Sergey Poznyakoff authored
67
  { "daemon", 'd', N_("NUMBER"), OPTION_ARG_OPTIONAL,
Sergey Poznyakoff authored
68
    N_("runs in daemon mode with a maximum of NUMBER children"), 0 },
69 70
  { "file", 'f', N_("FILE"), 0,
    N_("read FILE instead of .biffrc"), 0 },
71
  { NULL, 0, NULL, 0, NULL, 0 }
Sergey Poznyakoff authored
72 73
};

74 75
static error_t comsatd_parse_opt (int key, char *arg,
				  struct argp_state *state);
76 77 78 79

static struct argp argp = {
  options,
  comsatd_parse_opt,
80
  args_doc, 
81
  doc,
Sergey Poznyakoff authored
82
  NULL,
83 84
  NULL, NULL
};
Sergey Poznyakoff authored
85

Sergey Poznyakoff authored
86
static const char *comsat_argp_capa[] = {
87
  "common",
88
  "debug",
Sergey Poznyakoff authored
89
  "logging",
90
  "mailbox",
91
  "locking",
Sergey Poznyakoff authored
92 93 94
  NULL
};

Sergey Poznyakoff authored
95 96 97 98 99
#define SUCCESS 0
#define NOT_HERE 1
#define PERMISSION_DENIED 2

int maxlines = 5;
100
char *hostname;
101
const char *username;
102
int require_tty;
103
int biffrc_errors = BIFFRC_ERRORS_TO_TTY | BIFFRC_ERRORS_TO_ERR;
Sergey Poznyakoff authored
104
mu_m_server_t server;
Sergey Poznyakoff authored
105 106 107

static void comsat_init (void);
static int comsat_main (int fd);
108 109
static void notify_user (const char *user, const char *device,
			 const char *path, mu_message_qid_t qid);
110 111
static int find_user (const char *name, char *tty);
static char *mailbox_path (const char *user);
Sergey Poznyakoff authored
112
static int change_user (const char *user);
Sergey Poznyakoff authored
113

Sergey Poznyakoff authored
114
static int reload = 0;
115
int test_mode;
116
char *biffrc = BIFF_RC;
117

118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
static int
biffrc_error_ctl (mu_config_value_t *val, int flag)
{
  int res;
  
  if (mu_cfg_assert_value_type (val, MU_CFG_STRING))
    return 1;
  if (mu_cfg_parse_boolean (val->v.string, &res))
    mu_diag_output (MU_LOG_ERROR, _("not a boolean"));
  else if (res)
    biffrc_errors |= flag;
  else
    biffrc_errors &= ~flag;
  return 0;
}
    
static int
cb_biffrc_errors_to_tty (void *data, mu_config_value_t *val)
{
  return biffrc_error_ctl (val, BIFFRC_ERRORS_TO_TTY);
}

static int
cb_biffrc_errors_to_err (void *data, mu_config_value_t *val)
{
  return biffrc_error_ctl (val, BIFFRC_ERRORS_TO_ERR);
}

146 147
struct mu_cfg_param comsat_cfg_param[] = {
  { "allow-biffrc", mu_cfg_bool, &allow_biffrc, 0, NULL,
Sergey Poznyakoff authored
148
    N_("Read .biffrc file from the user home directory.") },
149
  { "require-tty", mu_cfg_bool, &require_tty, 0, NULL,
150
    N_("Notify only if the user is logged on one of the ttys.") },
151 152 153 154 155 156
  { "biffrc-errors-to-tty", mu_cfg_callback, NULL, 0, cb_biffrc_errors_to_tty,
    N_("Send biffrc errors to user's tty."),
    N_("arg: bool") },
  { "biffrc-errors-to-err", mu_cfg_callback, NULL, 0, cb_biffrc_errors_to_err,
    N_("Send biffrc errors to Mailutils error output."),
    N_("arg: bool") },
157 158 159
  { "max-lines", mu_cfg_int, &maxlines, 0, NULL,
    N_("Maximum number of message body lines to be output.") },
  { "max-requests", mu_cfg_uint, &maxrequests, 0, NULL,
160
    N_("Maximum number of incoming requests per request control interval.") },
161 162 163 164 165 166 167 168 169
  { "request-control-interval", mu_cfg_time, &request_control_interval,
    0, NULL,
    N_("Set control interval.") },
  { "overflow-control-interval", mu_cfg_time, &overflow_control_interval,
    0, NULL,
    N_("Set overflow control interval.") },
  { "overflow-delay-time", mu_cfg_time, &overflow_delay_time,
    0, NULL,
    N_("Time to sleep after the first overflow occurs.") },
Sergey Poznyakoff authored
170 171
  { ".server", mu_cfg_section, NULL, 0, NULL,
    N_("Server configuration.") },
172 173
  { NULL }
};
174

175 176 177
static error_t
comsatd_parse_opt (int key, char *arg, struct argp_state *state)
{
178
  static mu_list_t lst;
Sergey Poznyakoff authored
179

180 181
  switch (key)
    {
Sergey Poznyakoff authored
182
    case 'd':
183
      mu_argp_node_list_new (lst, "mode", "daemon");
Sergey Poznyakoff authored
184
      if (arg)
185
	mu_argp_node_list_new (lst, "max-children", arg);
Sergey Poznyakoff authored
186 187
      break;

188 189 190 191
    case 'f':
      biffrc = arg;
      break;
      
Sergey Poznyakoff authored
192
    case 'i':
193
      mu_argp_node_list_new (lst, "mode", "inetd");
Sergey Poznyakoff authored
194 195 196
      break;

    case OPT_FOREGROUND:
197
      mu_argp_node_list_new (lst, "foreground", "yes");
Sergey Poznyakoff authored
198 199
      break;

200 201 202 203
    case 't':
      test_mode = 1;
      break;
      
Sergey Poznyakoff authored
204 205 206 207 208
    case ARGP_KEY_INIT:
      mu_argp_node_list_init (&lst);
      break;
      
    case ARGP_KEY_FINI:
209
      mu_argp_node_list_finish (lst, NULL, NULL);
Sergey Poznyakoff authored
210 211
      break;

212 213 214 215 216 217
    default:
      return ARGP_ERR_UNKNOWN;
    }
  return 0;
}

218
static RETSIGTYPE
219 220
sig_hup (int sig)
{
Sergey Poznyakoff authored
221 222
  mu_m_server_stop (1);
  reload = 1;
223 224
}

Sergey Poznyakoff authored
225 226 227
void
comsat_init ()
{
228 229
  int rc;

230 231
  /* Register mailbox formats */
  mu_register_all_mbox_formats ();
Sergey Poznyakoff authored
232

233 234 235 236 237 238
  rc = mu_get_host_name (&hostname);
  if (rc)
    {
      mu_diag_funcall (MU_DIAG_ERROR, "mu_get_host_name", NULL, rc);
      exit (EXIT_FAILURE);
    } 
Sergey Poznyakoff authored
239
  /* Set signal handlers */
240 241
  signal (SIGTTOU, SIG_IGN);
  signal (SIGCHLD, SIG_IGN);
Sergey Poznyakoff authored
242 243 244
  signal (SIGHUP, SIG_IGN);	/* Ignore SIGHUP.  */
}

245
int allow_biffrc = 1;            /* Allow per-user biffrc files */
Sergey Poznyakoff authored
246 247 248 249 250 251 252
unsigned maxrequests = 16;       /* Maximum number of request allowed per
			            control interval */
time_t request_control_interval = 10;  /* Request control interval */
time_t overflow_control_interval = 10; /* Overflow control interval */
time_t overflow_delay_time = 5;

void
Sergey Poznyakoff authored
253
comsat_process (char *buffer, size_t rdlen)
Sergey Poznyakoff authored
254
{
Sergey Poznyakoff authored
255 256 257 258
  char tty[MAX_TTY_SIZE];
  char *p;
  char *path = NULL;
  mu_message_qid_t qid;
259

Sergey Poznyakoff authored
260 261 262
  /* Parse the buffer */
  p = strchr (buffer, '@');
  if (!p)
Sergey Poznyakoff authored
263
    {
264
      mu_diag_output (MU_DIAG_ERROR, _("malformed input: %s"), buffer);
Sergey Poznyakoff authored
265
      return;
Sergey Poznyakoff authored
266
    }
Sergey Poznyakoff authored
267
  *p++ = 0;
268

Sergey Poznyakoff authored
269 270 271
  qid = p;
  p = strchr (qid, ':');
  if (p)
Sergey Poznyakoff authored
272
    {
Sergey Poznyakoff authored
273 274
      *p++ = 0;
      path = p;
Sergey Poznyakoff authored
275
    }
Sergey Poznyakoff authored
276 277
    
  if (find_user (buffer, tty) != SUCCESS)
Sergey Poznyakoff authored
278
    {
Sergey Poznyakoff authored
279 280
      if (require_tty)
	return;
281
      tty[0] = 0;
Sergey Poznyakoff authored
282 283
    }

Sergey Poznyakoff authored
284 285
  /* Child: do actual I/O */
  notify_user (buffer, tty, path, qid);
286 287 288
}

int
Sergey Poznyakoff authored
289 290 291
comsat_main (int fd)
{
  int rdlen;
292
  socklen_t len;
293
  struct sockaddr fromaddr;
Sergey Poznyakoff authored
294
  char buffer[216]; /*FIXME: Arbitrary size */
Sergey Poznyakoff authored
295

296 297
  len = sizeof fromaddr;
  rdlen = recvfrom (fd, buffer, sizeof buffer, 0, &fromaddr, &len);
Sergey Poznyakoff authored
298 299 300 301
  if (rdlen <= 0)
    {
      if (errno == EINTR)
	return 0;
302
      mu_diag_output (MU_DIAG_ERROR, "recvfrom: %m");
Sergey Poznyakoff authored
303 304
      return 1;
    }
Sergey Poznyakoff authored
305 306 307 308
  buffer[rdlen] = 0;
  
  if (mu_m_server_check_acl (server, &fromaddr, len))
    return 0;
Sergey Poznyakoff authored
309

Sergey Poznyakoff authored
310 311 312
  comsat_process (buffer, rdlen);
  return 0;
}
313

Sergey Poznyakoff authored
314 315 316 317 318 319 320
static time_t last_request_time;    /* Timestamp of the last received
				       request */
static unsigned reqcount = 0;       /* Number of request received in the
				       current control interval */
static time_t last_overflow_time;   /* Timestamp of last overflow */
static unsigned overflow_count = 0; /* Number of overflows detected during
				       the current interval */
Sergey Poznyakoff authored
321

Sergey Poznyakoff authored
322 323 324 325 326 327 328 329
int
comsat_prefork (int fd, void *data, struct sockaddr *s, int size)
{
  int retval = 0;
  time_t now;
  
  /* Control the request flow */
  if (maxrequests != 0)
Sergey Poznyakoff authored
330
    {
Sergey Poznyakoff authored
331 332 333 334 335 336 337
      now = time (NULL);
      if (reqcount > maxrequests)
	{
	  unsigned delay;

	  delay = overflow_delay_time << (overflow_count + 1);
	  mu_diag_output (MU_DIAG_NOTICE,
338 339
			 ngettext ("too many requests: pausing for %u second",
				   "too many requests: pausing for %u seconds",
Sergey Poznyakoff authored
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
				    delay),
			  delay);
	  /* FIXME: drain the socket? */
	  sleep (delay);
	  reqcount = 0;
	  if (now - last_overflow_time <= overflow_control_interval)
	    {
	      if ((overflow_delay_time << (overflow_count + 2)) >
		  overflow_delay_time)
		++overflow_count;
	    }
	  else
	    overflow_count = 0;
	  last_overflow_time = time (NULL);
	  retval = 1;
	}
Sergey Poznyakoff authored
356

Sergey Poznyakoff authored
357 358 359 360 361 362 363
      if (now - last_request_time <= request_control_interval)
	reqcount++;
      else
	{
	  last_request_time = now;
	  reqcount = 1;
	}
364
    }
Sergey Poznyakoff authored
365 366
  return retval;
}
Sergey Poznyakoff authored
367

Sergey Poznyakoff authored
368 369 370 371 372 373 374
int
comsat_connection (int fd, struct sockaddr *sa, int salen,
		   void *data, mu_ip_server_t srv,
		   time_t to, int transcript)
{
  char *buffer;
  size_t rdlen, size;
Sergey Poznyakoff authored
375

Sergey Poznyakoff authored
376 377 378
  if (mu_udp_server_get_rdata (srv, &buffer, &rdlen))
    return 0;
  if (transcript)
Sergey Poznyakoff authored
379
    {
Sergey Poznyakoff authored
380 381
      char *p = mu_sockaddr_to_astr (sa, salen);
      mu_diag_output (MU_DIAG_INFO,
382 383
		      ngettext ("received %d byte from %s",
				"received %d bytes from %s", rdlen),
Sergey Poznyakoff authored
384 385 386
		      rdlen, p);
      mu_diag_output (MU_DIAG_INFO, "string: %s", buffer);
      free (p);
Sergey Poznyakoff authored
387
    }
Sergey Poznyakoff authored
388 389
  mu_udp_server_get_bufsize (srv, &size);
  if (size < rdlen + 1)
Sergey Poznyakoff authored
390
    {
Sergey Poznyakoff authored
391 392 393
      int rc = mu_udp_server_set_bufsize (srv, rdlen + 1);
      if (rc)
	{
394
	  mu_error (_("cannot resize buffer: %s"), mu_strerror (rc));
Sergey Poznyakoff authored
395 396
	  return 0;
	}
397
    }
Sergey Poznyakoff authored
398 399 400
  buffer[rdlen] = 0;
  comsat_process (buffer, rdlen);
  return 0;
Sergey Poznyakoff authored
401 402 403 404
}

/* NOTE: Do not bother to free allocated memory, as the program exits
   immediately after executing this */
405
static void
406 407
notify_user (const char *user, const char *device, const char *path,
	     mu_message_qid_t qid)
Sergey Poznyakoff authored
408
{
409
  mu_mailbox_t mbox = NULL;
410
  mu_message_t msg;
Sergey Poznyakoff authored
411 412
  int status;

Sergey Poznyakoff authored
413 414
  if (change_user (user))
    return;
Sergey Poznyakoff authored
415 416 417 418 419 420 421 422

  if (!path)
    {
      path = mailbox_path (user);
      if (!path)
	return;
    }

423 424 425
  if ((status = mu_mailbox_create (&mbox, path)) != 0 ||
      (status = mu_mailbox_open (mbox,
				 MU_STREAM_READ|MU_STREAM_QACCESS)) != 0)
Sergey Poznyakoff authored
426
    {
427
      mu_error (_("cannot open mailbox %s: %s"),
428
	      path, mu_strerror (status));
Sergey Poznyakoff authored
429 430 431
      return;
    }

432 433
  status = mu_mailbox_quick_get_message (mbox, qid, &msg);
  if (status)
Sergey Poznyakoff authored
434
    {
435
      mu_error (_("cannot get message (mailbox %s, qid %s): %s"),
436
		path, qid, mu_strerror (status));
437
      return; /* FIXME: Notify the user, anyway */
Sergey Poznyakoff authored
438 439
    }

440
  run_user_action (device, msg);
Sergey Poznyakoff authored
441 442 443
}

/* Search utmp for the local user */
444 445
static int
find_user (const char *name, char *tty)
Sergey Poznyakoff authored
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
{
  UTMP *uptr;
  int status;
  struct stat statb;
  char ftty[MAX_TTY_SIZE];
  time_t last_time = 0;

  status = NOT_HERE;
  sprintf (ftty, "%s/", PATH_TTY_PFX);

  SETUTENT ();

  while ((uptr = GETUTENT ()) != NULL)
    {
#ifdef USER_PROCESS
      if (uptr->ut_type != USER_PROCESS)
	continue;
#endif
      if (!strncmp (uptr->ut_name, name, sizeof(uptr->ut_name)))
	{
	  /* no particular tty was requested */
	  strncpy (ftty + sizeof(PATH_DEV),
		   uptr->ut_line,
		   sizeof (ftty) - sizeof (PATH_DEV) - 2);
	  ftty[sizeof (ftty) - 1] = 0;

472
	  mu_normalize_path (ftty);
473
	  if (strncmp (ftty, PATH_TTY_PFX, strlen (PATH_TTY_PFX)))
Sergey Poznyakoff authored
474 475
	    {
	      /* An attempt to break security... */
476 477
	      mu_diag_output (MU_DIAG_ALERT,
			      _("bad line name in utmp record: %s"), ftty);
Sergey Poznyakoff authored
478 479 480 481 482 483 484
	      return NOT_HERE;
	    }

	  if (stat (ftty, &statb) == 0)
	    {
	      if (!S_ISCHR (statb.st_mode))
		{
485 486
		  mu_diag_output (MU_DIAG_ALERT,
				  _("not a character device: %s"), ftty);
Sergey Poznyakoff authored
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510
		  return NOT_HERE;
		}

	      if (!(statb.st_mode & S_IEXEC))
		{
		  if (status != SUCCESS)
		    status = PERMISSION_DENIED;
		  continue;
		}
	      if (statb.st_atime > last_time)
		{
		  last_time = statb.st_atime;
		  strcpy(tty, ftty);
		  status = SUCCESS;
		}
	      continue;
	    }
	}
    }

  ENDUTENT ();
  return status;
}

Sergey Poznyakoff authored
511
int
512
change_user (const char *user)
Sergey Poznyakoff authored
513 514 515 516 517 518
{
  struct passwd *pw;

  pw = getpwnam (user);
  if (!pw)
    {
519
      mu_diag_output (MU_DIAG_CRIT, _("no such user: %s"), user);
Sergey Poznyakoff authored
520
      return 1;
Sergey Poznyakoff authored
521 522 523 524
    }

  setgid (pw->pw_gid);
  setuid (pw->pw_uid);
525 526
  chdir (pw->pw_dir);
  username = user;
Sergey Poznyakoff authored
527
  return 0;
Sergey Poznyakoff authored
528 529 530 531 532
}

char *
mailbox_path (const char *user)
{
533
  struct mu_auth_data *auth;
Sergey Poznyakoff authored
534
  char *mailbox_name;
535

536 537 538
  auth = mu_get_auth_by_name (user);

  if (!auth)
Sergey Poznyakoff authored
539
    {
540
      mu_diag_output (MU_DIAG_ALERT, _("user nonexistent: %s"), user);
Sergey Poznyakoff authored
541 542 543
      return NULL;
    }

544 545
  mailbox_name = strdup (auth->mailbox);
  mu_auth_data_free (auth);
Sergey Poznyakoff authored
546 547 548
  return mailbox_name;
}

Sergey Poznyakoff authored
549 550 551 552 553 554 555 556

int
main (int argc, char **argv)
{
  int c;
  int ind;

  /* Native Language Support */
Sergey Poznyakoff authored
557
  MU_APP_INIT_NLS ();
Sergey Poznyakoff authored
558

559
  mu_argp_init (NULL, NULL);
Sergey Poznyakoff authored
560 561 562
  comsat_init ();
  mu_acl_cfg_init ();
  mu_m_server_cfg_init ();
563
  mu_m_server_create (&server, program_version);
Sergey Poznyakoff authored
564 565 566 567 568 569 570 571
  mu_m_server_set_type (server, MU_IP_UDP);
  mu_m_server_set_conn (server, comsat_connection);
  mu_m_server_set_prefork (server, comsat_prefork);
  mu_m_server_set_mode (server, MODE_INTERACTIVE);
  mu_m_server_set_max_children (server, 20);
  /* FIXME mu_m_server_set_pidfile (); */
  mu_m_server_set_default_port (server, 512);
  /* FIXME: timeout is not needed. How to disable it? */
572
  mu_log_syslog = 1;
Sergey Poznyakoff authored
573 574 575
  
  if (mu_app_init (&argp, comsat_argp_capa, comsat_cfg_param, argc, argv, 0,
		   &ind, server))
576
    exit (EXIT_FAILURE);
Sergey Poznyakoff authored
577 578 579 580 581 582 583 584

  if (test_mode)
    {
      char *user;
      
      argc -= ind;
      argv += ind;
  
585
      mu_stdstream_strerr_setup (MU_STRERR_STDERR);
586
      biffrc_errors = BIFFRC_ERRORS_TO_ERR;
Sergey Poznyakoff authored
587 588
      if (argc < 2 || argc > 2)
	{
589
	  mu_error (_("mailbox URL and message QID are required in test mode"));
Sergey Poznyakoff authored
590 591 592 593 594 595 596 597 598 599 600 601
	  exit (EXIT_FAILURE);
	}

      user = getenv ("LOGNAME");
      if (!user)
	{
	  user = getenv ("USER");
	  if (!user)
	    {
	      struct passwd *pw = getpwuid (getuid ());
	      if (!pw)
		{
602
		  mu_error (_("cannot determine user name"));
Sergey Poznyakoff authored
603 604 605 606 607
		  exit (EXIT_FAILURE);
		}
	      user = pw->pw_name;
	    }
	}
608

Sergey Poznyakoff authored
609 610
      if (biffrc[0] == '.' && (biffrc[1] == '/' ||
			       (biffrc[1] == '.' && biffrc[2] == '/')))
611 612 613 614 615 616 617 618 619 620 621 622
	{
	  char *cwd = mu_getcwd ();
	  biffrc = mu_make_file_name (cwd, biffrc);
	  if (!biffrc)
	    {
	      mu_error ("%s", mu_strerror (ENOMEM));
	      exit (1);
	    }
	  mu_normalize_path (biffrc);
	  free (cwd);
	}
      
Sergey Poznyakoff authored
623 624 625 626
      notify_user (user, "/dev/tty", argv[0], argv[1]);
      exit (0);
    }
  
627 628
  mu_stdstream_strerr_setup (mu_log_syslog ?
			     MU_STRERR_SYSLOG : MU_STRERR_STDERR);
Sergey Poznyakoff authored
629 630 631 632 633

  if (mu_m_server_mode (server) == MODE_DAEMON)
    {
      if (argv[0][0] != '/')
	mu_diag_output (MU_DIAG_NOTICE,
634
			_("program name is not absolute; reloading will not "
Sergey Poznyakoff authored
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651
			  "be possible"));
      else
	{
	  sigset_t set;

	  mu_m_server_get_sigset (server, &set);
	  sigdelset (&set, SIGHUP);
	  mu_m_server_set_sigset (server, &set);
	  signal (SIGHUP, sig_hup);
	}
      
      mu_m_server_begin (server);
      c = mu_m_server_run (server);
      mu_m_server_end (server);
      mu_m_server_destroy (&server);
      if (reload)
	{
652
	  mu_diag_output (MU_DIAG_NOTICE, _("restarting"));
Sergey Poznyakoff authored
653 654 655 656 657 658 659 660 661 662 663
	  execvp (argv[0], argv);
	}
    }
  else
    {
      chdir ("/");
      c = comsat_main (0);
    }
  
  return c != 0;
}