1 /* -*- mode: C; c-file-style: "gnu" -*- */ 2 /* dbus-monitor.c Utility program to monitor messages on the bus 3 * 4 * Copyright (C) 2003 Philip Blundell <philb (at) 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 */ 21 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <string.h> 25 26 #include <sys/time.h> 27 #include <time.h> 28 29 #include <signal.h> 30 31 #include "dbus-print-message.h" 32 33 static DBusHandlerResult 34 monitor_filter_func (DBusConnection *connection, 35 DBusMessage *message, 36 void *user_data) 37 { 38 print_message (message, FALSE); 39 40 if (dbus_message_is_signal (message, 41 DBUS_INTERFACE_LOCAL, 42 "Disconnected")) 43 exit (0); 44 45 /* Conceptually we want this to be 46 * DBUS_HANDLER_RESULT_NOT_YET_HANDLED, but this raises 47 * some problems. See bug 1719. 48 */ 49 return DBUS_HANDLER_RESULT_HANDLED; 50 } 51 52 #define PROFILE_TIMED_FORMAT "%s\t%lu\t%lu" 53 #define TRAP_NULL_STRING(str) ((str) ? (str) : "<none>") 54 55 typedef enum 56 { 57 PROFILE_ATTRIBUTE_FLAG_SERIAL = 1, 58 PROFILE_ATTRIBUTE_FLAG_REPLY_SERIAL = 2, 59 PROFILE_ATTRIBUTE_FLAG_SENDER = 4, 60 PROFILE_ATTRIBUTE_FLAG_DESTINATION = 8, 61 PROFILE_ATTRIBUTE_FLAG_PATH = 16, 62 PROFILE_ATTRIBUTE_FLAG_INTERFACE = 32, 63 PROFILE_ATTRIBUTE_FLAG_MEMBER = 64, 64 PROFILE_ATTRIBUTE_FLAG_ERROR_NAME = 128, 65 } ProfileAttributeFlags; 66 67 static void 68 profile_print_with_attrs (const char *type, DBusMessage *message, 69 struct timeval *t, ProfileAttributeFlags attrs) 70 { 71 printf (PROFILE_TIMED_FORMAT, type, t->tv_sec, t->tv_usec); 72 73 if (attrs & PROFILE_ATTRIBUTE_FLAG_SERIAL) 74 printf ("\t%u", dbus_message_get_serial (message)); 75 76 if (attrs & PROFILE_ATTRIBUTE_FLAG_REPLY_SERIAL) 77 printf ("\t%u", dbus_message_get_reply_serial (message)); 78 79 if (attrs & PROFILE_ATTRIBUTE_FLAG_SENDER) 80 printf ("\t%s", TRAP_NULL_STRING (dbus_message_get_sender (message))); 81 82 if (attrs & PROFILE_ATTRIBUTE_FLAG_DESTINATION) 83 printf ("\t%s", TRAP_NULL_STRING (dbus_message_get_destination (message))); 84 85 if (attrs & PROFILE_ATTRIBUTE_FLAG_PATH) 86 printf ("\t%s", TRAP_NULL_STRING (dbus_message_get_path (message))); 87 88 if (attrs & PROFILE_ATTRIBUTE_FLAG_INTERFACE) 89 printf ("\t%s", TRAP_NULL_STRING (dbus_message_get_interface (message))); 90 91 if (attrs & PROFILE_ATTRIBUTE_FLAG_MEMBER) 92 printf ("\t%s", TRAP_NULL_STRING (dbus_message_get_member (message))); 93 94 if (attrs & PROFILE_ATTRIBUTE_FLAG_ERROR_NAME) 95 printf ("\t%s", TRAP_NULL_STRING (dbus_message_get_error_name (message))); 96 97 printf ("\n"); 98 } 99 100 static void 101 print_message_profile (DBusMessage *message) 102 { 103 struct timeval t; 104 105 if (gettimeofday (&t, NULL) < 0) 106 { 107 printf ("un\n"); 108 return; 109 } 110 111 switch (dbus_message_get_type (message)) 112 { 113 case DBUS_MESSAGE_TYPE_METHOD_CALL: 114 profile_print_with_attrs ("mc", message, &t, 115 PROFILE_ATTRIBUTE_FLAG_SERIAL | 116 PROFILE_ATTRIBUTE_FLAG_SENDER | 117 PROFILE_ATTRIBUTE_FLAG_PATH | 118 PROFILE_ATTRIBUTE_FLAG_INTERFACE | 119 PROFILE_ATTRIBUTE_FLAG_MEMBER); 120 break; 121 case DBUS_MESSAGE_TYPE_METHOD_RETURN: 122 profile_print_with_attrs ("mr", message, &t, 123 PROFILE_ATTRIBUTE_FLAG_SERIAL | 124 PROFILE_ATTRIBUTE_FLAG_DESTINATION | 125 PROFILE_ATTRIBUTE_FLAG_REPLY_SERIAL); 126 break; 127 case DBUS_MESSAGE_TYPE_ERROR: 128 profile_print_with_attrs ("err", message, &t, 129 PROFILE_ATTRIBUTE_FLAG_SERIAL | 130 PROFILE_ATTRIBUTE_FLAG_DESTINATION | 131 PROFILE_ATTRIBUTE_FLAG_REPLY_SERIAL); 132 break; 133 case DBUS_MESSAGE_TYPE_SIGNAL: 134 profile_print_with_attrs ("sig", message, &t, 135 PROFILE_ATTRIBUTE_FLAG_SERIAL | 136 PROFILE_ATTRIBUTE_FLAG_PATH | 137 PROFILE_ATTRIBUTE_FLAG_INTERFACE | 138 PROFILE_ATTRIBUTE_FLAG_MEMBER); 139 break; 140 default: 141 printf (PROFILE_TIMED_FORMAT "\n", "tun", t.tv_sec, t.tv_usec); 142 break; 143 } 144 } 145 146 static DBusHandlerResult 147 profile_filter_func (DBusConnection *connection, 148 DBusMessage *message, 149 void *user_data) 150 { 151 print_message_profile (message); 152 153 if (dbus_message_is_signal (message, 154 DBUS_INTERFACE_LOCAL, 155 "Disconnected")) 156 exit (0); 157 158 return DBUS_HANDLER_RESULT_HANDLED; 159 } 160 161 static void 162 usage (char *name, int ecode) 163 { 164 fprintf (stderr, "Usage: %s [--system | --session] [--monitor | --profile ] [watch expressions]\n", name); 165 exit (ecode); 166 } 167 168 dbus_bool_t sigint_received = FALSE; 169 170 static void 171 sigint_handler (int signum) 172 { 173 sigint_received = TRUE; 174 } 175 176 int 177 main (int argc, char *argv[]) 178 { 179 DBusConnection *connection; 180 DBusError error; 181 DBusBusType type = DBUS_BUS_SESSION; 182 DBusHandleMessageFunction filter_func = monitor_filter_func; 183 184 int i = 0, j = 0, numFilters = 0; 185 char **filters = NULL; 186 for (i = 1; i < argc; i++) 187 { 188 char *arg = argv[i]; 189 190 if (!strcmp (arg, "--system")) 191 type = DBUS_BUS_SYSTEM; 192 else if (!strcmp (arg, "--session")) 193 type = DBUS_BUS_SESSION; 194 else if (!strcmp (arg, "--help")) 195 usage (argv[0], 0); 196 else if (!strcmp (arg, "--monitor")) 197 filter_func = monitor_filter_func; 198 else if (!strcmp (arg, "--profile")) 199 filter_func = profile_filter_func; 200 else if (!strcmp (arg, "--")) 201 continue; 202 else if (arg[0] == '-') 203 usage (argv[0], 1); 204 else { 205 numFilters++; 206 filters = (char **)realloc(filters, numFilters * sizeof(char *)); 207 filters[j] = (char *)malloc((strlen(arg) + 1) * sizeof(char *)); 208 snprintf(filters[j], strlen(arg) + 1, "%s", arg); 209 j++; 210 } 211 } 212 213 dbus_error_init (&error); 214 connection = dbus_bus_get (type, &error); 215 if (connection == NULL) 216 { 217 fprintf (stderr, "Failed to open connection to %s message bus: %s\n", 218 (type == DBUS_BUS_SYSTEM) ? "system" : "session", 219 error.message); 220 dbus_error_free (&error); 221 exit (1); 222 } 223 224 if (numFilters) 225 { 226 for (i = 0; i < j; i++) 227 { 228 dbus_bus_add_match (connection, filters[i], &error); 229 if (dbus_error_is_set (&error)) 230 { 231 fprintf (stderr, "Failed to setup match \"%s\": %s\n", 232 filters[i], error.message); 233 dbus_error_free (&error); 234 exit (1); 235 } 236 free(filters[i]); 237 } 238 } 239 else 240 { 241 dbus_bus_add_match (connection, 242 "type='signal'", 243 &error); 244 if (dbus_error_is_set (&error)) 245 goto lose; 246 dbus_bus_add_match (connection, 247 "type='method_call'", 248 &error); 249 if (dbus_error_is_set (&error)) 250 goto lose; 251 dbus_bus_add_match (connection, 252 "type='method_return'", 253 &error); 254 if (dbus_error_is_set (&error)) 255 goto lose; 256 dbus_bus_add_match (connection, 257 "type='error'", 258 &error); 259 if (dbus_error_is_set (&error)) 260 goto lose; 261 } 262 263 if (!dbus_connection_add_filter (connection, filter_func, NULL, NULL)) { 264 fprintf (stderr, "Couldn't add filter!\n"); 265 exit (1); 266 } 267 268 /* we handle SIGINT so exit() is reached and flushes stdout */ 269 signal (SIGINT, sigint_handler); 270 while (dbus_connection_read_write_dispatch(connection, -1) 271 && !sigint_received) 272 ; 273 exit (0); 274 lose: 275 fprintf (stderr, "Error: %s\n", error.message); 276 exit (1); 277 } 278 279