1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 2/* dbus-monitor.c Utility program to monitor messages on the bus 3 * 4 * Copyright (C) 2003 Philip Blundell <philb@gnu.org> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 * 20 */ 21 22#include <config.h> 23#include <stdio.h> 24#include <stdlib.h> 25#include <string.h> 26 27#ifdef DBUS_WIN 28#include <winsock2.h> 29#undef interface 30#else 31#include <sys/time.h> 32#endif 33 34#include <time.h> 35 36#include "dbus-print-message.h" 37 38#ifdef DBUS_WIN 39 40/* gettimeofday is not defined on windows */ 41#define DBUS_SECONDS_SINCE_1601 11644473600LL 42#define DBUS_USEC_IN_SEC 1000000LL 43 44#ifdef DBUS_WINCE 45 46#ifndef _IOLBF 47#define _IOLBF 0x40 48#endif 49#ifndef _IONBF 50#define _IONBF 0x04 51#endif 52 53void 54GetSystemTimeAsFileTime (LPFILETIME ftp) 55{ 56 SYSTEMTIME st; 57 GetSystemTime (&st); 58 SystemTimeToFileTime (&st, ftp); 59} 60#endif 61 62static int 63gettimeofday (struct timeval *__p, 64 void *__t) 65{ 66 union { 67 unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */ 68 FILETIME ft; 69 } now; 70 71 GetSystemTimeAsFileTime (&now.ft); 72 __p->tv_usec = (long) ((now.ns100 / 10LL) % DBUS_USEC_IN_SEC); 73 __p->tv_sec = (long)(((now.ns100 / 10LL) / DBUS_SECONDS_SINCE_1601) - DBUS_SECONDS_SINCE_1601); 74 75 return 0; 76} 77#endif 78 79static DBusHandlerResult 80monitor_filter_func (DBusConnection *connection, 81 DBusMessage *message, 82 void *user_data) 83{ 84 print_message (message, FALSE); 85 86 if (dbus_message_is_signal (message, 87 DBUS_INTERFACE_LOCAL, 88 "Disconnected")) 89 exit (0); 90 91 /* Conceptually we want this to be 92 * DBUS_HANDLER_RESULT_NOT_YET_HANDLED, but this raises 93 * some problems. See bug 1719. 94 */ 95 return DBUS_HANDLER_RESULT_HANDLED; 96} 97 98#define PROFILE_TIMED_FORMAT "%s\t%lu\t%lu" 99#define TRAP_NULL_STRING(str) ((str) ? (str) : "<none>") 100 101typedef enum 102{ 103 PROFILE_ATTRIBUTE_FLAG_SERIAL = 1, 104 PROFILE_ATTRIBUTE_FLAG_REPLY_SERIAL = 2, 105 PROFILE_ATTRIBUTE_FLAG_SENDER = 4, 106 PROFILE_ATTRIBUTE_FLAG_DESTINATION = 8, 107 PROFILE_ATTRIBUTE_FLAG_PATH = 16, 108 PROFILE_ATTRIBUTE_FLAG_INTERFACE = 32, 109 PROFILE_ATTRIBUTE_FLAG_MEMBER = 64, 110 PROFILE_ATTRIBUTE_FLAG_ERROR_NAME = 128 111} ProfileAttributeFlags; 112 113static void 114profile_print_with_attrs (const char *type, DBusMessage *message, 115 struct timeval *t, ProfileAttributeFlags attrs) 116{ 117 printf (PROFILE_TIMED_FORMAT, type, t->tv_sec, t->tv_usec); 118 119 if (attrs & PROFILE_ATTRIBUTE_FLAG_SERIAL) 120 printf ("\t%u", dbus_message_get_serial (message)); 121 122 if (attrs & PROFILE_ATTRIBUTE_FLAG_REPLY_SERIAL) 123 printf ("\t%u", dbus_message_get_reply_serial (message)); 124 125 if (attrs & PROFILE_ATTRIBUTE_FLAG_SENDER) 126 printf ("\t%s", TRAP_NULL_STRING (dbus_message_get_sender (message))); 127 128 if (attrs & PROFILE_ATTRIBUTE_FLAG_DESTINATION) 129 printf ("\t%s", TRAP_NULL_STRING (dbus_message_get_destination (message))); 130 131 if (attrs & PROFILE_ATTRIBUTE_FLAG_PATH) 132 printf ("\t%s", TRAP_NULL_STRING (dbus_message_get_path (message))); 133 134 if (attrs & PROFILE_ATTRIBUTE_FLAG_INTERFACE) 135 printf ("\t%s", TRAP_NULL_STRING (dbus_message_get_interface (message))); 136 137 if (attrs & PROFILE_ATTRIBUTE_FLAG_MEMBER) 138 printf ("\t%s", TRAP_NULL_STRING (dbus_message_get_member (message))); 139 140 if (attrs & PROFILE_ATTRIBUTE_FLAG_ERROR_NAME) 141 printf ("\t%s", TRAP_NULL_STRING (dbus_message_get_error_name (message))); 142 143 printf ("\n"); 144} 145 146static void 147print_message_profile (DBusMessage *message) 148{ 149 struct timeval t; 150 151 if (gettimeofday (&t, NULL) < 0) 152 { 153 printf ("un\n"); 154 return; 155 } 156 157 switch (dbus_message_get_type (message)) 158 { 159 case DBUS_MESSAGE_TYPE_METHOD_CALL: 160 profile_print_with_attrs ("mc", message, &t, 161 PROFILE_ATTRIBUTE_FLAG_SERIAL | 162 PROFILE_ATTRIBUTE_FLAG_SENDER | 163 PROFILE_ATTRIBUTE_FLAG_PATH | 164 PROFILE_ATTRIBUTE_FLAG_INTERFACE | 165 PROFILE_ATTRIBUTE_FLAG_MEMBER); 166 break; 167 case DBUS_MESSAGE_TYPE_METHOD_RETURN: 168 profile_print_with_attrs ("mr", message, &t, 169 PROFILE_ATTRIBUTE_FLAG_SERIAL | 170 PROFILE_ATTRIBUTE_FLAG_DESTINATION | 171 PROFILE_ATTRIBUTE_FLAG_REPLY_SERIAL); 172 break; 173 case DBUS_MESSAGE_TYPE_ERROR: 174 profile_print_with_attrs ("err", message, &t, 175 PROFILE_ATTRIBUTE_FLAG_SERIAL | 176 PROFILE_ATTRIBUTE_FLAG_DESTINATION | 177 PROFILE_ATTRIBUTE_FLAG_REPLY_SERIAL); 178 break; 179 case DBUS_MESSAGE_TYPE_SIGNAL: 180 profile_print_with_attrs ("sig", message, &t, 181 PROFILE_ATTRIBUTE_FLAG_SERIAL | 182 PROFILE_ATTRIBUTE_FLAG_PATH | 183 PROFILE_ATTRIBUTE_FLAG_INTERFACE | 184 PROFILE_ATTRIBUTE_FLAG_MEMBER); 185 break; 186 default: 187 printf (PROFILE_TIMED_FORMAT "\n", "tun", t.tv_sec, t.tv_usec); 188 break; 189 } 190} 191 192static DBusHandlerResult 193profile_filter_func (DBusConnection *connection, 194 DBusMessage *message, 195 void *user_data) 196{ 197 print_message_profile (message); 198 199 if (dbus_message_is_signal (message, 200 DBUS_INTERFACE_LOCAL, 201 "Disconnected")) 202 exit (0); 203 204 return DBUS_HANDLER_RESULT_HANDLED; 205} 206 207static void 208usage (char *name, int ecode) 209{ 210 fprintf (stderr, "Usage: %s [--system | --session | --address ADDRESS] [--monitor | --profile ] [watch expressions]\n", name); 211 exit (ecode); 212} 213 214static dbus_bool_t sigint_received = FALSE; 215 216static void 217sigint_handler (int signum) 218{ 219 sigint_received = TRUE; 220} 221 222int 223main (int argc, char *argv[]) 224{ 225 DBusConnection *connection; 226 DBusError error; 227 DBusBusType type = DBUS_BUS_SESSION; 228 DBusHandleMessageFunction filter_func = monitor_filter_func; 229 char *address = NULL; 230 231 int i = 0, j = 0, numFilters = 0; 232 char **filters = NULL; 233 234 /* Set stdout to be unbuffered; this is basically so that if people 235 * do dbus-monitor > file, then send SIGINT via Control-C, they 236 * don't lose the last chunk of messages. 237 */ 238 239#ifdef DBUS_WIN 240 setvbuf (stdout, NULL, _IONBF, 0); 241#else 242 setvbuf (stdout, NULL, _IOLBF, 0); 243#endif 244 245 for (i = 1; i < argc; i++) 246 { 247 char *arg = argv[i]; 248 249 if (!strcmp (arg, "--system")) 250 type = DBUS_BUS_SYSTEM; 251 else if (!strcmp (arg, "--session")) 252 type = DBUS_BUS_SESSION; 253 else if (!strcmp (arg, "--address")) 254 { 255 if (i+1 < argc) 256 { 257 address = argv[i+1]; 258 i++; 259 } 260 else 261 usage (argv[0], 1); 262 } 263 else if (!strcmp (arg, "--help")) 264 usage (argv[0], 0); 265 else if (!strcmp (arg, "--monitor")) 266 filter_func = monitor_filter_func; 267 else if (!strcmp (arg, "--profile")) 268 filter_func = profile_filter_func; 269 else if (!strcmp (arg, "--")) 270 continue; 271 else if (arg[0] == '-') 272 usage (argv[0], 1); 273 else { 274 numFilters++; 275 filters = (char **)realloc(filters, numFilters * sizeof(char *)); 276 filters[j] = (char *)malloc((strlen(arg) + 1) * sizeof(char *)); 277 snprintf(filters[j], strlen(arg) + 1, "%s", arg); 278 j++; 279 } 280 } 281 282 dbus_error_init (&error); 283 284 if (address != NULL) 285 { 286 connection = dbus_connection_open (address, &error); 287 if (connection) 288 { 289 if (!dbus_bus_register (connection, &error)) 290 { 291 fprintf (stderr, "Failed to register connection to bus at %s: %s\n", 292 address, error.message); 293 dbus_error_free (&error); 294 exit (1); 295 } 296 } 297 } 298 else 299 connection = dbus_bus_get (type, &error); 300 if (connection == NULL) 301 { 302 const char *where; 303 if (address != NULL) 304 where = address; 305 else 306 { 307 switch (type) 308 { 309 case DBUS_BUS_SYSTEM: 310 where = "system bus"; 311 break; 312 case DBUS_BUS_SESSION: 313 where = "session bus"; 314 break; 315 default: 316 where = ""; 317 } 318 } 319 fprintf (stderr, "Failed to open connection to %s: %s\n", 320 where, 321 error.message); 322 dbus_error_free (&error); 323 exit (1); 324 } 325 326 if (numFilters) 327 { 328 for (i = 0; i < j; i++) 329 { 330 dbus_bus_add_match (connection, filters[i], &error); 331 if (dbus_error_is_set (&error)) 332 { 333 fprintf (stderr, "Failed to setup match \"%s\": %s\n", 334 filters[i], error.message); 335 dbus_error_free (&error); 336 exit (1); 337 } 338 free(filters[i]); 339 } 340 } 341 else 342 { 343 dbus_bus_add_match (connection, 344 "type='signal'", 345 &error); 346 if (dbus_error_is_set (&error)) 347 goto lose; 348 dbus_bus_add_match (connection, 349 "type='method_call'", 350 &error); 351 if (dbus_error_is_set (&error)) 352 goto lose; 353 dbus_bus_add_match (connection, 354 "type='method_return'", 355 &error); 356 if (dbus_error_is_set (&error)) 357 goto lose; 358 dbus_bus_add_match (connection, 359 "type='error'", 360 &error); 361 if (dbus_error_is_set (&error)) 362 goto lose; 363 } 364 365 if (!dbus_connection_add_filter (connection, filter_func, NULL, NULL)) { 366 fprintf (stderr, "Couldn't add filter!\n"); 367 exit (1); 368 } 369 370 while (dbus_connection_read_write_dispatch(connection, -1)) 371 ; 372 exit (0); 373 lose: 374 fprintf (stderr, "Error: %s\n", error.message); 375 exit (1); 376} 377 378