pcsc-lite  1.8.3
pcscdaemon.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( http://www.linuxnet.com )
3  *
4  * Copyright (C) 1999-2002
5  * David Corcoran <corcoran@linuxnet.com>
6  * Copyright (C) 2002-2011
7  * Ludovic Rousseau <ludovic.rousseau@free.fr>
8  *
9  * $Id: pcscdaemon.c 6105 2011-11-14 10:19:44Z rousseau $
10  */
11 
21 #include "config.h"
22 #include <time.h>
23 #include <signal.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <errno.h>
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #ifdef HAVE_GETOPT_H
33 #include <getopt.h>
34 #endif
35 
36 #include "misc.h"
37 #include "pcsclite.h"
38 #include "pcscd.h"
39 #include "debuglog.h"
40 #include "sd-daemon.h"
41 #include "winscard_msg.h"
42 #include "winscard_svc.h"
43 #include "sys_generic.h"
44 #include "hotplug.h"
45 #include "readerfactory.h"
46 #include "configfile.h"
47 #include "powermgt_generic.h"
48 #include "utils.h"
49 
50 #ifndef TRUE
51 #define TRUE 1
52 #define FALSE 0
53 #endif
54 
55 char AraKiri = FALSE;
56 static char Init = TRUE;
57 char AutoExit = FALSE;
58 char SocketActivated = FALSE;
59 static int ExitValue = EXIT_FAILURE;
60 int HPForceReaderPolling = 0;
61 static int pipefd[] = {-1, -1};
62 
63 /*
64  * Some internal functions
65  */
66 static void at_exit(void);
67 static void clean_temp_files(void);
68 static void signal_reload(int sig);
69 static void signal_trap(int);
70 static void print_version (void);
71 static void print_usage (char const * const);
72 
81 static void SVCServiceRunLoop(void)
82 {
83  int rsp;
84  LONG rv;
85  uint32_t dwClientID; /* Connection ID used to reference the Client */
86 
87  while (TRUE)
88  {
89  switch (rsp = ProcessEventsServer(&dwClientID))
90  {
91 
92  case 0:
93  Log2(PCSC_LOG_DEBUG, "A new context thread creation is requested: %d", dwClientID);
94  rv = CreateContextThread(&dwClientID);
95 
96  if (rv != SCARD_S_SUCCESS)
97  Log1(PCSC_LOG_ERROR, "Problem during the context thread creation");
98  break;
99 
100  case 2:
101  /*
102  * timeout in ProcessEventsServer(): do nothing
103  * this is used to catch the Ctrl-C signal at some time when
104  * nothing else happens
105  */
106  break;
107 
108  case -1:
109  Log1(PCSC_LOG_ERROR, "Error in ProcessEventsServer");
110  break;
111 
112  case -2:
113  /* Nothing to do in case of a syscall interrupted
114  * It happens when SIGUSR1 (reload) or SIGINT (Ctrl-C) is received
115  * We just try again */
116  break;
117 
118  default:
119  Log2(PCSC_LOG_ERROR, "ProcessEventsServer unknown retval: %d",
120  rsp);
121  break;
122  }
123 
124  if (AraKiri)
125  {
126  /* stop the hotpug thread and waits its exit */
127 #ifdef USE_USB
128  (void)HPStopHotPluggables();
129 #endif
130  (void)SYS_Sleep(1);
131 
132  /* now stop all the drivers */
133  RFCleanupReaders();
134  ContextsDeinitialize();
135  at_exit();
136  }
137  }
138 }
139 
140 int main(int argc, char **argv)
141 {
142  int rv;
143  char setToForeground;
144  char HotPlug;
145  char *newReaderConfig;
146  struct stat fStatBuf;
147  int customMaxThreadCounter = 0;
148  int customMaxReaderHandles = 0;
149  int customMaxThreadCardHandles = 0;
150  int opt;
151  int limited_rights = FALSE;
152 #ifdef HAVE_GETOPT_LONG
153  int option_index = 0;
154  static struct option long_options[] = {
155  {"config", 1, NULL, 'c'},
156  {"foreground", 0, NULL, 'f'},
157  {"color", 0, NULL, 'T'},
158  {"help", 0, NULL, 'h'},
159  {"version", 0, NULL, 'v'},
160  {"apdu", 0, NULL, 'a'},
161  {"debug", 0, NULL, 'd'},
162  {"info", 0, NULL, 0},
163  {"error", 0, NULL, 'e'},
164  {"critical", 0, NULL, 'C'},
165  {"hotplug", 0, NULL, 'H'},
166  {"force-reader-polling", optional_argument, NULL, 0},
167  {"max-thread", 1, NULL, 't'},
168  {"max-card-handle-per-thread", 1, NULL, 's'},
169  {"max-card-handle-per-reader", 1, NULL, 'r'},
170  {"auto-exit", 0, NULL, 'x'},
171  {NULL, 0, NULL, 0}
172  };
173 #endif
174 #define OPT_STRING "c:fTdhvaeCHt:r:s:x"
175 
176  newReaderConfig = NULL;
177  setToForeground = FALSE;
178  HotPlug = FALSE;
179 
180  /*
181  * test the version
182  */
183  if (strcmp(PCSCLITE_VERSION_NUMBER, VERSION) != 0)
184  {
185  printf("BUILD ERROR: The release version number PCSCLITE_VERSION_NUMBER\n");
186  printf(" in pcsclite.h (%s) does not match the release version number\n",
188  printf(" generated in config.h (%s) (see configure.in).\n", VERSION);
189 
190  return EXIT_FAILURE;
191  }
192 
193  /*
194  * By default we create a daemon (not connected to any output)
195  * so log to syslog to have error messages.
196  */
197  DebugLogSetLogType(DEBUGLOG_SYSLOG_DEBUG);
198 
199  /* if the process is setuid or setgid it may have some restrictions */
200  limited_rights = (getgid() != getegid()) && (getuid() != 0);
201 
202  /*
203  * Handle any command line arguments
204  */
205 #ifdef HAVE_GETOPT_LONG
206  while ((opt = getopt_long (argc, argv, OPT_STRING, long_options, &option_index)) != -1) {
207 #else
208  while ((opt = getopt (argc, argv, OPT_STRING)) != -1) {
209 #endif
210  switch (opt) {
211 #ifdef HAVE_GETOPT_LONG
212  case 0:
213  if (strcmp(long_options[option_index].name,
214  "force-reader-polling") == 0)
215  HPForceReaderPolling = optarg ? abs(atoi(optarg)) : 1;
216  break;
217 #endif
218  case 'c':
219  if (limited_rights)
220  {
221  Log1(PCSC_LOG_CRITICAL, "Can't use a user specified config file");
222  return EXIT_FAILURE;
223  }
224  Log2(PCSC_LOG_INFO, "using new config file: %s", optarg);
225  newReaderConfig = optarg;
226  break;
227 
228  case 'f':
229  setToForeground = TRUE;
230  /* debug to stdout instead of default syslog */
231  DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
232  Log1(PCSC_LOG_INFO,
233  "pcscd set to foreground with debug send to stdout");
234  break;
235 
236  case 'T':
237  DebugLogSetLogType(DEBUGLOG_STDOUT_COLOR_DEBUG);
238  Log1(PCSC_LOG_INFO, "Force colored logs");
239  break;
240 
241  case 'd':
242  DebugLogSetLevel(PCSC_LOG_DEBUG);
243  break;
244 
245  case 'e':
246  DebugLogSetLevel(PCSC_LOG_ERROR);
247  break;
248 
249  case 'C':
250  DebugLogSetLevel(PCSC_LOG_CRITICAL);
251  break;
252 
253  case 'h':
254  print_usage (argv[0]);
255  return EXIT_SUCCESS;
256 
257  case 'v':
258  print_version ();
259  return EXIT_SUCCESS;
260 
261  case 'a':
262  if (limited_rights)
263  {
264  Log1(PCSC_LOG_CRITICAL, "Can't log APDU (restricted)");
265  return EXIT_FAILURE;
266  }
267  (void)DebugLogSetCategory(DEBUG_CATEGORY_APDU);
268  break;
269 
270  case 'H':
271  /* debug to stdout instead of default syslog */
272  DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
273  HotPlug = TRUE;
274  break;
275 
276  case 't':
277  customMaxThreadCounter = optarg ? atoi(optarg) : 0;
278  if (limited_rights && (customMaxThreadCounter < PCSC_MAX_CONTEXT_THREADS))
279  customMaxThreadCounter = PCSC_MAX_CONTEXT_THREADS;
280  Log2(PCSC_LOG_INFO, "setting customMaxThreadCounter to: %d",
281  customMaxThreadCounter);
282  break;
283 
284  case 'r':
285  customMaxReaderHandles = optarg ? atoi(optarg) : 0;
286  if (limited_rights && (customMaxReaderHandles < PCSC_MAX_READER_HANDLES))
287  customMaxReaderHandles = PCSC_MAX_READER_HANDLES;
288  Log2(PCSC_LOG_INFO, "setting customMaxReaderHandles to: %d",
289  customMaxReaderHandles);
290  break;
291 
292  case 's':
293  customMaxThreadCardHandles = optarg ? atoi(optarg) : 0;
294  if (limited_rights && (customMaxThreadCardHandles < PCSC_MAX_CONTEXT_CARD_HANDLES))
295  customMaxThreadCardHandles = PCSC_MAX_CONTEXT_CARD_HANDLES;
296  Log2(PCSC_LOG_INFO, "setting customMaxThreadCardHandles to: %d",
297  customMaxThreadCardHandles);
298  break;
299 
300  case 'x':
301  AutoExit = TRUE;
302  Log2(PCSC_LOG_INFO, "Auto exit after %d seconds of inactivity",
303  TIME_BEFORE_SUICIDE);
304  break;
305 
306  default:
307  print_usage (argv[0]);
308  return EXIT_FAILURE;
309  }
310 
311  }
312 
313  if (argv[optind])
314  {
315  printf("Unknown option: %s\n", argv[optind]);
316  print_usage(argv[0]);
317  return EXIT_FAILURE;
318  }
319 
320  /*
321  * Check if systemd passed us any file descriptors
322  */
323  rv = sd_listen_fds(0);
324  if (rv > 1)
325  {
326  Log1(PCSC_LOG_CRITICAL, "Too many file descriptors received");
327  return EXIT_FAILURE;
328  }
329  else
330  {
331  if (rv == 1)
332  {
333  SocketActivated = TRUE;
334  Log1(PCSC_LOG_INFO, "Started by systemd");
335  }
336  else
337  SocketActivated = FALSE;
338  }
339 
340  /*
341  * test the presence of /var/run/pcscd/pcscd.comm
342  */
343 
344  rv = stat(PCSCLITE_CSOCK_NAME, &fStatBuf);
345 
346  if (rv == 0)
347  {
348  pid_t pid;
349 
350  /* read the pid file to get the old pid and test if the old pcscd is
351  * still running
352  */
353  pid = GetDaemonPid();
354 
355  if (pid != -1)
356  {
357  if (HotPlug)
358  return SendHotplugSignal();
359 
360  rv = kill(pid, 0);
361  if (0 == rv)
362  {
363  Log1(PCSC_LOG_CRITICAL,
364  "file " PCSCLITE_CSOCK_NAME " already exists.");
365  Log2(PCSC_LOG_CRITICAL,
366  "Another pcscd (pid: %d) seems to be running.", pid);
367  return EXIT_FAILURE;
368  }
369  else
370  if (ESRCH == errno)
371  {
372  /* the old pcscd is dead. make some cleanup */
373  clean_temp_files();
374  }
375  else
376  {
377  /* permission denied or other error */
378  Log2(PCSC_LOG_CRITICAL, "kill failed: %s", strerror(errno));
379  return EXIT_FAILURE;
380  }
381  }
382  else
383  {
384  if (HotPlug)
385  {
386  Log1(PCSC_LOG_CRITICAL, "file " PCSCLITE_RUN_PID " do not exist");
387  Log1(PCSC_LOG_CRITICAL, "Hotplug failed");
388  return EXIT_FAILURE;
389  }
390  }
391  }
392  else
393  if (HotPlug)
394  {
395  Log1(PCSC_LOG_CRITICAL, "Hotplug failed: pcscd is not running");
396  return EXIT_FAILURE;
397  }
398 
399  /* like in daemon(3): changes the current working directory to the
400  * root ("/") */
401  (void)chdir("/");
402 
403  /*
404  * If this is set to one the user has asked it not to fork
405  */
406  if (!setToForeground)
407  {
408  int pid;
409 
410  if (pipe(pipefd) == -1)
411  {
412  Log2(PCSC_LOG_CRITICAL, "pipe() failed: %s", strerror(errno));
413  return EXIT_FAILURE;
414  }
415 
416  pid = fork();
417  if (-1 == pid)
418  {
419  Log2(PCSC_LOG_CRITICAL, "fork() failed: %s", strerror(errno));
420  return EXIT_FAILURE;
421  }
422 
423  /* like in daemon(3): redirect standard input, standard output
424  * and standard error to /dev/null */
425  (void)close(0);
426  (void)close(1);
427  (void)close(2);
428 
429  if (pid)
430  /* in the father */
431  {
432  char buf;
433  int ret;
434 
435  /* close write side */
436  close(pipefd[1]);
437 
438  /* wait for the son to write the return code */
439  ret = read(pipefd[0], &buf, 1);
440  if (ret <= 0)
441  return 2;
442 
443  close(pipefd[0]);
444 
445  /* exit code */
446  return buf;
447  }
448  else
449  /* in the son */
450  {
451  /* close read side */
452  close(pipefd[0]);
453  }
454  }
455 
456  /*
457  * cleanly remove /var/run/pcscd/files when exiting
458  * signal_trap() does just set a global variable used by the main loop
459  */
460  (void)signal(SIGQUIT, signal_trap);
461  (void)signal(SIGTERM, signal_trap); /* default kill signal & init round 1 */
462  (void)signal(SIGINT, signal_trap); /* sent by Ctrl-C */
463 
464  /* exits on SIGALARM to allow pcscd to suicide if not used */
465  (void)signal(SIGALRM, signal_trap);
466 
467  /*
468  * If PCSCLITE_IPC_DIR does not exist then create it
469  */
470  rv = stat(PCSCLITE_IPC_DIR, &fStatBuf);
471  if (rv < 0)
472  {
473  int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU;
474 
475  rv = mkdir(PCSCLITE_IPC_DIR, mode);
476  if (rv != 0)
477  {
478  Log2(PCSC_LOG_CRITICAL,
479  "cannot create " PCSCLITE_IPC_DIR ": %s", strerror(errno));
480  return EXIT_FAILURE;
481  }
482 
483  /* set mode so that the directory is world readable and
484  * executable even is umask is restrictive
485  * The directory containes files used by libpcsclite */
486  (void)chmod(PCSCLITE_IPC_DIR, mode);
487  }
488 
489  /*
490  * Allocate memory for reader structures
491  */
492  rv = RFAllocateReaderSpace(customMaxReaderHandles);
493  if (SCARD_S_SUCCESS != rv)
494  at_exit();
495 
496 #ifdef USE_SERIAL
497  /*
498  * Grab the information from the reader.conf
499  */
500  if (newReaderConfig)
501  {
502  rv = RFStartSerialReaders(newReaderConfig);
503  if (rv != 0)
504  {
505  Log3(PCSC_LOG_CRITICAL, "invalid file %s: %s", newReaderConfig,
506  strerror(errno));
507  at_exit();
508  }
509  }
510  else
511  {
512  rv = RFStartSerialReaders(PCSCLITE_CONFIG_DIR);
513  if (rv == -1)
514  at_exit();
515  }
516 #endif
517 
518  Log1(PCSC_LOG_INFO, "pcsc-lite " VERSION " daemon ready.");
519 
520  /*
521  * Record our pid to make it easier
522  * to kill the correct pcscd
523  *
524  * Do not fork after this point or the stored pid will be wrong
525  */
526  {
527  int f;
528  int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
529 
530  f = open(PCSCLITE_RUN_PID, O_RDWR | O_CREAT, mode);
531  if (f != -1)
532  {
533  char pid[PID_ASCII_SIZE];
534 
535  (void)snprintf(pid, sizeof(pid), "%u\n", (unsigned) getpid());
536  (void)write(f, pid, strlen(pid));
537  (void)close(f);
538 
539  /* set mode so that the file is world readable even is umask is
540  * restrictive
541  * The file is used by libpcsclite */
542  (void)chmod(PCSCLITE_RUN_PID, mode);
543  }
544  else
545  Log2(PCSC_LOG_CRITICAL, "cannot create " PCSCLITE_RUN_PID ": %s",
546  strerror(errno));
547  }
548 
549  /*
550  * post initialistion
551  */
552  Init = FALSE;
553 
554  /*
555  * Hotplug rescan
556  */
557  (void)signal(SIGUSR1, signal_reload);
558 
559  /*
560  * Initialize the comm structure
561  */
562  if (SocketActivated)
563  rv = ListenExistingSocket(SD_LISTEN_FDS_START + 0);
564  else
565  rv = InitializeSocket();
566 
567  if (rv)
568  {
569  Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
570  at_exit();
571  }
572 
573  /*
574  * Initialize the contexts structure
575  */
576  rv = ContextsInitialize(customMaxThreadCounter, customMaxThreadCardHandles);
577 
578  if (rv == -1)
579  {
580  Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
581  at_exit();
582  }
583 
584  (void)signal(SIGPIPE, SIG_IGN);
585  (void)signal(SIGHUP, SIG_IGN); /* needed for Solaris. The signal is sent
586  * when the shell is existed */
587 
588 #if !defined(PCSCLITE_STATIC_DRIVER) && defined(USE_USB)
589  /*
590  * Set up the search for USB/PCMCIA devices
591  */
592  rv = HPSearchHotPluggables();
593  if (rv)
594  at_exit();
595 
596  rv = HPRegisterForHotplugEvents();
597  if (rv)
598  {
599  Log1(PCSC_LOG_ERROR, "HPRegisterForHotplugEvents failed");
600  at_exit();
601  }
602 
603  RFWaitForReaderInit();
604 #endif
605 
606  /*
607  * Set up the power management callback routine
608  */
609  (void)PMRegisterForPowerEvents();
610 
611  /* initialisation succeeded */
612  if (pipefd[1] >= 0)
613  {
614  char buf = 0;
615 
616  /* write a 0 (success) to father process */
617  write(pipefd[1], &buf, 1);
618  close(pipefd[1]);
619  }
620 
622 
623  Log1(PCSC_LOG_ERROR, "SVCServiceRunLoop returned");
624  return EXIT_FAILURE;
625 }
626 
627 static void at_exit(void)
628 {
629  Log1(PCSC_LOG_INFO, "cleaning " PCSCLITE_IPC_DIR);
630 
631  clean_temp_files();
632 
633  if (pipefd[1] >= 0)
634  {
635  char buf;
636 
637  /* write the error code to father process */
638  buf = ExitValue;
639  write(pipefd[1], &buf, 1);
640  close(pipefd[1]);
641  }
642 
643  exit(ExitValue);
644 }
645 
646 static void clean_temp_files(void)
647 {
648  int rv;
649 
650  if (!SocketActivated)
651  {
652  rv = remove(PCSCLITE_CSOCK_NAME);
653  if (rv != 0)
654  Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_CSOCK_NAME ": %s",
655  strerror(errno));
656  }
657 
658  rv = remove(PCSCLITE_RUN_PID);
659  if (rv != 0)
660  Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_RUN_PID ": %s",
661  strerror(errno));
662 }
663 
664 static void signal_reload(/*@unused@*/ int sig)
665 {
666  (void)signal(SIGUSR1, signal_reload);
667 
668  (void)sig;
669 
670  if (AraKiri)
671  return;
672 
673 #ifdef USE_USB
674  HPReCheckSerialReaders();
675 #endif
676 } /* signal_reload */
677 
678 static void signal_trap(int sig)
679 {
680  Log2(PCSC_LOG_INFO, "Received signal: %d", sig);
681 
682  /* do not wait if asked to terminate
683  * avoids waiting after the reader(s) in shutdown for example */
684  if (SIGTERM == sig)
685  {
686  Log1(PCSC_LOG_INFO, "Direct suicide");
687  at_exit();
688  }
689 
690  if (SIGALRM == sig)
691  {
692  /* normal exit without error */
693  ExitValue = EXIT_SUCCESS;
694  }
695 
696  /* the signal handler is called several times for the same Ctrl-C */
697  if (AraKiri == FALSE)
698  {
699  Log1(PCSC_LOG_INFO, "Preparing for suicide");
700  AraKiri = TRUE;
701 
702  /* if still in the init/loading phase the AraKiri will not be
703  * seen by the main event loop
704  */
705  if (Init)
706  {
707  Log1(PCSC_LOG_INFO, "Suicide during init");
708  at_exit();
709  }
710  }
711  else
712  {
713  /* if pcscd do not want to die */
714  static int lives = 2;
715 
716  lives--;
717  /* no live left. Something is blocking the normal death. */
718  if (0 == lives)
719  {
720  Log1(PCSC_LOG_INFO, "Forced suicide");
721  at_exit();
722  }
723  }
724 }
725 
726 static void print_version (void)
727 {
728  printf("%s version %s.\n", PACKAGE, VERSION);
729  printf("Copyright (C) 1999-2002 by David Corcoran <corcoran@linuxnet.com>.\n");
730  printf("Copyright (C) 2001-2011 by Ludovic Rousseau <ludovic.rousseau@free.fr>.\n");
731  printf("Copyright (C) 2003-2004 by Damien Sauveron <sauveron@labri.fr>.\n");
732  printf("Report bugs to <muscle@lists.musclecard.com>.\n");
733 
734  printf ("Enabled features:%s\n", PCSCLITE_FEATURES);
735 }
736 
737 static void print_usage (char const * const progname)
738 {
739  printf("Usage: %s options\n", progname);
740  printf("Options:\n");
741 #ifdef HAVE_GETOPT_LONG
742  printf(" -a, --apdu log APDU commands and results\n");
743  printf(" -c, --config path to reader.conf\n");
744  printf(" -f, --foreground run in foreground (no daemon),\n");
745  printf(" send logs to stdout instead of syslog\n");
746  printf(" -T, --color force use of colored logs\n");
747  printf(" -h, --help display usage information\n");
748  printf(" -H, --hotplug ask the daemon to rescan the available readers\n");
749  printf(" -v, --version display the program version number\n");
750  printf(" -d, --debug display lower level debug messages\n");
751  printf(" --info display info level debug messages\n");
752  printf(" -e --error display error level debug messages (default level)\n");
753  printf(" -C --critical display critical only level debug messages\n");
754  printf(" --force-reader-polling ignore the IFD_GENERATE_HOTPLUG reader capability\n");
755  printf(" -t, --max-thread maximum number of threads (default %d)\n", PCSC_MAX_CONTEXT_THREADS);
756  printf(" -s, --max-card-handle-per-thread maximum number of card handle per thread (default: %d)\n", PCSC_MAX_CONTEXT_CARD_HANDLES);
757  printf(" -r, --max-card-handle-per-reader maximum number of card handle per reader (default: %d)\n", PCSC_MAX_READER_HANDLES);
758  printf(" -x, --auto-exit pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE);
759 #else
760  printf(" -a log APDU commands and results\n");
761  printf(" -c path to reader.conf\n");
762  printf(" -f run in foreground (no daemon), send logs to stdout instead of syslog\n");
763  printf(" -T force use of colored logs\n");
764  printf(" -d display debug messages.\n");
765  printf(" -e display error messages (default level).\n");
766  printf(" -C display critical messages.\n");
767  printf(" -h display usage information\n");
768  printf(" -H ask the daemon to rescan the available readers\n");
769  printf(" -v display the program version number\n");
770  printf(" -t maximum number of threads\n");
771  printf(" -s maximum number of card handle per thread\n");
772  printf(" -r maximum number of card handle per reader\n");
773  printf(" -x pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE);
774 #endif
775 }
776