~ubuntu-branches/ubuntu/maverick/dbus/maverick-security

« back to all changes in this revision

Viewing changes to .pc/11-589662-reload-kqueue.patch/bus/dir-watch-kqueue.c

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2010-09-27 13:06:32 UTC
  • mfrom: (1.1.23 upstream)
  • Revision ID: james.westby@ubuntu.com-20100927130632-bqs145trvchd2lmf
Tags: 1.4.0-0ubuntu1
* New upstream release
 - Fixes https://bugs.freedesktop.org/show_bug.cgi?id=17754 Race condition in protected_change_timeout
 - Requested by various upstream KDE developers http://lists.kde.org/?t=128514970000004&r=1&w=2

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
 
/* dir-watch-kqueue.c  OS specific directory change notification for message bus
3
 
 *
4
 
 * Copyright (C) 2003 Red Hat, Inc.
5
 
 *
6
 
 * Licensed under the Academic Free License version 2.1
7
 
 * 
8
 
 * This program is free software; you can redistribute it and/or modify
9
 
 * it under the terms of the GNU General Public License as published by
10
 
 * the Free Software Foundation; either version 2 of the License, or
11
 
 * (at your option) any later version.
12
 
 *
13
 
 * This program is distributed in the hope that it will be useful,
14
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 
 * GNU General Public License for more details.
17
 
 * 
18
 
 * You should have received a copy of the GNU General Public License
19
 
 * along with this program; if not, write to the Free Software
20
 
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21
 
 *
22
 
 */
23
 
 
24
 
#include <config.h>
25
 
 
26
 
#include <sys/types.h>
27
 
#include <sys/event.h>
28
 
#include <sys/time.h>
29
 
#include <signal.h>
30
 
#include <fcntl.h>
31
 
#include <unistd.h>
32
 
#ifdef HAVE_ERRNO_H
33
 
#include <errno.h>
34
 
#endif
35
 
 
36
 
#include "bus.h"
37
 
#include <dbus/dbus-watch.h>
38
 
 
39
 
#include <dbus/dbus-internals.h>
40
 
#include <dbus/dbus-list.h>
41
 
#include "dir-watch.h"
42
 
 
43
 
#define MAX_DIRS_TO_WATCH 128
44
 
 
45
 
static int kq = -1;
46
 
static int fds[MAX_DIRS_TO_WATCH];
47
 
static char *dirs[MAX_DIRS_TO_WATCH];
48
 
static int num_fds = 0;
49
 
static DBusWatch *watch = NULL;
50
 
static DBusLoop *loop = NULL;
51
 
 
52
 
static dbus_bool_t
53
 
_kqueue_watch_callback (DBusWatch *watch, unsigned int condition, void *data)
54
 
{
55
 
  return dbus_watch_handle (watch, condition);
56
 
}
57
 
 
58
 
static dbus_bool_t
59
 
_handle_kqueue_watch (DBusWatch *watch, unsigned int flags, void *data)
60
 
{
61
 
  struct kevent ev;
62
 
  struct timespec nullts = { 0, 0 };
63
 
  int res;
64
 
  pid_t pid;
65
 
 
66
 
  res = kevent (kq, NULL, 0, &ev, 1, &nullts);
67
 
 
68
 
  /* Sleep for half a second to avoid a race when files are install(1)'d
69
 
   * to system.d. */
70
 
  usleep(500000);
71
 
 
72
 
  if (res > 0)
73
 
    {
74
 
      pid = getpid ();
75
 
      _dbus_verbose ("Sending SIGHUP signal on reception of a kevent\n");
76
 
      (void) kill (pid, SIGHUP);
77
 
    }
78
 
  else if (res < 0 && errno == EBADF)
79
 
    {
80
 
      kq = -1;
81
 
      if (watch != NULL)
82
 
        {
83
 
          _dbus_loop_remove_watch (loop, watch, _kqueue_watch_callback, NULL);
84
 
          _dbus_watch_unref (watch);
85
 
          watch = NULL;
86
 
        }
87
 
      pid = getpid ();
88
 
      _dbus_verbose ("Sending SIGHUP signal since kqueue has been closed\n");
89
 
      (void) kill (pid, SIGHUP);
90
 
    }
91
 
 
92
 
  return TRUE;
93
 
}
94
 
 
95
 
static int
96
 
_init_kqueue (BusContext *context)
97
 
{
98
 
  int ret = 0;
99
 
 
100
 
  if (kq < 0)
101
 
    {
102
 
 
103
 
      kq = kqueue ();
104
 
      if (kq < 0)
105
 
        {
106
 
          _dbus_warn ("Cannot create kqueue; error '%s'\n", _dbus_strerror (errno));
107
 
          goto out;
108
 
        }
109
 
 
110
 
        loop = bus_context_get_loop (context);
111
 
 
112
 
        watch = _dbus_watch_new (kq, DBUS_WATCH_READABLE, TRUE,
113
 
                                 _handle_kqueue_watch, NULL, NULL);
114
 
 
115
 
        if (watch == NULL)
116
 
          {
117
 
            _dbus_warn ("Unable to create kqueue watch\n");
118
 
            close (kq);
119
 
            kq = -1;
120
 
            goto out;
121
 
          }
122
 
 
123
 
        if (!_dbus_loop_add_watch (loop, watch, _kqueue_watch_callback,
124
 
                                   NULL, NULL))
125
 
          {
126
 
            _dbus_warn ("Unable to add reload watch to main loop");
127
 
            close (kq);
128
 
            kq = -1;
129
 
            _dbus_watch_unref (watch);
130
 
            watch = NULL;
131
 
            goto out;
132
 
          }
133
 
    }
134
 
 
135
 
  ret = 1;
136
 
 
137
 
out:
138
 
  return ret;
139
 
}
140
 
 
141
 
