~ubuntu-branches/ubuntu/utopic/xen/utopic

« back to all changes in this revision

Viewing changes to tools/xenstore/xenstored_watch.c

  • Committer: Bazaar Package Importer
  • Author(s): Bastian Blank
  • Date: 2010-05-06 15:47:38 UTC
  • mto: (1.3.1) (15.1.1 sid) (4.1.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20100506154738-agoz0rlafrh1fnq7
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
    Watch code for Xen Store Daemon.
 
3
    Copyright (C) 2005 Rusty Russell IBM Corporation
 
4
 
 
5
    This program is free software; you can redistribute it and/or modify
 
6
    it under the terms of the GNU General Public License as published by
 
7
    the Free Software Foundation; either version 2 of the License, or
 
8
    (at your option) any later version.
 
9
 
 
10
    This program is distributed in the hope that it will be useful,
 
11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
    GNU General Public License for more details.
 
14
 
 
15
    You should have received a copy of the GNU General Public License
 
16
    along with this program; if not, write to the Free Software
 
17
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
18
*/
 
19
 
 
20
#include <stdio.h>
 
21
#include <sys/types.h>
 
22
#include <stdarg.h>
 
23
#include <stdlib.h>
 
24
#include <sys/time.h>
 
25
#include <time.h>
 
26
#include <assert.h>
 
27
#include "talloc.h"
 
28
#include "list.h"
 
29
#include "xenstored_watch.h"
 
30
#include "xs_lib.h"
 
31
#include "utils.h"
 
32
#include "xenstored_domain.h"
 
33
 
 
34
extern int quota_nb_watch_per_domain;
 
35
 
 
36
struct watch
 
37
{
 
38
        /* Watches on this connection */
 
39
        struct list_head list;
 
40
 
 
41
        /* Current outstanding events applying to this watch. */
 
42
        struct list_head events;
 
43
 
 
44
        /* Is this relative to connnection's implicit path? */
 
45
        const char *relative_path;
 
46
 
 
47
        char *token;
 
48
        char *node;
 
49
};
 
50
 
 
51
static void add_event(struct connection *conn,
 
52
                      struct watch *watch,
 
53
                      const char *name)
 
54
{
 
55
        /* Data to send (node\0token\0). */
 
56
        unsigned int len;
 
57
        char *data;
 
58
 
 
59
        if (!check_event_node(name)) {
 
60
                /* Can this conn load node, or see that it doesn't exist? */
 
61
                struct node *node = get_node(conn, name, XS_PERM_READ);
 
62
                /*
 
63
                 * XXX We allow EACCES here because otherwise a non-dom0
 
64
                 * backend driver cannot watch for disappearance of a frontend
 
65
                 * xenstore directory. When the directory disappears, we
 
66
                 * revert to permissions of the parent directory for that path,
 
67
                 * which will typically disallow access for the backend.
 
68
                 * But this breaks device-channel teardown!
 
69
                 * Really we should fix this better...
 
70
                 */
 
71
                if (!node && errno != ENOENT && errno != EACCES)
 
72
                        return;
 
73
        }
 
74
 
 
75
        if (watch->relative_path) {
 
76
                name += strlen(watch->relative_path);
 
77
                if (*name == '/') /* Could be "" */
 
78
                        name++;
 
79
        }
 
80
 
 
81
        len = strlen(name) + 1 + strlen(watch->token) + 1;
 
82
        data = talloc_array(watch, char, len);
 
83
        strcpy(data, name);
 
84
        strcpy(data + strlen(name) + 1, watch->token);
 
85
        send_reply(conn, XS_WATCH_EVENT, data, len);
 
86
        talloc_free(data);
 
87
}
 
88
 
 
89
void fire_watches(struct connection *conn, const char *name, bool recurse)
 
90
{
 
91
        struct connection *i;
 
92
        struct watch *watch;
 
93
 
 
94
        /* During transactions, don't fire watches. */
 
95
        if (conn && conn->transaction)
 
96
                return;
 
97
 
 
98
        /* Create an event for each watch. */
 
99
        list_for_each_entry(i, &connections, list) {
 
100
                list_for_each_entry(watch, &i->watches, list) {
 
101
                        if (is_child(name, watch->node))
 
102
                                add_event(i, watch, name);
 
103
                        else if (recurse && is_child(watch->node, name))
 
104
                                add_event(i, watch, watch->node);
 
105
                }
 
106
        }
 
107
}
 
108
 
 
109
static int destroy_watch(void *_watch)
 
110
{
 
111
        trace_destroy(_watch, "watch");
 
112
        return 0;
 
113
}
 
114
 
 
115
void do_watch(struct connection *conn, struct buffered_data *in)
 
116
{
 
117
        struct watch *watch;
 
118
        char *vec[2];
 
119
        bool relative;
 
120
 
 
121
        if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) {
 
122
                send_error(conn, EINVAL);
 
123
                return;
 
124
        }
 
125
 
 
126
        if (strstarts(vec[0], "@")) {
 
127
                relative = false;
 
128
                if (strlen(vec[0]) > XENSTORE_REL_PATH_MAX) {
 
129
                        send_error(conn, EINVAL);
 
130
                        return;
 
131
                }
 
132
                /* check if valid event */
 
133
        } else {
 
134
                relative = !strstarts(vec[0], "/");
 
135
                vec[0] = canonicalize(conn, vec[0]);
 
136
                if (!is_valid_nodename(vec[0])) {
 
137
                        send_error(conn, errno);
 
138
                        return;
 
139
                }
 
140
        }
 
141
 
 
142
        /* Check for duplicates. */
 
143
        list_for_each_entry(watch, &conn->watches, list) {
 
144
                if (streq(watch->node, vec[0]) &&
 
145
                    streq(watch->token, vec[1])) {
 
146
                        send_error(conn, EEXIST);
 
147
                        return;
 
148
                }
 
149
        }
 
150
 
 
151
        if (domain_watch(conn) > quota_nb_watch_per_domain) {
 
152
                send_error(conn, E2BIG);
 
153
                return;
 
154
        }
 
155
 
 
156
        watch = talloc(conn, struct watch);
 
157
        watch->node = talloc_strdup(watch, vec[0]);
 
158
        watch->token = talloc_strdup(watch, vec[1]);
 
159
        if (relative)
 
160
                watch->relative_path = get_implicit_path(conn);
 
161
        else
 
162
                watch->relative_path = NULL;
 
163
 
 
164
        INIT_LIST_HEAD(&watch->events);
 
165
 
 
166
        domain_watch_inc(conn);
 
167
        list_add_tail(&watch->list, &conn->watches);
 
168
        trace_create(watch, "watch");
 
169
        talloc_set_destructor(watch, destroy_watch);
 
170
        send_ack(conn, XS_WATCH);
 
171
 
 
172
        /* We fire once up front: simplifies clients and restart. */
 
173
        add_event(conn, watch, watch->node);
 
174
}
 
