[PATCH 1/2] split socket server into a separate process, abrt-server
by Denys Vlasenko
This patch makes abrtd spawn a new process, abrt-server,
for every socket client.
This allows for simpler timeout handling
using SIGALRM, and makes timers for tracking client timeouts
unnecessary.
This also allows for debugging and regression testing
of abrt-server separately - it can be simply run from command-line
and fed commands on stdin.
Also it provides a better fault isolation - crash in
abrt-server does not take down abrtd.
The code is based on dumpsocket.{cpp,h}. Most of dumpsocket.cpp
goes to abrt-server.c, a small part goes to Daemon.cpp (i.e. to abrtd).
This patch will not compile - it does not have dumpsocket.cpp
renamed to abrt-server.c, which makes review easier.
The next patch, which I'll post after this one,
contains only the renaming.
Please review.
--
vda
diff -x '*.po' -d -urpN abrt.2/abrt.spec abrt.3/abrt.spec
--- abrt.2/abrt.spec 2010-09-14 00:00:39.642503695 +0200
+++ abrt.3/abrt.spec 2010-09-13 22:46:24.531493957 +0200
@@ -348,6 +348,7 @@ fi
/lib/systemd/system/%{name}d.service
%endif
%{_sbindir}/abrtd
+%{_sbindir}/abrt-server
%{_bindir}/%{name}-debuginfo-install
%{_bindir}/%{name}-handle-upload
%{_bindir}/%{name}-backtrace
diff -x '*.po' -d -urpN abrt.2/src/daemon/Daemon.cpp abrt.3/src/daemon/Daemon.cpp
--- abrt.2/src/daemon/Daemon.cpp 2010-09-14 00:05:50.820254281 +0200
+++ abrt.3/src/daemon/Daemon.cpp 2010-09-14 00:05:59.569494388 +0200
@@ -19,6 +19,7 @@
#if HAVE_LOCALE_H
# include <locale.h>
#endif
+#include <sys/un.h>
#include <syslog.h>
#include <pthread.h>
#include <resolv.h> /* res_init */
@@ -32,12 +33,20 @@
#include "abrt_exception.h"
#include "CrashWatcher.h"
#include "Daemon.h"
-#include "dumpsocket.h"
#include "rpm.h"
using namespace std;
+#define VAR_RUN_LOCK_FILE VAR_RUN"/abrt/abrtd.lock"
+#define VAR_RUN_PIDFILE VAR_RUN"/abrtd.pid"
+
+#define SOCKET_FILE VAR_RUN"/abrt/abrt.socket"
+#define SOCKET_PERMISSION 0666
+/* Maximum number of simultaneously opened client connections. */
+#define MAX_CLIENT_COUNT 10
+
+
/* Daemon initializes, then sits in glib main loop, waiting for events.
* Events can be:
* - inotify: something new appeared under /var/spool/abrt
@@ -77,12 +86,129 @@ using namespace std;
* If set_client_name(NULL) was done, they are not sent.
*/
+CCommLayerServer* g_pCommLayer;
-#define VAR_RUN_LOCK_FILE VAR_RUN"/abrt/abrtd.lock"
-#define VAR_RUN_PIDFILE VAR_RUN"/abrtd.pid"
+static bool daemonize = true;
+static volatile sig_atomic_t s_sig_caught;
+static int s_signal_pipe[2];
+static int s_signal_pipe_write = -1;
+static int s_upload_watch = -1;
+static unsigned s_timeout;
+static bool s_exiting;
+
+static GIOChannel *socket_channel = NULL;
+static guint socket_channel_cb_id = 0;
+static int socket_client_count = 0;
+
+
+/* Helpers */
+
+static guint add_watch_or_die(GIOChannel *channel, unsigned condition, GIOFunc func)
+{
+ errno = 0;
+ guint r = g_io_add_watch(channel, (GIOCondition)condition, func, NULL);
+ if (!r)
+ perror_msg_and_die("g_io_add_watch failed");
+ return r;
+}
+
+
+/* Socket handling */
+
+/* Callback called by glib main loop when a client connects to ABRT's socket. */
+static gboolean server_socket_cb(GIOChannel *source, GIOCondition condition, gpointer ptr_unused)
+{
+ /* Check the limit for number of simultaneously attached clients. */
+ if (socket_client_count >= MAX_CLIENT_COUNT)
+ {
+ error_msg("Too many clients, refusing connections to '%s'", SOCKET_FILE);
+ /* To avoid infinite loop caused by the descriptor in "ready" state,
+ * the callback must be disabled.
+ * It is added back in client_free(). */
+ g_source_remove(socket_channel_cb_id);
+ socket_channel_cb_id = 0;
+ return TRUE;
+ }
+
+ int socket = accept(g_io_channel_unix_get_fd(source), NULL, NULL);
+ if (socket == -1)
+ {
+ perror_msg("accept");
+ return TRUE;
+ }
+
+ log("New client connected");
+ pid_t pid = fork();
+ if (pid < 0)
+ {
+ close(socket);
+ perror_msg("fork");
+ return TRUE;
+ }
+ if (pid == 0) /* child */
+ {
+ xmove_fd(socket, 0);
+ xdup2(0, 1);
+
+ char *argv[3]; /* abrt-server [-s] NULL */
+ char **pp = argv;
+ *pp++ = (char*)"abrt-server";
+ if (logmode & LOGMODE_SYSLOG)
+ *pp++ = (char*)"-s";
+ *pp = NULL;
+
+ execvp(argv[0], argv);
+ perror_msg_and_die("Can't execute '%s'", argv[0]);
+ }
+ /* parent */
+ socket_client_count++;
+ close(socket);
+ return TRUE;
+}
+
+/* Initializes the dump socket, usually in /var/run directory
+ * (the path depends on compile-time configuration).
+ */
+static void dumpsocket_init()
+{
+ unlink(SOCKET_FILE); /* not caring about the result */
+
+ int socketfd = xsocket(AF_UNIX, SOCK_STREAM, 0);
+ close_on_exec_on(socketfd);
+
+ struct sockaddr_un local;
+ memset(&local, 0, sizeof(local));
+ local.sun_family = AF_UNIX;
+ strcpy(local.sun_path, SOCKET_FILE);
+ xbind(socketfd, (struct sockaddr*)&local, sizeof(local));
+ xlisten(socketfd, MAX_CLIENT_COUNT);
+
+ if (chmod(SOCKET_FILE, SOCKET_PERMISSION) != 0)
+ perror_msg_and_die("chmod '%s'", SOCKET_FILE);
+
+ socket_channel = g_io_channel_unix_new(socketfd);
+ g_io_channel_set_close_on_unref(socket_channel, TRUE);
+ socket_channel_cb_id = add_watch_or_die(socket_channel, G_IO_IN | G_IO_PRI, server_socket_cb);
+}
+
+/* Releases all resources used by dumpsocket. */
+static void dumpsocket_shutdown()
+{
+ /* Set everything to pre-initialization state. */
+ if (socket_channel)
+ {
+ /* Undo add_watch_or_die */
+ g_source_remove(socket_channel_cb_id);
+ /* Undo g_io_channel_unix_new */
+ g_io_channel_unref(socket_channel);
+ socket_channel = NULL;
+ }
+}
+
+
+/* Cron handling */
-//FIXME: add some struct to be able to join all threads!
typedef struct cron_callback_data_t
{
std::string m_sPluginName;
@@ -99,17 +225,6 @@ typedef struct cron_callback_data_t
{}
} cron_callback_data_t;
-
-static volatile sig_atomic_t s_sig_caught;
-static int s_signal_pipe[2];
-static int s_signal_pipe_write = -1;
-static int s_upload_watch = -1;
-static unsigned s_timeout;
-static bool s_exiting;
-
-CCommLayerServer* g_pCommLayer;
-
-
static void cron_delete_callback_data_cb(gpointer data)
{
cron_callback_data_t* cronDeleteCallbackData = static_cast<cron_callback_data_t*>(data);
@@ -392,7 +507,7 @@ static int Lock()
/* we leak opened lfd intentionally */
}
-static void handle_fatal_signal(int signo)
+static void handle_signal(int signo)
{
// Enable for debugging only, malloc/printf are unsafe in signal handlers
//VERB3 log("Got signal %d", signo);
@@ -415,7 +530,18 @@ static gboolean handle_signal_cb(GIOChan
{
/* we did receive a signal */
VERB3 log("Got signal %d through signal pipe", signo);
- s_exiting = 1;
+ if (signo != SIGCHLD)
+ s_exiting = 1;
+ else
+ {
+ if (socket_client_count)
+ socket_client_count--;
+ if (!socket_channel_cb_id)
+ {
+ log("Accepting connections on '%s'", SOCKET_FILE);
+ socket_channel_cb_id = add_watch_or_die(socket_channel, G_IO_IN | G_IO_PRI, server_socket_cb);
+ }
+ }
return TRUE;
}
return FALSE;
@@ -739,7 +865,6 @@ static void sanitize_dump_dir_rights()
int main(int argc, char** argv)
{
- bool daemonize = true;
int opt;
int parent_pid = getpid();
@@ -753,6 +878,10 @@ int main(int argc, char** argv)
if (getuid() != 0)
error_msg_and_die("ABRT daemon must be run as root");
+ char *env_verbose = getenv("ABRT_VERBOSE");
+ if (env_verbose)
+ g_verbose = atoi(env_verbose);
+
while ((opt = getopt(argc, argv, "dsvt:")) != -1)
{
unsigned long ul;
@@ -787,15 +916,18 @@ int main(int argc, char** argv)
}
}
+ putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose));
+
msg_prefix = "abrtd"; /* for log(), error_msg() and such */
xpipe(s_signal_pipe);
close_on_exec_on(s_signal_pipe[0]);
close_on_exec_on(s_signal_pipe[1]);
- signal(SIGTERM, handle_fatal_signal);
- signal(SIGINT, handle_fatal_signal);
+ signal(SIGTERM, handle_signal);
+ signal(SIGINT, handle_signal);
+ signal(SIGCHLD, handle_signal);
if (s_timeout)
- signal(SIGALRM, handle_fatal_signal);
+ signal(SIGALRM, handle_signal);
/* Daemonize unless -d */
if (daemonize)
@@ -995,7 +1127,7 @@ int main(int argc, char** argv)
g_main_loop_unref(pMainloop);
/* Exiting */
- if (s_sig_caught && s_sig_caught != SIGALRM)
+ if (s_sig_caught && s_sig_caught != SIGALRM && s_sig_caught != SIGCHLD)
{
error_msg_and_die("Got signal %d, exiting", s_sig_caught);
signal(s_sig_caught, SIG_DFL);
diff -x '*.po' -d -urpN abrt.2/src/daemon/dumpsocket.cpp abrt.3/src/daemon/dumpsocket.cpp
--- abrt.2/src/daemon/dumpsocket.cpp 2010-09-07 18:57:31.000000000 +0200
+++ abrt.3/src/daemon/dumpsocket.cpp 2010-09-14 00:08:50.680494743 +0200
@@ -15,184 +15,127 @@
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#include <glib.h>
-#include <sys/un.h>
#include "abrtlib.h"
-#include "dumpsocket.h"
-#include "crash_types.h"
-//#include "abrt_exception.h"
+#include "dump_dir.h"
+#include "crash_types.h" /* FILENAME_foo */
#include "hooklib.h"
-#define SOCKET_FILE VAR_RUN"/abrt/abrt.socket"
-#define SOCKET_PERMISSION 0666
/* Maximal length of backtrace. */
#define MAX_BACKTRACE_SIZE (1024*1024)
-
/* Amount of data received from one client for a message before reporting error. */
#define MAX_MESSAGE_SIZE (4*MAX_BACKTRACE_SIZE)
+/* Maximal number of characters read from socket at once. */
+#define INPUT_BUFFER_SIZE (8*1024)
+/* We exit after this many seconds */
+#define TIMEOUT 10
-/* Maximum number of simultaneously opened client connections. */
-#define MAX_CLIENT_COUNT 10
-/* Interval between checks of client halt, in seconds. */
-#define CLIENT_CHECK_INTERVAL 10
+/*
+Unix socket in ABRT daemon for creating new dump directories.
-/* Interval with no data received from client, after which the client is
- considered halted, in seconds. */
-#define CLIENT_HALT_INTERVAL 10
+Why to use socket for creating dump dirs? Security. When a Python
+script throws unexpected exception, ABRT handler catches it, running
+as a part of that broken Python application. The application is running
+with certain SELinux privileges, for example it can not execute other
+programs, or to create files in /var/cache or anything else required
+to properly fill a dump directory. Adding these privileges to every
+application would weaken the security.
+The most suitable solution is for the Python application
+to open a socket where ABRT daemon is listening, write all relevant
+data to that socket, and close it. ABRT daemon handles the rest.
-/* Maximal number of characters read from socket at once. */
-#define INPUT_BUFFER_SIZE 1024
+** Protocol
-static GIOChannel *channel = NULL;
-static guint channel_cb_id = 0;
-static int client_count = 0;
+Initializing new dump:
+open /var/run/abrt.socket
-/* Information about single socket session. */
-struct client
-{
- /* Client user id */
- uid_t uid;
- /* Buffer for incomplete incoming messages. */
- GByteArray *messagebuf;
- /* Executable. */
- char *executable;
- /* Process ID. */
- int pid;
- char *backtrace;
- /* Python, Ruby etc. */
- char *analyzer;
- /* Directory base name: python (or pyhook), ruby etc. */
- char *basename;
- /* Crash reason.
- * Python example: "CCMainWindow.py:1:<module>:ZeroDivisionError:
- * integer division or modulo by zero"
- */
- char *reason;
- /* Last time some data were received over the socket
- * from the client.
- */
- time_t lastwrite;
- /* Timer checking client halt. */
- guint timer_id;
- /* Client socket callback id. */
- guint socket_id;
- /* Client socket channel */
- GIOChannel *channel;
-};
+Providing dump data (hook writes to the socket):
+-> "PID="
+ number 0 - PID_MAX (/proc/sys/kernel/pid_max)
+ \0
+-> "EXECUTABLE="
+ string (maximum length ~MAX_PATH)
+ \0
+-> "BACKTRACE="
+ string (maximum length 1 MB)
+ \0
+-> "ANALYZER="
+ string (maximum length 100 bytes)
+ \0
+-> "BASENAME="
+ string (maximum length 100 bytes, no slashes)
+ \0
+-> "REASON="
+ string (maximum length 512 bytes)
+ \0
-static gboolean server_socket_cb(GIOChannel *source,
- GIOCondition condition,
- gpointer data);
+Finalizing dump creation:
+-> "DONE"
+ \0
+*/
-/* Releases all memory that belongs to a client session. */
-static void client_free(struct client *client)
-{
- /* Delete the uncompleted message if there is some. */
- g_byte_array_free(client->messagebuf, TRUE);
- free(client->executable);
- free(client->backtrace);
- free(client->analyzer);
- free(client->basename);
- free(client->reason);
- g_source_remove(client->timer_id);
- g_source_remove(client->socket_id);
- g_io_channel_unref(client->channel);
- free(client);
- --client_count;
- if (!channel_cb_id)
- {
- channel_cb_id = g_io_add_watch(channel,
- (GIOCondition)(G_IO_IN | G_IO_PRI),
- (GIOFunc)server_socket_cb,
- NULL);
- if (!channel_cb_id)
- perror_msg_and_die("dumpsocket: Can't add socket watch");
- }
-}
-/* Callback called by glib main loop at regular intervals when
- some client is connected. */
-static gboolean client_check_cb(gpointer data)
-{
- struct client *client = (struct client*)data;
- if (time(NULL) - client->lastwrite > CLIENT_HALT_INTERVAL)
- {
- log("dumpsocket: client socket timeout reached, closing connection");
- client_free(client);
- return FALSE;
- }
- return TRUE;
-}
+/* Buffer for incomplete incoming messages. */
+static char *messagebuf_data = NULL;
+static unsigned messagebuf_len = 0;
+
+static unsigned total_bytes_read = 0;
+
+static uid_t client_uid = (uid_t)-1L;
+
+static int pid;
+static char *executable;
+static char *backtrace;
+/* "python", "ruby" etc. */
+static char *analyzer;
+/* Directory base name: "pyhook", "ruby" etc. */
+static char *dir_basename;
+/* Crash reason.
+ * Python example:
+ * "CCMainWindow.py:1:<module>:ZeroDivisionError: integer division or modulo by zero"
+ */
+static char *reason;
-/* Caller is responsible to free() the returned value. */
-static char *giocondition_to_string(GIOCondition condition)
-{
- struct strbuf *strbuf = strbuf_new();
- if (condition & G_IO_HUP)
- strbuf_append_str(strbuf, "G_IO_HUP | ");
- if (condition & G_IO_ERR)
- strbuf_append_str(strbuf, "G_IO_ERR | ");
- if (condition & G_IO_NVAL)
- strbuf_append_str(strbuf, "G_IO_NVAL | ");
- if (condition & G_IO_IN)
- strbuf_append_str(strbuf, "G_IO_IN | ");
- if (condition & G_IO_OUT)
- strbuf_append_str(strbuf, "G_IO_OUT | ");
- if (condition & G_IO_PRI)
- strbuf_append_str(strbuf, "G_IO_PRI | ");
- if (strbuf->len == 0)
- strbuf_append_str(strbuf, "none");
- else
- {
- /* remove the last " | " */
- strbuf->len -= 3;
- strbuf->buf[strbuf->len] = '\0';
- }
- char *result = strbuf->buf;
- strbuf_free_nobuf(strbuf);
- return result;
-}
/* Create a new debug dump from client session.
* Caller must ensure that all fields in struct client
* are properly filled.
*/
-static void create_debug_dump(struct client *client)
+static void create_debug_dump()
{
/* Create temp directory with the debug dump.
This directory is renamed to final directory name after
all files have been stored into it.
*/
char *path = xasprintf(DEBUG_DUMPS_DIR"/%s-%ld-%u.new",
- client->basename,
+ dir_basename,
(long)time(NULL),
- client->pid);
+ pid);
/* No need to check the path length, as all variables used are limited, and dd_create()
fails if the path is too long. */
- dump_dir_t *dd = dd_init();;
- if (!dd_create(dd, path, client->uid))
+ dump_dir_t *dd = dd_init();
+ if (!dd_create(dd, path, client_uid))
{
dd_delete(dd);
dd_close(dd);
- error_msg_and_die("dumpsocket: Error while creating crash dump %s", path);
+ error_msg_and_die("Error creating crash dump %s", path);
}
- dd_save_text(dd, FILENAME_ANALYZER, client->analyzer);
- dd_save_text(dd, FILENAME_EXECUTABLE, client->executable);
- dd_save_text(dd, FILENAME_BACKTRACE, client->backtrace);
- dd_save_text(dd, FILENAME_REASON, client->reason);
+ dd_save_text(dd, FILENAME_ANALYZER, analyzer);
+ dd_save_text(dd, FILENAME_EXECUTABLE, executable);
+ dd_save_text(dd, FILENAME_BACKTRACE, backtrace);
+ dd_save_text(dd, FILENAME_REASON, reason);
/* Obtain and save the command line. */
- char *cmdline = get_cmdline(client->pid); // never NULL
+ char *cmdline = get_cmdline(pid); // never NULL
dd_save_text(dd, FILENAME_CMDLINE, cmdline);
free(cmdline);
/* Store id of the user whose application crashed. */
char uid_str[sizeof(long) * 3 + 2];
- sprintf(uid_str, "%lu", (long)client->uid);
+ sprintf(uid_str, "%lu", (long)client_uid);
dd_save_text(dd, CD_UID, uid_str);
dd_close(dd);
@@ -204,11 +147,9 @@ static void create_debug_dump(struct cli
strcpy(path, newpath);
free(newpath);
- log("dumpsocket: Saved %s crash dump of pid %u to %s",
- client->analyzer, client->pid, path);
+ log("Saved %s crash dump of pid %u to %s", analyzer, pid, path);
- /* Handle free space checking. */
-//FIXME! needs to use globals, like the rest of daemon does!
+ /* Trim old crash dumps if necessary */
unsigned maxCrashReportsSize = 0;
parse_conf(NULL, &maxCrashReportsSize, NULL, NULL);
if (maxCrashReportsSize > 0)
@@ -252,25 +193,23 @@ static char *try_to_get_string(const cha
return NULL;
const char *contents = message + strlen(tag);
- if ((printable && !printable_str(contents)) ||
- (!allow_slashes && strchr(contents, '/')))
- {
- error_msg("dumpsocket: Received %s contains invalid characters -> skipping", tag);
+ if ((printable && !printable_str(contents))
+ || (!allow_slashes && strchr(contents, '/'))
+ ) {
+ error_msg("Received %s contains invalid characters, skipping", tag);
return NULL;
}
if (strlen(contents) > max_len)
{
- char *max_len_str = g_format_size_for_display(max_len);
- error_msg("dumpsocket: Received %s too long -> trimming to %s", tag, max_len_str);
- g_free(max_len_str);
+ error_msg("Received %s too long, trimming to %lu", tag, (long)max_len);
}
return xstrndup(contents, max_len);
}
/* Handles a message received from client over socket. */
-static void process_message(struct client *client, const char *message)
+static void process_message(const char *message)
{
/* @param tag
* The message identifier. Message starting with it
@@ -287,17 +226,20 @@ static void process_message(struct clien
* Whether to allow slashes to be a part of input.
*/
#define HANDLE_INCOMING_STRING(tag, field, max_len, printable, allow_slashes) \
- char *field = try_to_get_string(message, tag, max_len, printable, allow_slashes); \
- if (field) \
+{ \
+ char *s = try_to_get_string(message, tag, max_len, printable, allow_slashes); \
+ if (s) \
{ \
- free(client->field); \
- client->field = field; \
+ free(field); \
+ field = s; \
+ VERB3 log("Saved %s%s", tag, s); \
return; \
- }
+ } \
+}
HANDLE_INCOMING_STRING("EXECUTABLE=", executable, PATH_MAX, true, true);
HANDLE_INCOMING_STRING("BACKTRACE=", backtrace, MAX_BACKTRACE_SIZE, false, true);
- HANDLE_INCOMING_STRING("BASENAME=", basename, 100, true, false);
+ HANDLE_INCOMING_STRING("BASENAME=", dir_basename, 100, true, false);
HANDLE_INCOMING_STRING("ANALYZER=", analyzer, 100, true, true);
HANDLE_INCOMING_STRING("REASON=", reason, 512, false, true);
@@ -306,261 +248,135 @@ static void process_message(struct clien
/* PID is not handled as a string, we convert it to pid_t. */
if (starts_with(message, "PID="))
{
- /* xatou() cannot be used here, because it would
- * kill whole daemon by non-numeric string.
- */
- char *endptr;
- errno = 0;
- const char *nptr = message + strlen("PID=");
- unsigned long number = strtoul(nptr, &endptr, 10);
- /* pid == 0 is error, the lowest PID is 1. */
- if (errno || nptr == endptr || *endptr != '\0' || number > UINT_MAX || number == 0)
- {
- error_msg("dumpsocket: invalid PID received -> ignoring");
- return;
- }
- client->pid = number;
+ pid = xatou(message + strlen("PID="));
+ if (pid < 1)
+ /* pid == 0 is error, the lowest PID is 1. */
+ error_msg_and_die("Malformed or out-of-range number: '%s'", message + strlen("PID="));
+ VERB3 log("Saved PID %u", pid);
return;
}
/* Creates debug dump if all fields were already provided. */
if (starts_with(message, "DONE"))
{
- if (client->pid == 0 ||
- client->backtrace == NULL ||
- client->executable == NULL ||
- client->analyzer == NULL ||
- client->basename == NULL ||
- client->reason == NULL)
- {
- error_msg("dumpsocket: DONE received, but some data are missing -> ignoring");
- return;
+ if (!pid || !backtrace || !executable
+ || !analyzer || !dir_basename || !reason
+ ) {
+ error_msg_and_die("Got DONE, but some data are missing. Aborting");
}
- create_debug_dump(client);
- return;
+ /* Write out the crash dump. Don't let alarm to interrupt here */
+ alarm(0);
+ create_debug_dump();
+
+ /* Reset alarm and the counter which detects oversized dumps */
+ alarm(TIMEOUT);
+ total_bytes_read = 0;
}
}
-/* Callback called by glib main loop when ABRT receives data that have
- * been written to the socket by some client.
- */
-static gboolean client_socket_cb(GIOChannel *source,
- GIOCondition condition,
- gpointer data)
-{
- struct client *client = (struct client*)data;
+static void dummy_handler(int sig_unused) {}
- /* Detailed logging, useful for debugging. */
- if (g_verbose >= 3)
- {
- char *cond = giocondition_to_string(condition);
- log("dumpsocket: client condition %s", cond);
- free(cond);
- }
+int main(int argc, char **argv)
+{
+ char *env_verbose = getenv("ABRT_VERBOSE");
+ if (env_verbose)
+ g_verbose = atoi(env_verbose);
- /* Handle incoming data. */
- if (condition & (G_IO_IN | G_IO_PRI))
+ enum {
+ OPT_s = (1 << 0),
+ };
+ int optflags = 0;
+ int opt;
+ while ((opt = getopt(argc, argv, "u:vs")) != -1)
{
- guint loop = client->messagebuf->len;
- gsize len;
- gchar buf[INPUT_BUFFER_SIZE];
- GError *err = NULL;
- /* Read data in chunks of size INPUT_BUFFER_SIZE. This allows to limit the number of
- bytes received (to prevent memory exhaustion). */
- do {
- GIOStatus result = g_io_channel_read_chars(source, buf, INPUT_BUFFER_SIZE, &len, &err);
- if (result == G_IO_STATUS_ERROR)
- {
- g_assert(err);
- error_msg("dumpsocket: Error while reading data from client socket: %s", err->message);
- g_error_free(err);
- client_free(client);
- return FALSE;
- }
-
- if (g_verbose >= 3)
- log("dumpsocket: received %zu bytes of data", len);
-
- /* Append the incoming data to the message buffer. */
- g_byte_array_append(client->messagebuf, (guint8*)buf, len);
-
- if (client->messagebuf->len > MAX_MESSAGE_SIZE)
- {
- error_msg("dumpsocket: Message too long.");
- client_free(client);
- return FALSE;
- }
- } while (len > 0);
-
- /* Check, if we received a complete message now. */
- for (; loop < client->messagebuf->len; ++loop)
+ switch (opt)
{
- if (client->messagebuf->data[loop] != '\0')
- continue;
-
- VERB3 log("dumpsocket: Processing message: %s",
- client->messagebuf->data);
-
- /* Process the message. */
- process_message(client, (char*)client->messagebuf->data);
- /* Remove the message including the ending \0 */
- g_byte_array_remove_range(client->messagebuf, 0, loop + 1);
- loop = 0;
+ case 'u':
+ client_uid = xatoi_u(optarg);
+ break;
+ case 'v':
+ g_verbose++;
+ break;
+ case 's':
+ optflags |= OPT_s;
+ break;
+ default:
+ error_msg_and_die(
+ "Usage: abrt-server [-v] [-u UID]\n"
+ "\n(So far only) creates crash dumps"
+ "\nOptions:"
+ "\n\t-v\tVerbose"
+ "\n\t-s\tLog to syslog"
+ "\n\t-u UID\tUse UID as client uid"
+ );
}
-
- /* Update the last write access time */
- client->lastwrite = time(NULL);
- }
-
- /* Handle socket disconnection.
- It is important to do it after handling G_IO_IN, because sometimes
- G_IO_HUP comes together with G_IO_IN. It means that some data arrived
- and then the socket has been closed.
- */
- if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL))
- {
- log("dumpsocket: Socket client disconnected");
- client_free(client);
- return FALSE;
}
- return TRUE;
-}
-
-/* If the status indicates failure, report it. */
-static void check_status(GIOStatus status, GError *err, const char *operation)
-{
- if (status == G_IO_STATUS_NORMAL)
- return;
-
- if (err)
+ putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose));
+ msg_prefix = xasprintf("abrt-server[%u]", getpid());
+ if (optflags & OPT_s)
{
- error_msg("dumpsocket: Error while %s: %s", operation, err->message);
- g_error_free(err);
+ openlog(msg_prefix, 0, LOG_DAEMON);
+ logmode = LOGMODE_SYSLOG;
}
- else
- error_msg("dumpsocket: Error while %s", operation);
-}
-
-/* Initializes a new client session data structure. */
-static struct client *client_new(int socket)
-{
- struct client *client = (struct client*)xzalloc(sizeof(struct client));
-
- /* Get credentials for the socket client. */
- struct ucred cr;
- socklen_t crlen = sizeof(struct ucred);
- if (0 != getsockopt(socket, SOL_SOCKET, SO_PEERCRED, &cr, &crlen))
- perror_msg_and_die("dumpsocket: Failed to get client uid");
- if (crlen != sizeof(struct ucred))
- error_msg_and_die("dumpsocket: Failed to get client uid (crlen)");
- client->uid = cr.uid;
-
- client->messagebuf = g_byte_array_new();
- client->lastwrite = time(NULL);
-
- close_on_exec_on(socket);
- /* Create client IO channel. */
- client->channel = g_io_channel_unix_new(socket);
- g_io_channel_set_close_on_unref(client->channel, TRUE);
-
- /* Set nonblocking access. */
- GError *err = NULL;
- GIOStatus status = g_io_channel_set_flags(client->channel, G_IO_FLAG_NONBLOCK, &err);
- check_status(status, err, "setting NONBLOCK flag");
-
- /* Disable channel encoding to protect binary data. */
- err = NULL;
- status = g_io_channel_set_encoding(client->channel, NULL, &err);
- check_status(status, err, "setting encoding");
-
- /* Start timer to check the client problems. */
- client->timer_id = g_timeout_add_seconds(CLIENT_CHECK_INTERVAL, client_check_cb, client);
- if (!client->timer_id)
- error_msg_and_die("dumpsocket: Can't add client timer");
-
- /* Register client callback. */
- client->socket_id = g_io_add_watch(client->channel,
- (GIOCondition)(G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP | G_IO_NVAL),
- client_socket_cb,
- client);
- if (!client->socket_id)
- error_msg_and_die("dumpsocket: Can't add client socket watch");
-
- ++client_count;
- return client;
-}
+ /* Set up timeout handling */
+ /* Part 1 - need this to make SIGALRM interrupt syscalls
+ * (as opposed to restarting them): I want read syscall to be interrupted
+ */
+ struct sigaction sa;
+ /* sa.sa_flags.SA_RESTART bit is clear: make signal interrupt syscalls */
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = dummy_handler; /* pity, SIG_DFL won't do */
+ sigaction(SIGALRM, &sa, NULL);
+ /* Part 2 - set the timeout per se */
+ alarm(TIMEOUT);
-/* Callback called by glib main loop when a client newly opens ABRT's socket. */
-static gboolean server_socket_cb(GIOChannel *source,
- GIOCondition condition,
- gpointer data)
-{
- /* Check the limit for number of simultaneously attached clients. */
- if (client_count >= MAX_CLIENT_COUNT)
+ if (client_uid == (uid_t)-1L)
{
- error_msg("dumpsocket: Too many clients, refusing connection.");
- /* To avoid infinite loop caused by the descriptor in "ready" state,
- the callback must be disabled.
- It is added back in client_free(). */
- g_source_remove(channel_cb_id);
- channel_cb_id = 0;
- return TRUE;
+ /* Get uid of the connected client */
+ struct ucred cr;
+ socklen_t crlen = sizeof(cr);
+ if (0 != getsockopt(STDIN_FILENO, SOL_SOCKET, SO_PEERCRED, &cr, &crlen))
+ perror_msg_and_die("getsockopt(SO_PEERCRED)");
+ if (crlen != sizeof(cr))
+ error_msg_and_die("%s: bad crlen %d", "getsockopt(SO_PEERCRED)", (int)crlen);
+ client_uid = cr.uid;
}
- int socket = accept(g_io_channel_unix_get_fd(source), NULL, NULL);
- if (socket == -1)
+ /* Loop until EOF/error/timeout */
+ while (1)
{
- perror_msg("dumpsocket: Server can not accept client");
- return TRUE;
- }
-
- log("dumpsocket: New client connected");
- client_new(socket);
- return TRUE;
-}
-
-/* Initializes the dump socket, usually in /var/run directory
- * (the path depends on compile-time configuration).
- */
-void dumpsocket_init()
-{
- struct sockaddr_un local;
- unlink(SOCKET_FILE); /* not caring about the result */
- int socketfd = xsocket(AF_UNIX, SOCK_STREAM, 0);
- close_on_exec_on(socketfd);
- memset(&local, 0, sizeof(local));
- local.sun_family = AF_UNIX;
- strcpy(local.sun_path, SOCKET_FILE);
- xbind(socketfd, (struct sockaddr*)&local, sizeof(local));
- xlisten(socketfd, MAX_CLIENT_COUNT);
-
- if (chmod(SOCKET_FILE, SOCKET_PERMISSION) != 0)
- perror_msg_and_die("dumpsocket: failed to chmod socket file");
+ messagebuf_data = xrealloc(messagebuf_data, messagebuf_len + INPUT_BUFFER_SIZE);
+ int rd = read(STDIN_FILENO, messagebuf_data + messagebuf_len, INPUT_BUFFER_SIZE);
+ if (rd < 0)
+ {
+ if (errno == EINTR) /* SIGALRM? */
+ error_msg_and_die("Timed out");
+ perror_msg_and_die("read");
+ }
+ if (rd == 0)
+ break;
- channel = g_io_channel_unix_new(socketfd);
- g_io_channel_set_close_on_unref(channel, TRUE);
- channel_cb_id = g_io_add_watch(channel,
- (GIOCondition)(G_IO_IN | G_IO_PRI),
- server_socket_cb,
- NULL);
- if (!channel_cb_id)
- perror_msg_and_die("dumpsocket: Can't add socket watch");
-}
+ VERB3 log("Received %u bytes of data", rd);
+ messagebuf_len += rd;
+ total_bytes_read += rd;
+ if (total_bytes_read > MAX_MESSAGE_SIZE)
+ error_msg_and_die("Message is too long, aborting");
-/* Releases all resources used by dumpsocket. */
-void dumpsocket_shutdown()
-{
- /* Set everything to pre-initialization state. */
- if (channel)
- {
- /* This one is for g_io_add_watch. */
- if (channel_cb_id)
- g_source_remove(channel_cb_id);
- /* This one is for g_io_channel_unix_new. */
- g_io_channel_unref(channel);
- channel = NULL;
+ while (1)
+ {
+ unsigned len = strnlen(messagebuf_data, messagebuf_len);
+ if (len >= messagebuf_len)
+ break;
+ /* messagebuf has at least one NUL - process the line */
+ process_message(messagebuf_data);
+ messagebuf_len -= (len + 1);
+ memmove(messagebuf_data, messagebuf_data + len + 1, messagebuf_len);
+ }
}
+
+ VERB1 log("EOF detected, exiting");
+ return 0;
}
diff -x '*.po' -d -urpN abrt.2/src/daemon/dumpsocket.h abrt.3/src/daemon/dumpsocket.h
--- abrt.2/src/daemon/dumpsocket.h 2010-09-07 13:34:48.000000000 +0200
+++ abrt.3/src/daemon/dumpsocket.h 1970-01-01 01:00:00.000000000 +0100
@@ -1,81 +0,0 @@
-/*
- Copyright (C) 2010 ABRT team
-
- 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.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-#ifndef ABRT_DUMPSOCKET_H
-#define ABRT_DUMPSOCKET_H
-
-/*
-Unix socket in ABRT daemon for creating new dump directories.
-
-Why to use socket for creating dump dirs? Security. When a Python
-script throws unexpected exception, ABRT handler catches it, running
-as a part of that broken Python application. The application is running
-with certain SELinux privileges, for example it can not execute other
-programs, or to create files in /var/cache or anything else required
-to properly fill a dump directory. Adding these privileges to every
-application would weaken the security.
-The most suitable solution is for the Python application
-to open a socket where ABRT daemon is listening, write all relevant
-data to that socket, and close it. ABRT daemon handles the rest.
-
-** Protocol
-
-Initializing new dump:
-open /var/run/abrt.socket
-
-Providing dump data (hook writes to the socket):
--> "PID="
- number 0 - PID_MAX (/proc/sys/kernel/pid_max)
- \0
--> "EXECUTABLE="
- string (maximum length ~MAX_PATH)
- \0
--> "BACKTRACE="
- string (maximum length 1 MB)
- \0
--> "ANALYZER="
- string (maximum length 100 bytes)
- \0
--> "BASENAME="
- string (maximum length 100 bytes, no slashes)
- \0
--> "REASON="
- string (maximum length 512 bytes)
- \0
-
-Finalizing dump creation:
--> "DONE"
- \0
-*/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Initializes the dump socket, usually in /var/run directory
- * (the path depends on compile-time configuration).
- */
-extern void dumpsocket_init();
-
-/* Releases all resources used by dumpsocket. */
-extern void dumpsocket_shutdown();
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff -x '*.po' -d -urpN abrt.2/src/daemon/Makefile.am abrt.3/src/daemon/Makefile.am
--- abrt.2/src/daemon/Makefile.am 2010-09-14 00:02:49.638494581 +0200
+++ abrt.3/src/daemon/Makefile.am 2010-09-13 22:53:32.190494836 +0200
@@ -1,6 +1,6 @@
bin_SCRIPTS = abrt-debuginfo-install abrt-handle-upload
-sbin_PROGRAMS = abrtd
+sbin_PROGRAMS = abrtd abrt-server
abrtd_SOURCES = \
PluginManager.h PluginManager.cpp \
@@ -10,7 +10,6 @@ abrtd_SOURCES = \
CommLayerServer.h CommLayerServer.cpp \
CommLayerServerDBus.h CommLayerServerDBus.cpp \
Settings.h Settings.cpp \
- dumpsocket.h dumpsocket.cpp \
Daemon.h Daemon.cpp
abrtd_CPPFLAGS = \
-I$(srcdir)/../../inc \
@@ -36,6 +35,23 @@ abrtd_LDADD = \
$(RPM_LIBS) \
$(XMLRPC_LIBS) $(XMLRPC_CLIENT_LIBS)
+abrt_server_SOURCES = \
+ abrt-server.c
+abrt_server_CPPFLAGS = \
+ -I$(srcdir)/../../inc \
+ -I$(srcdir)/../../lib/utils \
+ -DBIN_DIR=\"$(bindir)\" \
+ -DVAR_RUN=\"$(VAR_RUN)\" \
+ -DCONF_DIR=\"$(CONF_DIR)\" \
+ -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
+ -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \
+ -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
+ -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \
+ -D_GNU_SOURCE \
+ -Wall -Werror
+abrt_server_LDADD = \
+ ../../lib/utils/libABRTUtils.la
+
dbusabrtconfdir = ${sysconfdir}/dbus-1/system.d/
dist_dbusabrtconf_DATA = dbus-abrt.conf
13 years, 7 months
[PATCH] make gdb timeout configurable
by Denys Vlasenko
Implemented in a straightforward way. Compile-tested.
Please review.
--
vda
diff -x '*.po' -d -urpN abrt.0/lib/plugins/CCpp.conf abrt.1/lib/plugins/CCpp.conf
--- abrt.0/lib/plugins/CCpp.conf 2010-08-31 14:49:06.000000000 +0200
+++ abrt.1/lib/plugins/CCpp.conf 2010-09-13 14:53:53.659617932 +0200
@@ -11,6 +11,8 @@ SaveBinaryImage = no
# Generate backtrace
Backtrace = yes
+# How long to wait for gdb to finish. Default is 60 seconds.
+# GdbTimeoutSec = 60
# Generate backtrace for crashes uploaded from remote machines.
# Note that for reliable backtrace generation, your local machine
diff -x '*.po' -d -urpN abrt.0/lib/plugins/CCpp.cpp abrt.1/lib/plugins/CCpp.cpp
--- abrt.0/lib/plugins/CCpp.cpp 2010-09-07 18:57:31.000000000 +0200
+++ abrt.1/lib/plugins/CCpp.cpp 2010-09-13 13:51:15.750764456 +0200
@@ -49,7 +49,8 @@ CAnalyzerCCpp::CAnalyzerCCpp() :
m_bBacktraceRemotes(false),
m_bMemoryMap(false),
m_bInstallDebugInfo(true),
- m_nDebugInfoCacheMB(4000)
+ m_nDebugInfoCacheMB(4000),
+ m_nGdbTimeoutSec(60)
{}
static string create_hash(const char *pInput)
@@ -113,7 +114,7 @@ static string create_hash(const char *pI
* @param[out] status See `man 2 wait` for status information.
* @return Malloc'ed string
*/
-static char* exec_vp(char **args, uid_t uid, int redirect_stderr, int *status)
+static char* exec_vp(char **args, uid_t uid, int redirect_stderr, int timeout_sec, int *status)
{
/* Nuke everything which may make setlocale() switch to non-POSIX locale:
* we need to avoid having gdb output in some obscure language.
@@ -143,7 +144,7 @@ static char* exec_vp(char **args, uid_t
* Therefore we have a (largish) timeout, after which we kill the child.
*/
int t = time(NULL); /* int is enough, no need to use time_t */
- int endtime = t + 60;
+ int endtime = t + timeout_sec;
struct strbuf *buf_out = strbuf_new();
@@ -181,7 +182,7 @@ static char* exec_vp(char **args, uid_t
return strbuf_free_nobuf(buf_out);
}
-static char *get_backtrace(const char *pDebugDumpDir, const char *pDebugInfoDirs)
+static char *get_backtrace(const char *pDebugDumpDir, const char *pDebugInfoDirs, int timeout_sec)
{
update_client(_("Generating backtrace"));
@@ -201,7 +202,7 @@ static char *get_backtrace(const char *p
// http://sourceware.org/bugzilla/show_bug.cgi?id=9622
unsetenv("TERM");
// This is not necessary, and was observed to cause
- // environmant corruption (because we run in a thread?):
+ // environment corruption (because we run in a thread?):
//putenv((char*)"TERM=dumb");
char *args[21];
@@ -276,7 +277,7 @@ static char *get_backtrace(const char *p
while (1)
{
args[9] = xasprintf("%s backtrace %u%s", thread_apply_all, bt_depth, full);
- bt = exec_vp(args, xatoi_u(uid), /*redirect_stderr:*/ 1, NULL);
+ bt = exec_vp(args, xatoi_u(uid), /*redirect_stderr:*/ 1, timeout_sec, NULL);
if (bt && (bt_depth <= 64 || strlen(bt) < 256*1024))
{
free(args[9]);
@@ -332,7 +333,7 @@ static void GetIndependentBuildIdPC(cons
}
}
-static char* run_unstrip_n(const char *pDebugDumpDir)
+static char* run_unstrip_n(const char *pDebugDumpDir, int timeout_sec)
{
dump_dir_t *dd = dd_init();
if (!dd_opendir(dd, pDebugDumpDir))
@@ -351,7 +352,7 @@ static char* run_unstrip_n(const char *p
args[2] = (char*)"-n";
args[3] = NULL;
- char *out = exec_vp(args, xatoi_u(uid), /*redirect_stderr:*/ 0, NULL);
+ char *out = exec_vp(args, xatoi_u(uid), /*redirect_stderr:*/ 0, timeout_sec, NULL);
free(uid);
free(args[1]);
@@ -541,7 +542,7 @@ string CAnalyzerCCpp::GetLocalUUID(const
dd_close(dd);
string independentBuildIdPC;
- char *unstrip_n_output = run_unstrip_n(pDebugDumpDir);
+ char *unstrip_n_output = run_unstrip_n(pDebugDumpDir, m_nGdbTimeoutSec);
if (unstrip_n_output)
GetIndependentBuildIdPC(unstrip_n_output, independentBuildIdPC);
else
@@ -811,7 +812,7 @@ void CAnalyzerCCpp::CreateReport(const c
VERB1 log(_("Skipping the debuginfo installation"));
/* Create and store backtrace. */
- char *backtrace_str = get_backtrace(pDebugDumpDir, m_sDebugInfoDirs.c_str());
+ char *backtrace_str = get_backtrace(pDebugDumpDir, m_sDebugInfoDirs.c_str(), m_nGdbTimeoutSec);
if (!backtrace_str)
{
backtrace_str = xstrdup("");
@@ -1109,6 +1110,11 @@ void CAnalyzerCCpp::SetSettings(const ma
{
m_nDebugInfoCacheMB = xatou(it->second.c_str());
}
+ it = pSettings.find("GdbTimeoutSec");
+ if (it != end)
+ {
+ m_nGdbTimeoutSec = xatoi_u(it->second.c_str());
+ }
it = pSettings.find("InstallDebugInfo");
if (it == end) //compat, remove after 0.0.11
it = pSettings.find("InstallDebuginfo");
diff -x '*.po' -d -urpN abrt.0/lib/plugins/CCpp.h abrt.1/lib/plugins/CCpp.h
--- abrt.0/lib/plugins/CCpp.h 2010-08-31 14:49:06.000000000 +0200
+++ abrt.1/lib/plugins/CCpp.h 2010-09-13 13:46:33.410765929 +0200
@@ -34,6 +34,7 @@ class CAnalyzerCCpp : public CAnalyzer
bool m_bMemoryMap;
bool m_bInstallDebugInfo;
unsigned m_nDebugInfoCacheMB;
+ unsigned m_nGdbTimeoutSec;
std::string m_sOldCorePattern;
std::string m_sDebugInfo;
std::string m_sDebugInfoDirs;
13 years, 7 months
elf the pink of fashion. His
by Radomski Bellaire
Lf another drink and light up another cigar--not bad, are they--and
tell me all you've been doing." * * * * * At a quarter to four the
following day Howard put in his appearance at Lady Fitzharford's
house in Eaton Square. "Oh, I'm so glad
you've come," she said: everybody was pleased to see Howard; "you are
just the man
I want. That sweet creature, Miss Heron, is coming here directly to
try over some songs with me--I'm going to sing at that Bazaar, you
know--and as you know something of music--is there anything you don't
know, Mr. Howard?--you can give us your opinion." "Wit
13 years, 7 months
Un nouveau message de Mme Sylvie DUBUISSON, votre attachee commerciale
by Sylvie DUBUISSON
Bonjour,
Je vous contacte aujourdhui pour vous apporter quelques précisions sur notre gamme dannuaires d'entreprises email, fax, téléphone et postal en téléchargement.
Proactive Mail est aujourdhui leader sur le marché des annuaires dentreprises en téléchargement.
NOUVELLES VERSIONS SEPTEMBRE 2010
800 000 E-mails d'entreprises.
800 000 Adresses postales d'entreprises inscrites au Registre National du Commerce et des Sociétés,
780 000 Numéros de téléphone.
425 000 Numéros de fax.
512 000 Dirigeants statutaires.
La gamme est constituée de 3 fichiers ergonomiques et simples d'utilisation qui vous permettront didentifier les prospects à fort potentiel, de constituer des fichiers de prospection avec une segmentation très fine et de créer vos opérations de communication via email, téléphone, fax ou courrier en toute autonomie.
UNE PROSPECTION SIMPLE ET EFFICACE EN 3 ETAPES :
1.EFFECTUEZ VOTRE SELECTION A PARTIR DE 3 GRANDES FAMILLES DE CRITERES :
- Activité :
Proactive Mail est le seul annuaire dentreprises à proposer et à autoriser la combinaison des 3 classifications dactivité suivantes :
Code NAF, familles dactivités selon la nouvelle nomenclature de janvier 2008 et 1820 rubriques professionnelles.
- Zone géographique :
Région, département ou ville
- Eléments financiers :
Chiffre daffaires, tranche deffectifs
2.LANCEZ VOTRE COMPTAGE ET EXPORTEZ VOTRE FICHIER
En quelques secondes vous obtenez le résultat de votre sélection et lexportez sous le format désiré (csv, txt, xls) en indiquant les champs que vous souhaitez exporter :
- Raison sociale
- Adresse aux normes postales
- Téléphone/ Fax (si disponible)
- Email 40% des emails contenus dans nos bases sont des emails génériques,
les 60 autres % sont nominatifs.)
- Nom du dirigeant (si disponible)
- Code NAF et rubrique professionnelle.
Toutes les données contenues dans nos annuaires sont en exportation illimitée !
3.EXPLOITEZ VOS DONNEES
Vous pouvez à partir des fichiers générés réaliser toutes vos opérations de prospection commerciale (phoning, courrier, mailing fax, mailing) à moindre coût.
La gamme Proactive Mail vous permet de prospecter efficacement à partir de 299 ht.
Vous trouverez ci-dessous la grille tarifaire de nos produits.
Version 8 - 800 000 emails d'entreprises en exportation illimitée - 559,95 ht au lieu de 799,95 ht
Version 7 - 700 000 emails d'entreprises en exportation illimitée - 489,95 ht au lieu de 699,95 ht
Version 5 - 500 000 emails d'entreprises en exportation illimitée - 299,95 ht
4.AUTRES DISPONIBILITES
Gamme de fichiers Metiers : Architectes, BtP, Mairies, Business
Gamme de fichiers Europe : Belgiques, Suisse et prochainement Espagne.
Très prochainement : Decideurs informatique, Décideurs RH, Décideurs Comptables et financiers.
Si vous souhaitez un complément dinformation sur nos produits, je me tiens à votre disposition au : 01 70 37 6200
Retrouvez tous nos fichiers sur notre site internet : Pro-activemail [Point] Com
PROACTIVE MAIL est commercialisé par :
Le groupe Media Contact ltd
Tel : 01 70 37 6200
Pour ne plus recevoir de mail de notre part de me sortir de la liste de diffusion en : Cliquant-ici.
Si vous souhaitez vous désabonner, recopiez cette adresse dans la barre d'adresse de votre navigateur :
http://www.reply-fade.net/u-1.1.php?param=3Rbi_1IvEkRQjb1KxE8hY_9NiA2D7kt...
13 years, 7 months
Domaine.fr Hébergement - Votre Serveur Privé Cloud...
by Domaine.fr - Domaine.info
Vendredi 10 septembre 2010
Spécialisé dans les nouvelles technologies d'hébergements
de sites internet, Ihost, plateforme d'hébergement Pro de Domaine.fr vous propose des solutions simples et efficaces jusqu'alors réservées aux seuls professionnels et revendeurs.
Les serveurs privés virtuels (VPS) sont basés sur une
technologie stable.
Gérer efficacement vos sites Internet ou ceux de vos clients
grâce à une interface ludique, conviviale et on ne peut plus simple.
Administrer son VPS devient aussi simple que passer un coup de fil.
Inclus dans chaque pack (99 HT/mois)
Multi domaines Adresse IP fixe
Trafic illimité Extention Fontpage
Accès FTP illimité PHP Perl 5,0 PHP Lib
Répertoire cgi-bin Email POP illimités
Extension SSI Redirection illimités
Fichier logs Logiciel Webmail
Accès SSH PhpMyAdmin 2.5.3
Retrouvez-nous sur :
Pour ne plus recevoir cette lettre de diffusion, envoyez un simple email à news-off(a)domaine.fr
13 years, 7 months
Ther charitably complies, the matter ends with: "T
by Napoli Bromberek
E awaits the coming of the animals. It is difficult to form an idea of
the peculiar excitement of this midnight sport in the thick woods of a
tropical country. The usual stillness of the
night, and the solitude of the wilderness--the croaking of the
night-birds, the movement of every
leaf, animated as it is by the myriads of
nocturnal insects that fill the atmosphere--the brilliant and fleeting
fire-flies travers
13 years, 8 months
[PATCH] SQLite3.cpp: get rid of CABRTException
by Nikola Pajkovsky
Signed-off-by: Nikola Pajkovsky <npajkovs(a)redhat.com>
---
lib/plugins/SQLite3.cpp | 53 +++++++++++++++++++++++++++-------------------
1 files changed, 31 insertions(+), 22 deletions(-)
diff --git a/lib/plugins/SQLite3.cpp b/lib/plugins/SQLite3.cpp
index 4af24c3..a57ec87 100644
--- a/lib/plugins/SQLite3.cpp
+++ b/lib/plugins/SQLite3.cpp
@@ -21,7 +21,6 @@
#include <sqlite3.h>
#include "abrtlib.h"
#include "SQLite3.h"
-#include "abrt_exception.h"
using namespace std;
@@ -177,21 +176,18 @@ static GList *get_table_or_die(sqlite3 *db, const char *fmt, ...)
return table;
}
-static int execute_sql(sqlite3 *db, const char *fmt, ...)
+static int vexecute_sql(sqlite3 *db, const char *fmt, va_list p)
{
- va_list p;
- va_start(p, fmt);
char *sql = xvasprintf(fmt, p);
- va_end(p);
char *err = NULL;
int ret = sqlite3_exec(db, sql, /*callback:*/ NULL, /*callback param:*/ NULL, &err);
if (ret != SQLITE_OK)
{
- string errstr = ssprintf("Error in SQL:'%s' error: %s", sql, err);
+ error_msg("Error in SQL:'%s' error: %s", sql, err);
free(sql);
sqlite3_free(err);
- throw CABRTException(EXCEP_PLUGIN, errstr.c_str());
+ return -1;
}
int affected = sqlite3_changes(db);
VERB2 log("%d rows affected by SQL:%s", affected, sql);
@@ -200,6 +196,19 @@ static int execute_sql(sqlite3 *db, const char *fmt, ...)
return affected;
}
+static int execute_sql_or_die(sqlite3 *db, const char *fmt, ...)
+{
+ va_list p;
+ va_start(p, fmt);
+ int ret = vexecute_sql(db, fmt, p);
+ va_end(p);
+
+ if (ret < 0)
+ xfunc_die();
+
+ return ret;
+}
+
static bool exists_uuid_uid(sqlite3 *db, const char *UUID, const char *UID)
{
GList *table = get_table_or_die(db, "SELECT * FROM "ABRT_TABLE
@@ -310,7 +319,7 @@ static void update_from_old_ver(sqlite3 *db, int old_version)
while (old_version < ABRT_TABLE_VERSION)
{
- execute_sql(db, update_sql_commands[old_version]);
+ execute_sql_or_die(db, update_sql_commands[old_version]);
old_version++;
}
}
@@ -398,7 +407,7 @@ void CSQLite3::Connect()
{
if (ret != SQLITE_CANTOPEN)
{
- throw CABRTException(EXCEP_PLUGIN, "Can't open database '%s': %s", m_sDBPath.c_str(), sqlite3_errmsg(m_pDB));
+ error_msg_and_die("Can't open database '%s': %s", m_sDBPath.c_str(), sqlite3_errmsg(m_pDB));
}
ret = sqlite3_open_v2(m_sDBPath.c_str(),
@@ -408,13 +417,13 @@ void CSQLite3::Connect()
);
if (ret != SQLITE_OK)
{
- throw CABRTException(EXCEP_PLUGIN, "Can't create database '%s': %s", m_sDBPath.c_str(), sqlite3_errmsg(m_pDB));
+ error_msg_and_die("Can't create database '%s': %s", m_sDBPath.c_str(), sqlite3_errmsg(m_pDB));
}
}
if (!check_table(m_pDB))
{
- execute_sql(m_pDB,
+ execute_sql_or_die(m_pDB,
"CREATE TABLE "ABRT_TABLE" ("
COL_UUID" VARCHAR NOT NULL,"
COL_UID" VARCHAR NOT NULL,"
@@ -426,7 +435,7 @@ void CSQLite3::Connect()
COL_MESSAGE" VARCHAR NOT NULL DEFAULT '',"
"PRIMARY KEY ("COL_UUID","COL_UID"));"
);
- execute_sql(m_pDB,
+ execute_sql_or_die(m_pDB,
"CREATE TABLE "ABRT_REPRESULT_TABLE" ("
COL_UUID" VARCHAR NOT NULL,"
COL_UID" VARCHAR NOT NULL,"
@@ -460,7 +469,7 @@ void CSQLite3::Insert_or_Update(const char *crash_id,
if (!exists_uuid_uid(m_pDB, UUID, UID))
{
- execute_sql(m_pDB,
+ execute_sql_or_die(m_pDB,
"INSERT INTO "ABRT_TABLE" ("
COL_UUID","
COL_UID","
@@ -474,7 +483,7 @@ void CSQLite3::Insert_or_Update(const char *crash_id,
}
else
{
- execute_sql(m_pDB,
+ execute_sql_or_die(m_pDB,
"UPDATE "ABRT_TABLE
" SET "COL_COUNT"="COL_COUNT"+1,"COL_TIME"='%s'"
" WHERE "COL_UUID"='%s' AND "COL_UID"='%s';",
@@ -502,11 +511,11 @@ void CSQLite3::DeleteRow(const char *crash_id)
if (exists_uuid_uid(m_pDB, UUID, UID))
{
- execute_sql(m_pDB, "DELETE FROM "ABRT_TABLE
+ execute_sql_or_die(m_pDB, "DELETE FROM "ABRT_TABLE
" WHERE "COL_UUID"='%s' AND "COL_UID"='%s';",
UUID, UID
);
- execute_sql(m_pDB, "DELETE FROM "ABRT_REPRESULT_TABLE
+ execute_sql_or_die(m_pDB, "DELETE FROM "ABRT_REPRESULT_TABLE
" WHERE "COL_UUID"='%s' AND "COL_UID"='%s';",
UUID, UID
);
@@ -540,13 +549,13 @@ void CSQLite3::DeleteRows_by_dir(const char *dump_dir)
for (GList *li = table; li != NULL; li = g_list_next(li))
{
row = (struct db_row*)li->data;
- execute_sql(m_pDB,
+ execute_sql_or_die(m_pDB,
"DELETE FROM "ABRT_REPRESULT_TABLE
" WHERE "COL_UUID"='%s' AND "COL_UID"='%s';",
row->db_uuid, row->db_uid
);
}
- execute_sql(m_pDB,
+ execute_sql_or_die(m_pDB,
"DELETE FROM "ABRT_TABLE
" WHERE "COL_DEBUG_DUMP_PATH"='%s'",
dump_dir
@@ -572,13 +581,13 @@ void CSQLite3::SetReported(const char *crash_id, const char *pMessage)
if (exists_uuid_uid(m_pDB, UUID, UID))
{
- execute_sql(m_pDB,
+ execute_sql_or_die(m_pDB,
"UPDATE "ABRT_TABLE
" SET "COL_REPORTED"=1"
" WHERE "COL_UUID"='%s' AND "COL_UID"='%s';",
UUID, UID
);
- execute_sql(m_pDB,
+ execute_sql_or_die(m_pDB,
"UPDATE "ABRT_TABLE
" SET "COL_MESSAGE"='%s'"
" WHERE "COL_UUID"='%s' AND "COL_UID"='%s';",
@@ -611,7 +620,7 @@ void CSQLite3::SetReportedPerReporter(const char *crash_id,
strncpy(UID, crash_id, uid_len);
UID[uid_len] = '\0';
- int affected_rows = execute_sql(m_pDB,
+ int affected_rows = execute_sql_or_die(m_pDB,
"UPDATE "ABRT_REPRESULT_TABLE
" SET "COL_MESSAGE"='%s'"
" WHERE "COL_UUID"='%s' AND "COL_UID"='%s' AND "COL_REPORTER"='%s'",
@@ -620,7 +629,7 @@ void CSQLite3::SetReportedPerReporter(const char *crash_id,
);
if (!affected_rows)
{
- execute_sql(m_pDB,
+ execute_sql_or_die(m_pDB,
"INSERT INTO "ABRT_REPRESULT_TABLE
" ("COL_UUID","COL_UID","COL_REPORTER","COL_MESSAGE")"
" VALUES ('%s','%s','%s','%s');",
--
1.7.1
13 years, 8 months