From 3af2b1a77d462064faf4a8923baa4b0aedd11836 Mon Sep 17 00:00:00 2001 From: Alban Crequy Date: Mon, 26 Sep 2011 11:02:59 +0100 Subject: [PATCH 1/3] Add dbus-test-tool, currently with "echo" and "spam" modes This is installed by default, but easy to filter out for embedded systems or whatever. Based on earlier work by Simon McVittie and Will Thompson Bug: https://bugs.freedesktop.org/show_bug.cgi?id=34140 --- tools/.gitignore | 1 + tools/Makefile.am | 11 ++ tools/dbus-echo.c | 154 ++++++++++++++++++ tools/dbus-spam.c | 461 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/test-tool.c | 87 ++++++++++ tools/test-tool.h | 30 ++++ tools/tool-common.c | 60 +++++++ tools/tool-common.h | 38 +++++ 8 files changed, 842 insertions(+) create mode 100644 tools/dbus-echo.c create mode 100644 tools/dbus-spam.c create mode 100644 tools/test-tool.c create mode 100644 tools/test-tool.h create mode 100644 tools/tool-common.c create mode 100644 tools/tool-common.h diff --git a/tools/.gitignore b/tools/.gitignore index d7c21af..1e0d987 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -19,3 +19,4 @@ dbus-glib-bindings.h run-with-tmp-session-bus.conf print-introspect dbus-bus-introspect.xml +dbus-test-tool diff --git a/tools/Makefile.am b/tools/Makefile.am index 73d95fc..8d38c29 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -15,6 +15,7 @@ bin_PROGRAMS = \ dbus-launch \ dbus-monitor \ dbus-send \ + dbus-test-tool \ $(NULL) if DBUS_UNIX @@ -76,6 +77,16 @@ dbus_launch_LDADD = \ $(DBUS_X_LIBS) \ $(NULL) +dbus_test_tool_SOURCES = \ + dbus-echo.c \ + dbus-spam.c \ + tool-common.c \ + tool-common.h \ + test-tool.c \ + test-tool.h \ + $(NULL) +dbus_test_tool_LDADD = $(top_builddir)/dbus/libdbus-1.la + EXTRA_DIST = run-with-tmp-session-bus.sh strtoll.c strtoull.c CLEANFILES = \ run-with-tmp-session-bus.conf diff --git a/tools/dbus-echo.c b/tools/dbus-echo.c new file mode 100644 index 0000000..05af601 --- /dev/null +++ b/tools/dbus-echo.c @@ -0,0 +1,154 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-echo.c - a plain libdbus echo server + * + * Copyright © 2003 Philip Blundell + * Copyright © 2011 Nokia Corporation + * Copyright © 2014 Collabora Ltd. + * + * 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 + * + */ + +#include + +#include +#include +#include + +#include + +#include "test-tool.h" +#include "tool-common.h" + +static void +usage (int exit_with) +{ + fprintf (stderr, + "Usage: dbus-test-tool echo [OPTIONS]\n" + "\n" + "Respond to all method calls with an empty reply.\n" + "\n" + "Options:\n" + "\n" + " --name=NAME claim this well-known name first\n" + "\n" + " --sleep=N sleep N milliseconds before sending each reply\n" + "\n" + " --session use the session bus (default)\n" + " --system use the system bus\n" + ); + exit (exit_with); +} + +static DBusHandlerResult +filter (DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + DBusMessage *reply; + int *sleep_ms = user_data; + + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (*sleep_ms > 0) + { + tool_millisleep (*sleep_ms); + } + + reply = dbus_message_new_method_return (message); + + if (reply == NULL) + tool_oom ("allocating reply"); + + if (!dbus_connection_send (connection, reply, NULL)) + tool_oom ("sending reply"); + + dbus_message_unref (reply); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +int +dbus_test_tool_echo (int argc, char **argv) +{ + DBusConnection *connection; + DBusError error = DBUS_ERROR_INIT; + DBusBusType type = DBUS_BUS_SESSION; + int i; + int sleep_ms = -1; + const char *name = NULL; + + /* argv[1] is the tool name, so start from 2 */ + + for (i = 2; i < argc; i++) + { + const char *arg = argv[i]; + + if (strcmp (arg, "--system") == 0) + { + type = DBUS_BUS_SYSTEM; + } + else if (strcmp (arg, "--session") == 0) + { + type = DBUS_BUS_SESSION; + } + else if (strstr (arg, "--name=") == arg) + { + name = arg + strlen ("--name="); + } + else if (strstr (arg, "--sleep-ms=") == arg) + { + sleep_ms = atoi (arg + strlen ("--sleep-ms=")); + } + else + { + usage (2); + } + } + + connection = dbus_bus_get (type, &error); + + if (connection == NULL) + { + fprintf (stderr, "Failed to connect to bus: %s: %s\n", + error.name, error.message); + dbus_error_free (&error); + return 1; + } + + if (name != NULL) + { + if (dbus_bus_request_name (connection, name, DBUS_NAME_FLAG_DO_NOT_QUEUE, + NULL) != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) + { + fprintf (stderr, "failed to take bus name %s\n", name); + exit (1); + } + } + else + { + printf ("%s\n", dbus_bus_get_unique_name (connection)); + } + + if (!dbus_connection_add_filter (connection, filter, &sleep_ms, NULL)) + tool_oom ("adding message filter"); + + while (dbus_connection_read_write_dispatch (connection, -1)) + {} + + dbus_connection_unref (connection); + return 0; +} diff --git a/tools/dbus-spam.c b/tools/dbus-spam.c new file mode 100644 index 0000000..76f0e06 --- /dev/null +++ b/tools/dbus-spam.c @@ -0,0 +1,461 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-spam.c - a plain libdbus message-sender, loosely based on dbus-send + * + * Copyright © 2003 Philip Blundell + * Copyright © 2011 Nokia Corporation + * Copyright © 2014 Collabora Ltd. + * + * 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 + * + */ + +#include + +#include +#include +#include +#include + +#include + +#include "test-tool.h" +#include "tool-common.h" + +static dbus_bool_t ignore_errors = FALSE; + +static void +usage (int ecode) +{ + fprintf (stderr, + "Usage: dbus-test-tool spam [OPTIONS]\n" + "\n" + "Repeatedly call com.example.Spam() on the given D-Bus service.\n" + "\n" + "Options:\n" + "\n" + " --session use the session bus (default)\n" + " --system use the system bus\n" + "\n" + " --ignore-errors ignore errors\n" + " --dest=NAME call methods on NAME (default " DBUS_SERVICE_DBUS ")\n" + "\n" + " --count=N send N messages (default 1)\n" + " --queue=N queue up N messages at a time (default 1)\n" + " --flood send all messages immediately\n" + " --no-reply set the NO_REPLY flag (implies --flood)\n" + "\n" + " --string send payload as a string (default)\n" + " --bytes send payload as a byte-array\n" + " --empty send an empty payload\n" + "\n" + " --payload=S use S as payload (default \"hello, world!\")\n" + " --stdin read payload from stdin, until EOF\n" + " --message-stdin read a complete D-Bus message from stdin\n" + " --random-size read whitespace-separated ASCII decimal\n" + " payload sizes from stdin and pick one randomly\n" + " for each message\n" + "\n" + " --seed=SEED seed for srand (default is time())\n" + "\n" + ); + exit (ecode); +} + +static void +pc_notify (DBusPendingCall *pc, + void *data) +{ + DBusMessage *message; + int *received_p = data; + DBusError error; + + dbus_error_init (&error); + + message = dbus_pending_call_steal_reply (pc); + + if (!ignore_errors && dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR) + { + dbus_set_error_from_message (&error, message); + fprintf (stderr, "Failed to receive reply #%d: %s: %s\n", *received_p, + error.name, error.message); + } + else + { + VERBOSE (stderr, "received message #%d\n", *received_p); + } + + (*received_p)++; +} + +static void +consume_stdin (char **payload_p, + size_t *len_p) +{ + const size_t BLOCK_SIZE = 4096; + size_t len = BLOCK_SIZE; + size_t pos = 0; + size_t n; + char *buf; + + buf = dbus_malloc (len); + + if (buf == NULL) + tool_oom ("reading payload from stdin"); + + while (1) + { + if (len - pos < BLOCK_SIZE) + { + char *tmp = dbus_realloc (buf, len + BLOCK_SIZE); + + if (tmp == NULL) + tool_oom ("reading payload from stdin"); + + buf = tmp; + len += BLOCK_SIZE; + } + + n = fread (buf + pos, 1, len - pos, stdin); + + if (n <= 0) + { + /* EOF or error - treat as EOF */ + break; + } + + pos += n; + } + + *len_p = pos; + *payload_p = buf; +} + +int +dbus_test_tool_spam (int argc, char **argv) +{ + DBusConnection *connection; + DBusError error = DBUS_ERROR_INIT; + DBusBusType type = DBUS_BUS_SESSION; + const char *destination = DBUS_SERVICE_DBUS; + int i; + int count = 1; + int sent = 0; + int received = 0; + int queue_len = 1; + const char *payload = NULL; + char *payload_buf = NULL; + size_t payload_len; + int payload_type = DBUS_TYPE_STRING; + DBusMessage *template = NULL; + dbus_bool_t no_reply = FALSE; + unsigned int seed = time (NULL); + int n_random_sizes = 0; + unsigned int *random_sizes = NULL; + + /* argv[1] is the tool name, so start from 2 */ + + for (i = 2; i < argc; i++) + { + const char *arg = argv[i]; + + if (strcmp (arg, "--system") == 0) + { + type = DBUS_BUS_SYSTEM; + } + else if (strcmp (arg, "--session") == 0) + { + type = DBUS_BUS_SESSION; + } + else if (strstr (arg, "--count=") == arg) + { + count = atoi (arg + strlen ("--count=")); + + if (count < 1) + usage (2); + } + else if (strcmp (arg, "--ignore-errors") == 0) + { + ignore_errors = TRUE; + } + else if (strstr (arg, "--dest=") == arg) + { + destination = arg + strlen ("--dest="); + } + else if (strstr (arg, "--payload=") == arg) + { + payload = arg + strlen ("--payload="); + } + else if (strcmp (arg, "--stdin") == 0) + { + consume_stdin (&payload_buf, &payload_len); + payload = payload_buf; + } + else if (strcmp (arg, "--message-stdin") == 0) + { + consume_stdin (&payload_buf, &payload_len); + payload = payload_buf; + template = dbus_message_demarshal (payload, payload_len, &error); + + if (template == NULL) + { + fprintf (stderr, "Unable to demarshal template message: %s: %s", + error.name, error.message); + exit (1); + } + + if (dbus_message_get_type (template) != DBUS_MESSAGE_TYPE_METHOD_CALL) + { + fprintf (stderr, "Template message must be a method call\n"); + exit (1); + } + } + else if (strcmp (arg, "--random-size") == 0) + { + unsigned int len, max = 0; + int j, consumed = 0; + const char *p; + + consume_stdin (&payload_buf, &payload_len); + + for (p = payload_buf; p < payload_buf + payload_len; p += consumed) + { + /* the space character matches any (or no) whitespace */ + if (sscanf (p, " %u %n", &len, &consumed) == 0) + break; + + n_random_sizes++; + } + + random_sizes = dbus_new0 (int, n_random_sizes); + + if (random_sizes == NULL) + tool_oom ("allocating array of message lengths"); + + for (p = payload_buf, j = 0; + p < payload_buf + payload_len && j < n_random_sizes; + p += consumed, j++) + { + sscanf (p, " %u %n", &len, &consumed); + random_sizes[j] = len; + + if (len > max) + max = len; + } + + dbus_free (payload_buf); + payload_len = max + 1; + payload_buf = dbus_new (char, payload_len); + payload = payload_buf; + + if (payload_buf == NULL) + tool_oom ("allocating maximum-sized payload"); + + memset (payload_buf, 'X', payload_len); + payload_buf[payload_len - 1] = '\0'; + } + else if (strcmp (arg, "--empty") == 0) + { + payload_type = DBUS_TYPE_INVALID; + } + else if (strcmp (arg, "--string") == 0) + { + payload_type = DBUS_TYPE_STRING; + } + else if (strcmp (arg, "--bytes") == 0) + { + payload_type = DBUS_TYPE_ARRAY; + } + else if (strcmp (arg, "--flood") == 0) + { + queue_len = -1; + } + else if (strcmp (arg, "--no-reply") == 0) + { + queue_len = -1; + no_reply = TRUE; + } + else if (strstr (arg, "--queue=") == arg) + { + queue_len = atoi (arg + strlen ("--queue=")); + + if (queue_len < 1) + usage (2); + } + else if (strstr (arg, "--seed=") == arg) + { + seed = strtoul (arg + strlen ("--seed="), NULL, 10); + } + else + { + usage (2); + } + } + + srand (seed); + + if (payload == NULL) + { + payload = "hello, world!"; + payload_len = strlen (payload); + } + + VERBOSE (stderr, "Will send up to %d messages, with up to %d queued\n", + count, queue_len); + + connection = dbus_bus_get_private (type, &error); + + if (connection == NULL) + { + fprintf (stderr, "Failed to connect to bus: %s: %s\n", + error.name, error.message); + dbus_error_free (&error); + return 1; + } + + while (no_reply ? sent < count : received < count) + { + while (sent < count && + (queue_len == -1 || sent < queue_len + received)) + { + DBusMessage *message; + + if (template != NULL) + { + message = dbus_message_copy (template); + + if (message == NULL) + tool_oom ("copying message"); + + dbus_message_set_no_reply (message, no_reply); + } + else + { + dbus_bool_t mem; + unsigned int len = 0; + + message = dbus_message_new_method_call (destination, + "/", + "com.example", + "Spam"); + + if (message == NULL) + tool_oom ("allocating message"); + + dbus_message_set_no_reply (message, no_reply); + + switch (payload_type) + { + case DBUS_TYPE_STRING: + if (random_sizes != NULL) + { + /* this isn't fair, strictly speaking - the first few + * are a bit more likely to be chosen, unless + * RAND_MAX is divisible by n_random_sizes - but it's + * good enough for traffic-generation */ + len = random_sizes[rand () % n_random_sizes]; + payload_buf[len] = '\0'; + } + + mem = dbus_message_append_args (message, + DBUS_TYPE_STRING, &payload, + DBUS_TYPE_INVALID); + + if (random_sizes != NULL) + { + /* undo the truncation above */ + payload_buf[len] = 'X'; + } + + break; + + case DBUS_TYPE_ARRAY: + len = payload_len; + + /* as above, not strictly fair, but close enough */ + if (random_sizes != NULL) + len = random_sizes[rand () % n_random_sizes]; + + mem = dbus_message_append_args (message, + DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE, + &payload, + (dbus_uint32_t) len, + DBUS_TYPE_INVALID); + break; + + default: + mem = TRUE; + } + + if (!mem) + tool_oom ("building message"); + } + + if (no_reply) + { + if (!dbus_connection_send (connection, message, NULL)) + tool_oom ("sending message"); + + sent++; + } + else + { + DBusPendingCall *pc; + + if (!dbus_connection_send_with_reply (connection, + message, + &pc, + DBUS_TIMEOUT_INFINITE)) + tool_oom ("sending message"); + + VERBOSE (stderr, "sent message #%d\n", sent); + sent++; + + if (pc == NULL) + tool_oom ("sending message"); + + if (dbus_pending_call_get_completed (pc)) + pc_notify (pc, &received); + else if (!dbus_pending_call_set_notify (pc, pc_notify, &received, + NULL)) + tool_oom ("setting pending call notifier"); + + dbus_pending_call_unref (pc); + } + + dbus_message_unref (message); + } + + if (!dbus_connection_read_write_dispatch (connection, -1)) + { + fprintf (stderr, "Disconnected from bus\n"); + exit (1); + } + } + + dbus_connection_flush (connection); + + VERBOSE (stderr, "Done\n"); + + dbus_free (payload_buf); + + if (template != NULL) + dbus_message_unref (template); + + dbus_connection_close (connection); + dbus_connection_unref (connection); + dbus_shutdown (); + return 0; +} diff --git a/tools/test-tool.c b/tools/test-tool.c new file mode 100644 index 0000000..1893b78 --- /dev/null +++ b/tools/test-tool.c @@ -0,0 +1,87 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-test-tool - D-Bus swiss army knife + * + * Copyright © 2003 Philip Blundell + * Copyright © 2011 Nokia Corporation + * Copyright © 2014 Collabora Ltd. + * + * 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 + * + */ + +#include +#include "test-tool.h" + +#include +#include +#include + +#include + +static struct { + const char *name; + int (*callback) (int, char **); +} subcommands[] = { + { "echo", dbus_test_tool_echo }, + { "spam", dbus_test_tool_spam }, + { NULL, NULL } +}; + +static void usage (int exit_with) _DBUS_GNUC_NORETURN; + +static void +usage (int exit_with) +{ + int i; + + fprintf (stderr, + "Usage: dbus-test-tool SUBCOMMAND [OPTIONS]\n" + "\n" + "Known SUBCOMMANDs are:\n" + "\n" + ); + + for (i = 0; subcommands[i].name != NULL; i++) + { + fprintf (stderr, "- %s\n", subcommands[i].name); + } + + fprintf (stderr, + "\n" + "For more information: dbus-test-tool SUBCOMMAND --help\n" + ); + + exit (exit_with); +} + +int +main (int argc, char **argv) +{ + int i; + + if (argc < 2) + { + usage (2); + } + + for (i = 0; subcommands[i].name != NULL; i++) + { + if (!strcmp (argv[1], subcommands[i].name)) + return subcommands[i].callback (argc, argv); + } + + usage (2); + return 2; +} diff --git a/tools/test-tool.h b/tools/test-tool.h new file mode 100644 index 0000000..b6d51c2 --- /dev/null +++ b/tools/test-tool.h @@ -0,0 +1,30 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* dbus-test-tool - D-Bus swiss army knife + * + * Copyright © 2003 Philip Blundell + * Copyright © 2011 Nokia Corporation + * Copyright © 2014 Collabora Ltd. + * + * 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 DBUS_TEST_TOOL_H +#define DBUS_TEST_TOOL_H + +int dbus_test_tool_echo (int argc, char **argv); +int dbus_test_tool_spam (int argc, char **argv); + +#endif diff --git a/tools/tool-common.c b/tools/tool-common.c new file mode 100644 index 0000000..b6af629 --- /dev/null +++ b/tools/tool-common.c @@ -0,0 +1,60 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* tool-common - common functionality for dbus-test-tool modules + * + * Copyright © 2003 Philip Blundell + * Copyright © 2011 Nokia Corporation + * Copyright © 2014 Collabora Ltd. + * + * 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 + * + */ + +#include +#include "tool-common.h" + +#include +#include +#include +#include + +#ifdef DBUS_WIN +#include +#endif + +/* a hack to avoid having to depend on the static -util version of libdbus; + * it's useful for ancillary programs to be able to use the shared library */ +void +tool_millisleep (int ms) +{ +#ifdef DBUS_WIN + Sleep (ms); +#else + fd_set nothing; + struct timeval tv; + + tv.tv_sec = ms / 1000; + tv.tv_usec = (ms % 1000) * 1000; + + FD_ZERO (¬hing); + select (1, ¬hing, ¬hing, ¬hing, &tv); +#endif +} + +void +tool_oom (const char *doing) +{ + fprintf (stderr, "OOM while %s\n", doing); + exit (1); +} diff --git a/tools/tool-common.h b/tools/tool-common.h new file mode 100644 index 0000000..f31076f --- /dev/null +++ b/tools/tool-common.h @@ -0,0 +1,38 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* tool-common - common functionality for dbus-test-tool modules + * + * Copyright © 2003 Philip Blundell + * Copyright © 2011 Nokia Corporation + * Copyright © 2014 Collabora Ltd. + * + * 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 DBUS_TOOL_COMMON_H +#define DBUS_TOOL_COMMON_H + +#include + +#if 0 +#define VERBOSE fprintf +#else +#define VERBOSE(...) do {} while (0) +#endif + +void tool_millisleep (int ms); +void tool_oom (const char *doing); + +#endif -- 1.8.5.3