| 1 | #include <config.h>
|
|---|
| 2 |
|
|---|
| 3 | #include <stdio.h>
|
|---|
| 4 | #include <fcntl.h>
|
|---|
| 5 | #include <unistd.h>
|
|---|
| 6 | #include <dirent.h>
|
|---|
| 7 | #include <glib.h>
|
|---|
| 8 |
|
|---|
| 9 | /*
|
|---|
| 10 | * Two timeouts - waiting while there are other
|
|---|
| 11 | * ( in ms ) handles to be checked.
|
|---|
| 12 | * - waiting after all other handles have
|
|---|
| 13 | * been checked.
|
|---|
| 14 | */
|
|---|
| 15 | #define SHORT_TIMEOUT 10
|
|---|
| 16 | #define LONG_TIMEOUT 1000
|
|---|
| 17 |
|
|---|
| 18 | static int total_count = 0;
|
|---|
| 19 | static int cleaned_count = 0;
|
|---|
| 20 |
|
|---|
| 21 | #include <linc-compat.h>
|
|---|
| 22 |
|
|---|
| 23 | #ifdef AF_UNIX
|
|---|
| 24 |
|
|---|
| 25 | typedef struct {
|
|---|
| 26 | char *name;
|
|---|
| 27 | int fd;
|
|---|
| 28 | } SocketEntry;
|
|---|
| 29 |
|
|---|
| 30 | static SocketEntry *
|
|---|
| 31 | new_socket_entry (const char *dir, const char *fname)
|
|---|
| 32 | {
|
|---|
| 33 | SocketEntry *se = g_new0 (SocketEntry, 1);
|
|---|
| 34 |
|
|---|
| 35 | se->name = g_build_filename (dir, fname, NULL);
|
|---|
| 36 | se->fd = -1;
|
|---|
| 37 |
|
|---|
| 38 | return se;
|
|---|
| 39 | }
|
|---|
| 40 |
|
|---|
| 41 | static void
|
|---|
| 42 | free_socket_entry (SocketEntry *se)
|
|---|
| 43 | {
|
|---|
| 44 | g_free (se->name);
|
|---|
| 45 | if (se->fd >= 0)
|
|---|
| 46 | close (se->fd);
|
|---|
| 47 | g_free (se);
|
|---|
| 48 | }
|
|---|
| 49 |
|
|---|
| 50 | static GList *
|
|---|
| 51 | read_sockets (const char *dir)
|
|---|
| 52 | {
|
|---|
| 53 | DIR *dirh;
|
|---|
| 54 | GList *files = NULL;
|
|---|
| 55 | struct dirent *dent;
|
|---|
| 56 |
|
|---|
| 57 | dirh = opendir (dir);
|
|---|
| 58 | if (!dirh)
|
|---|
| 59 | return NULL;
|
|---|
| 60 |
|
|---|
| 61 | while ((dent = readdir (dirh))) {
|
|---|
| 62 | if (strncmp (dent->d_name, "linc-", 5))
|
|---|
| 63 | continue;
|
|---|
| 64 |
|
|---|
| 65 | files = g_list_prepend (
|
|---|
| 66 | files, new_socket_entry (
|
|---|
| 67 | dir, dent->d_name));
|
|---|
| 68 | }
|
|---|
| 69 | closedir (dirh);
|
|---|
| 70 |
|
|---|
| 71 | return files;
|
|---|
| 72 | }
|
|---|
| 73 |
|
|---|
| 74 | typedef enum {
|
|---|
| 75 | SOCKET_DEAD_NOW,
|
|---|
| 76 | SOCKET_PENDING,
|
|---|
| 77 | SOCKET_AGAIN,
|
|---|
| 78 | SOCKET_ALIVE
|
|---|
| 79 | } SocketStatus;
|
|---|
| 80 |
|
|---|
| 81 | static SocketStatus
|
|---|
| 82 | open_socket (SocketEntry *se)
|
|---|
| 83 | {
|
|---|
| 84 | int saddr_len, ret;
|
|---|
| 85 | struct sockaddr_un saddr;
|
|---|
| 86 |
|
|---|
| 87 | g_return_val_if_fail (se != NULL, SOCKET_DEAD_NOW);
|
|---|
| 88 | g_return_val_if_fail (se->fd == -1, SOCKET_DEAD_NOW);
|
|---|
| 89 | g_return_val_if_fail (se->name != NULL, SOCKET_DEAD_NOW);
|
|---|
| 90 |
|
|---|
| 91 | saddr.sun_family = AF_UNIX;
|
|---|
| 92 |
|
|---|
| 93 | g_snprintf (saddr.sun_path, sizeof (saddr.sun_path),
|
|---|
| 94 | "%s", se->name);
|
|---|
| 95 |
|
|---|
| 96 | se->fd = socket (AF_UNIX, SOCK_STREAM, 0);
|
|---|
| 97 | g_assert (se->fd >= 0);
|
|---|
| 98 |
|
|---|
| 99 | if (fcntl (se->fd, F_SETFL, O_NONBLOCK) < 0)
|
|---|
| 100 | g_error ("Failed to set fd non-blocking");
|
|---|
| 101 |
|
|---|
| 102 | saddr_len = sizeof (struct sockaddr_un) -
|
|---|
| 103 | sizeof (saddr.sun_path) + strlen (saddr.sun_path);
|
|---|
| 104 |
|
|---|
| 105 | do {
|
|---|
| 106 | ret = connect (se->fd, &saddr, saddr_len);
|
|---|
| 107 | } while (ret < 0 && errno == EINTR);
|
|---|
| 108 |
|
|---|
| 109 | if (ret >= 0)
|
|---|
| 110 | return SOCKET_ALIVE;
|
|---|
| 111 | else {
|
|---|
| 112 | switch (errno) {
|
|---|
| 113 | case EINPROGRESS:
|
|---|
| 114 | return SOCKET_PENDING;
|
|---|
| 115 | case ECONNREFUSED:
|
|---|
| 116 | return SOCKET_DEAD_NOW;
|
|---|
| 117 | case EAGAIN:
|
|---|
| 118 | return SOCKET_AGAIN;
|
|---|
| 119 | case EBADF:
|
|---|
| 120 | g_error ("Bad bug fd %d", se->fd);
|
|---|
| 121 | break;
|
|---|
| 122 | default:
|
|---|
| 123 | g_warning ("Error '%s' on socket %d",
|
|---|
| 124 | g_strerror (errno), se->fd);
|
|---|
| 125 | break;
|
|---|
| 126 | }
|
|---|
| 127 | }
|
|---|
| 128 |
|
|---|
| 129 | return SOCKET_DEAD_NOW;
|
|---|
| 130 | }
|
|---|
| 131 |
|
|---|
| 132 | static GList *
|
|---|
| 133 | poll_open (GList *files, int *pending, int timeout)
|
|---|
| 134 | {
|
|---|
| 135 | if (!files)
|
|---|
| 136 | return NULL;
|
|---|
| 137 |
|
|---|
| 138 | g_print ("FIXME: should poll unknown descriptors for a bit");
|
|---|
| 139 |
|
|---|
| 140 | /* FIXME: we should really do something clever here,
|
|---|
| 141 | * poll for a while, wait for nice connected / bad
|
|---|
| 142 | * signals on the sockets, etc - but what we have
|
|---|
| 143 | * works well for now */
|
|---|
| 144 | while (files && *pending > 0) {
|
|---|
| 145 | free_socket_entry (files->data);
|
|---|
| 146 | files = g_list_delete_link (files, files);
|
|---|
| 147 | (*pending)--;
|
|---|
| 148 | }
|
|---|
| 149 |
|
|---|
| 150 | return files;
|
|---|
| 151 | }
|
|---|
| 152 |
|
|---|
| 153 | static void
|
|---|
| 154 | clean_dir (const char *dir)
|
|---|
| 155 | {
|
|---|
| 156 | int open_max;
|
|---|
| 157 | int pending = 0;
|
|---|
| 158 | int dirty_files = 0;
|
|---|
| 159 | GList *files, *l, *next;
|
|---|
| 160 |
|
|---|
| 161 | open_max = sysconf (_SC_OPEN_MAX);
|
|---|
| 162 |
|
|---|
| 163 | files = read_sockets (dir);
|
|---|
| 164 |
|
|---|
| 165 | dirty_files = g_list_length (files);
|
|---|
| 166 |
|
|---|
| 167 | for (l = files; l; l = next) {
|
|---|
| 168 | SocketEntry *se = l->data;
|
|---|
| 169 | SocketStatus status;
|
|---|
| 170 |
|
|---|
| 171 | next = l->next;
|
|---|
| 172 |
|
|---|
| 173 | status = open_socket (se);
|
|---|
| 174 |
|
|---|
| 175 | switch (status) {
|
|---|
| 176 | case SOCKET_DEAD_NOW:
|
|---|
| 177 | cleaned_count++;
|
|---|
| 178 | unlink (se->name);
|
|---|
| 179 | /* drop through */
|
|---|
| 180 | case SOCKET_ALIVE:
|
|---|
| 181 | files = g_list_delete_link (files, l);
|
|---|
| 182 | free_socket_entry (se);
|
|---|
| 183 | total_count++;
|
|---|
| 184 | break;
|
|---|
| 185 | case SOCKET_AGAIN:
|
|---|
| 186 | case SOCKET_PENDING:
|
|---|
| 187 | pending++;
|
|---|
| 188 | break;
|
|---|
| 189 | }
|
|---|
| 190 |
|
|---|
| 191 | while (pending >= open_max)
|
|---|
| 192 | files = poll_open (
|
|---|
| 193 | files, &pending, SHORT_TIMEOUT);
|
|---|
| 194 | }
|
|---|
| 195 |
|
|---|
| 196 | files = poll_open (files, &pending, LONG_TIMEOUT);
|
|---|
| 197 |
|
|---|
| 198 | while (files) {
|
|---|
| 199 | free_socket_entry (files->data);
|
|---|
| 200 | files = g_list_delete_link (files, files);
|
|---|
| 201 | }
|
|---|
| 202 | }
|
|---|
| 203 |
|
|---|
| 204 | #endif /* AF_UNIX */
|
|---|
| 205 |
|
|---|
| 206 | int
|
|---|
| 207 | main (int argc, char **argv)
|
|---|
| 208 | {
|
|---|
| 209 | char *dir;
|
|---|
| 210 |
|
|---|
| 211 | dir = g_strdup_printf ("%s/orbit-%s", g_get_tmp_dir (), g_get_user_name ());
|
|---|
| 212 |
|
|---|
| 213 | #ifdef AF_UNIX
|
|---|
| 214 | clean_dir (dir);
|
|---|
| 215 | #endif /* AF_UNIX */
|
|---|
| 216 |
|
|---|
| 217 | g_free (dir);
|
|---|
| 218 |
|
|---|
| 219 | printf ("Cleaned %d files %d still live\n",
|
|---|
| 220 | cleaned_count,
|
|---|
| 221 | total_count - cleaned_count);
|
|---|
| 222 |
|
|---|
| 223 | return 0;
|
|---|
| 224 | }
|
|---|