void
142
 
bus_set_watched_dirs (BusContext *context, DBusList **directories)
143
 
{
144
 
  int new_fds[MAX_DIRS_TO_WATCH];
145
 
  char *new_dirs[MAX_DIRS_TO_WATCH];
146
 
  DBusList *link;
147
 
  int i, j, f, fd;
148
 
  struct kevent ev;
149
 
 
150
 
  if (!_init_kqueue (context))
151
 
    goto out;
152
 
 
153
 
  for (i = 0; i < MAX_DIRS_TO_WATCH; i++)
154
 
    {
155
 
      new_fds[i] = -1;
156
 
      new_dirs[i] = NULL;
157
 
    }
158
 
 
159
 
  i = 0;
160
 
  link = _dbus_list_get_first_link (directories);
161
 
  while (link != NULL)
162
 
    {
163
 
      new_dirs[i++] = (char *)link->data;
164
 
      link = _dbus_list_get_next_link (directories, link);
165
 
    }
166
 
 
167
 
  /* Look for directories in both the old and new sets, if
168
 
   * we find one, move its data into the new set.
169
 
   */
170
 
  for (i = 0; new_dirs[i]; i++)
171
 
    {
172
 
      for (j = 0; i < num_fds; j++)
173
 
        {
174
 
          if (dirs[j] && strcmp (new_dirs[i], dirs[j]) == 0)
175
 
            {
176
 
              new_fds[i] = fds[j];
177
 
              new_dirs[i] = dirs[j];
178
 
              fds[j] = -1;
179
 
              dirs[j] = NULL;
180
 
              break;
181
 
            }
182
 
        }
183
 
    }
184
 
 
185
 
  /* Any directory we find in "fds" with a nonzero fd must
186
 
   * not be in the new set, so perform cleanup now.
187
 
   */
188
 
  for (j = 0; j < num_fds; j++)
189
 
    {
190
 
      if (fds[j] != -1)
191
 
        {
192
 
          close (fds[j]);
193
 
          dbus_free (dirs[j]);
194
 
          fds[j] = -1;
195
 
          dirs[j] = NULL;
196
 
        }
197
 
    }
198
 
 
199
 
  for (i = 0; new_dirs[i]; i++)
200
 
    {
201
 
      if (new_fds[i] == -1)
202
 
        {
203
 
          /* FIXME - less lame error handling for failing to add a watch;
204
 
           * we may need to sleep.
205
 
           */
206
 
          fd = open (new_dirs[i], O_RDONLY);
207
 
          if (fd < 0)
208
 
            {
209
 
              if (errno != ENOENT)
210
 
                {
211
 
                  _dbus_warn ("Cannot open directory '%s'; error '%s'\n", new_dirs[i], _dbus_strerror (errno));
212
 
                  goto out;
213
 
                }
214
 
              else
215
 
                {
216
 
                  new_fds[i] = -1;
217
 
                  new_dirs[i] = NULL;
218
 
                  continue;
219
 
                }
220
 
            }
221
 
 
222
 
          EV_SET (&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
223
 
                  NOTE_DELETE | NOTE_EXTEND | NOTE_WRITE | NOTE_RENAME, 0, 0);
224
 
          if (kevent (kq, &ev, 1, NULL, 0, NULL) == -1)
225
 
            {
226
 
              _dbus_warn ("Cannot setup a kevent for '%s'; error '%s'\n", new_dirs[i], _dbus_strerror (errno));
227
 
              close (fd);
228
 
              goto out;
229
 
            }
230
 
 
231
 
          new_fds[i] = fd;
232
 
          new_dirs[i] = _dbus_strdup (new_dirs[i]);
233
 
          if (!new_dirs[i])
234
 
            {
235
 
              /* FIXME have less lame handling for OOM, we just silently fail to
236
 
               * watch.  (In reality though, the whole OOM handling in dbus is
237
 
               * stupid but we won't go into that in this comment =) )
238
 
               */
239
 
              close (fd);
240
 
              new_fds[i] = -1;
241
 
            }
242
 
        }
243
 
    }
244
 
 
245
 
  num_fds = i;
246
 
 
247
 
  for (i = 0; i < MAX_DIRS_TO_WATCH; i++)
248
 
    {
249
 
      fds[i] = new_fds[i];
250
 
      dirs[i] = new_dirs[i];
251
 
    }
252
 
 
253
 
 out:
254
 
  ;
255
 
}