175
 
 
176
void do_unwatch(struct connection *conn, struct buffered_data *in)
 
177
{
 
178
        struct watch *watch;
 
179
        char *node, *vec[2];
 
180
 
 
181
        if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) {
 
182
                send_error(conn, EINVAL);
 
183
                return;
 
184
        }
 
185
 
 
186
        node = canonicalize(conn, vec[0]);
 
187
        list_for_each_entry(watch, &conn->watches, list) {
 
188
                if (streq(watch->node, node) && streq(watch->token, vec[1])) {
 
189
                        list_del(&watch->list);
 
190
                        talloc_free(watch);
 
191
                        domain_watch_dec(conn);
 
192
                        send_ack(conn, XS_UNWATCH);
 
193
                        return;
 
194
                }
 
195
        }
 
196
        send_error(conn, ENOENT);
 
197
}
 
198
 
 
199
void conn_delete_all_watches(struct connection *conn)
 
200
{
 
201
        struct watch *watch;
 
202
 
 
203
        while ((watch = list_top(&conn->watches, struct watch, list))) {
 
204
                list_del(&watch->list);
 
205
                talloc_free(watch);
 
206
                domain_watch_dec(conn);
 
207
        }
 
208
}
 
209
 
 
210
/*
 
211
 * Local variables:
 
212
 *  c-file-style: "linux"
 
213
 *  indent-tabs-mode: t
 
214
 *  c-indent-level: 8
 
215
 *  c-basic-offset: 8
 
216
 *  tab-width: 8
 
217
 * End:
 
218
 */