1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 /* dbus-cleanup-sockets.c dbus-cleanup-sockets utility
4 * Copyright (C) 2003 Red Hat, Inc.
5 * Copyright (C) 2002 Michael Meeks
7 * Note that this file is NOT licensed under the Academic Free License,
8 * as it is based on linc-cleanup-sockets which is LGPL.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 #include <sys/types.h>
32 #include <sys/socket.h>
47 #define NULL ((void*) 0)
51 xmalloc (size_t bytes)
62 fprintf (stderr, "Allocation of %d bytes failed\n",
71 xrealloc (void *old, size_t bytes)
81 mem = realloc (old, bytes);
85 fprintf (stderr, "Reallocation of %d bytes failed\n",
98 SOCKET_FAILED_TO_HANDLE,
104 static int alive_count = 0;
105 static int cleaned_count = 0;
106 static int unhandled_count = 0;
117 socket_entry_new (const char *dir,
123 se = xmalloc (sizeof (SocketEntry));
125 len = strlen (dir) + strlen (fname) + 2; /* 2 = nul and '/' */
126 se->name = xmalloc (len);
128 strcpy (se->name, dir);
129 strcat (se->name, "/");
130 strcat (se->name, fname);
134 se->status = SOCKET_UNKNOWN;
142 free_socket_entry (SocketEntry *se)
154 free_socket_entries (SocketEntry** entries,
161 for (i = 0; i < n_entries; ++i)
162 free_socket_entry (entries[i]);
168 read_sockets (const char *dir,
169 SocketEntry ***entries_p,
174 SocketEntry **entries;
180 entries = xmalloc (sizeof (SocketEntry*) * allocated);
182 dirh = opendir (dir);
185 fprintf (stderr, "Failed to open directory %s: %s\n",
186 dir, strerror (errno));
190 while ((dent = readdir (dirh)))
194 if (strncmp (dent->d_name, "dbus-", 5) != 0)
197 se = socket_entry_new (dir, dent->d_name);
199 if (n_entries == allocated)
202 entries = xrealloc (entries, sizeof (SocketEntry*) * allocated);
205 entries[n_entries] = se;
211 *entries_p = entries;
212 *n_entries_p = n_entries;
216 open_socket (SocketEntry *se)
219 struct sockaddr_un saddr;
221 if (se->n_retries > 5)
223 fprintf (stderr, "Warning: giving up on socket %s after several retries; unable to determine socket's status\n",
225 return SOCKET_FAILED_TO_HANDLE;
230 se->fd = socket (AF_UNIX, SOCK_STREAM, 0);
233 fprintf (stderr, "Warning: failed to open a socket to use for connecting: %s\n",
235 return SOCKET_UNKNOWN;
238 if (fcntl (se->fd, F_SETFL, O_NONBLOCK) < 0)
240 fprintf (stderr, "Warning: failed set socket %s nonblocking: %s\n",
241 se->name, strerror (errno));
242 return SOCKET_UNKNOWN;
246 memset (&saddr, '\0', sizeof (saddr)); /* nul-terminates the sun_path */
248 saddr.sun_family = AF_UNIX;
249 strncpy (saddr.sun_path, se->name, sizeof (saddr.sun_path) - 1);
253 ret = connect (se->fd, (struct sockaddr*) &saddr, sizeof (saddr));
255 while (ret < 0 && errno == EINTR);
265 return SOCKET_UNKNOWN;
269 fprintf (stderr, "Warning: unexpected error connecting to socket %s: %s\n",
270 se->name, strerror (errno));
271 return SOCKET_FAILED_TO_HANDLE;
277 handle_sockets (SocketEntry **entries,
286 while (i < n_entries)
296 fprintf (stderr, "Internal error, socket has fd kept open while status = %d\n",
301 if (se->status != SOCKET_UNKNOWN)
304 status = open_socket (se);
310 if (unlink (se->name) < 0)
312 fprintf (stderr, "Warning: Failed to delete %s: %s\n",
313 se->name, strerror (errno));
315 se->status = SOCKET_FAILED_TO_HANDLE;
318 se->status = SOCKET_UNLINKED;
325 case SOCKET_FAILED_TO_HANDLE:
330 case SOCKET_UNLINKED:
331 fprintf (stderr, "Bad status from open_socket(), should not happen\n");
342 if (se->status == SOCKET_UNKNOWN)
346 return n_unknown == 0;
350 clean_dir (const char *dir)
352 SocketEntry **entries;
355 read_sockets (dir, &entries, &n_entries);
357 /* open_socket() will fail conclusively after
358 * several retries, so this loop is guaranteed
359 * to terminate eventually
361 while (!handle_sockets (entries, n_entries))
363 fprintf (stderr, "Unable to determine state of some sockets, retrying in 2 seconds\n");
367 unhandled_count += (n_entries - alive_count - cleaned_count);
369 free_socket_entries (entries, n_entries);
377 fprintf (stderr, "dbus-cleanup-sockets [--version] [--help] <socketdir>\n");
384 printf ("D-Bus Socket Cleanup Utility %s\n"
385 "Copyright (C) 2003 Red Hat, Inc.\n"
386 "Copyright (C) 2002 Michael Meeks\n"
387 "This is free software; see the source for copying conditions.\n"
388 "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
394 main (int argc, char **argv)
400 saw_doubledash = FALSE;
405 const char *arg = argv[i];
407 if (strcmp (arg, "--help") == 0 ||
408 strcmp (arg, "-h") == 0 ||
409 strcmp (arg, "-?") == 0)
411 else if (strcmp (arg, "--version") == 0)
413 else if (!saw_doubledash)
415 if (strcmp (arg, "--") == 0)
416 saw_doubledash = TRUE;
417 else if (*arg == '-')
424 fprintf (stderr, "dbus-cleanup-sockets only supports a single directory name\n");
434 /* Default to session socket dir, usually /tmp */
436 dirname = DBUS_SESSION_SOCKET_DIR;
441 printf ("Cleaned up %d sockets in %s; %d sockets are still in use; %d in unknown state\n",
442 cleaned_count, dirname, alive_count, unhandled_count);
444 printf ("This system does not support UNIX domain sockets, so dbus-cleanup-sockets does nothing\n");