monotone

monotone Mtn Source Tree

Root/unix/main.cc

1// Copyright (C) 2006 Zack Weinberg <zackw@panix.com>
2// Based on code by Graydon Hoare and contributors
3// Originally derived from execution_monitor.cpp, a part of boost.
4//
5// This program is made available under the GNU GPL version 2.0 or
6// greater. See the accompanying file COPYING for details.
7//
8// This program is distributed WITHOUT ANY WARRANTY; without even the
9// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10// PURPOSE.
11
12
13// This file provides the outermost main(), but it is probable that you want
14// to look at monotone.cc for cpp_main(), where the real program logic
15// begins. The purpose of this file is to hide all the nastiness involved
16// in trapping and responding to operating-system-level hard error reports.
17// It is also responsible for a last-ditch catch(...) clause (which is not
18// _that_ different from what std::terminate() would do, but does get our
19// bug-report message printed.)
20//
21// On Unix, what we care about is signals. Signals come in two varieties:
22// those that indicate a catastrophic program error (SIGSEGV etc) and those
23// that indicate a user-initiated cancellation of processing (SIGINT etc).
24// In a perfect universe, we could simply throw an exception from the signal
25// handler and leave error reporting up to catch clauses out in main().
26// This does work for some platforms and some subset of the signals we care
27// about, but not enough of either to be worth doing. Also, for signals of
28// the first variety, enough program state may already have been mangled
29// that running destructors is unsafe.
30//
31// Furthermore, it is not safe to do anything "complicated" in a signal
32// handler. "Complicated" is a hard thing to define, but as a general rule,
33// accessing global variables of type 'volatile sig_atomic_t' is safe, and
34// so is making some (but not all) system calls, and that's about it. It is
35// known that write, signal, raise, setrlimit, and _exit [ *not* exit ] are
36// safe system calls [ even though some of them are actually libc wrappers ].
37// Two things that are definitely *not* safe are allocating memory and using
38// stdio or iostreams. strsignal() should be safe, but it is conceivable it
39// would allocate memory; should it cause trouble, out it goes.
40
41#include "config.h"
42
43#include <signal.h>
44#include <time.h>
45#include <string.h>
46#include <sys/resource.h>
47#include <unistd.h>
48
49static char const * argv0;
50
51// a convenient wrapper
52inline void
53write_str_to_stderr(const char *s)
54{
55 write(2, s, strlen(s));
56}
57
58// this message should be kept consistent with ui.cc::fatal and
59// win32/main.cc::bug_report_message (it is not exactly the same)
60static void
61bug_report_message()
62{
63 write_str_to_stderr("\nthis is almost certainly a bug in monotone."
64 "\nplease send this error message, the output of '");
65 write_str_to_stderr(argv0);
66 write_str_to_stderr(" --full-version',"
67 "\nand a description of what you were doing to "
68 PACKAGE_BUGREPORT "\n");
69}
70
71// this handler takes signals which would normally trigger a core
72// dump, and prints a slightly more helpful error message first.
73static void
74bug_signal(int signo)
75{
76 write_str_to_stderr(argv0);
77 write_str_to_stderr(": fatal signal: ");
78 write_str_to_stderr(strsignal(signo));
79 bug_report_message();
80 write_str_to_stderr("do not send a core dump, but if you have one, "
81 "\nplease preserve it in case we ask you for "
82 "information from it.\n");
83
84 raise(signo);
85 // The signal has been reset to the default handler by SA_RESETHAND
86 // specified in the sigaction() call, but it's also blocked; it will be
87 // delivered when this function returns.
88}
89
90// User interrupts cause abrupt termination of the process as well, but do
91// not represent a bug in the program. We do intercept the signal in order
92// to print a pretty message. Note that this relies on sqlite's auto-
93// recovery feature (see <http://sqlite.org/lockingv3.html>, notably section
94// 'The Rollback Journal').
95static void
96interrupt_signal(int signo)
97{
98 write_str_to_stderr(argv0);
99 write_str_to_stderr(": operation canceled: ");
100 write_str_to_stderr(strsignal(signo));
101 write_str_to_stderr("\n");
102 raise(signo);
103 // The signal has been reset to the default handler by SA_RESETHAND
104 // specified in the sigaction() call, but it's also blocked; it will be
105 // delivered when this function returns.
106}
107
108// Signals that we handle can indicate either that there is a real bug
109// (bug_signal), or that we should cancel processing in response to an
110// external event (interrupt_signal). NOTE: interrupt_signal returns,
111// and therefore it must not be used for any signal that means
112// processing cannot continue.
113static const int bug_signals[] = {
114 SIGQUIT, SIGILL, SIGABRT, SIGFPE, SIGSEGV, SIGBUS, SIGSYS, SIGTRAP
115};
116#define bug_signals_len (sizeof bug_signals / sizeof bug_signals[0])
117static const int interrupt_signals[] = {
118 SIGHUP, SIGINT, SIGPIPE, SIGTERM
119};
120#define interrupt_signals_len (sizeof interrupt_signals \
121 / sizeof interrupt_signals[0])
122
123
124// This file defines the real main(). It just sets up signal
125// handlers, and then calls cpp_main(), which is in monotone.cc.
126
127extern int
128cpp_main(int argc, char ** argv);
129
130int
131main(int argc, char ** argv)
132{
133 struct sigaction bug_signal_action;
134 struct sigaction interrupt_signal_action;
135 size_t i;
136
137 argv0 = argv[0];
138
139 bug_signal_action.sa_flags = SA_RESETHAND;
140 bug_signal_action.sa_handler = &bug_signal;
141 sigemptyset(&bug_signal_action.sa_mask);
142 for (i = 0; i < bug_signals_len; i++)
143 sigaddset(&bug_signal_action.sa_mask, bug_signals[i]);
144 for (i = 0; i < bug_signals_len; i++)
145 sigaction(bug_signals[i], &bug_signal_action, 0);
146
147 interrupt_signal_action.sa_flags = SA_RESETHAND;
148 interrupt_signal_action.sa_handler = &interrupt_signal;
149 sigemptyset(&interrupt_signal_action.sa_mask);
150 for (i = 0; i < interrupt_signals_len; i++)
151 sigaddset(&interrupt_signal_action.sa_mask, interrupt_signals[i]);
152 for (i = 0; i < interrupt_signals_len; i++)
153 sigaction(interrupt_signals[i], &interrupt_signal_action, 0);
154
155 return cpp_main(argc, argv);
156}
157
158// Local Variables:
159// mode: C++
160// fill-column: 76
161// c-file-style: "gnu"
162// indent-tabs-mode: nil
163// End:
164// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status