2
Watch code for Xen Store Daemon.
3
Copyright (C) 2005 Rusty Russell IBM Corporation
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.
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.
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
21
#include <sys/types.h>
29
#include "xenstored_watch.h"
32
#include "xenstored_domain.h"
34
extern int quota_nb_watch_per_domain;
38
/* Watches on this connection */
39
struct list_head list;
41
/* Current outstanding events applying to this watch. */
42
struct list_head events;
44
/* Is this relative to connnection's implicit path? */
45
const char *relative_path;
51
static void add_event(struct connection *conn,
55
/* Data to send (node\0token\0). */
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);
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...
71
if (!node && errno != ENOENT && errno != EACCES)
75
if (watch->relative_path) {
76
name += strlen(watch->relative_path);
77
if (*name == '/') /* Could be "" */
81
len = strlen(name) + 1 + strlen(watch->token) + 1;
82
data = talloc_array(watch, char, len);
84
strcpy(data + strlen(name) + 1, watch->token);
85
send_reply(conn, XS_WATCH_EVENT, data, len);
89
void fire_watches(struct connection *conn, const char *name, bool recurse)
94
/* During transactions, don't fire watches. */
95
if (conn && conn->transaction)
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);
109
static int destroy_watch(void *_watch)
111
trace_destroy(_watch, "watch");
115
void do_watch(struct connection *conn, struct buffered_data *in)
121
if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) {
122
send_error(conn, EINVAL);
126
if (strstarts(vec[0], "@")) {
128
if (strlen(vec[0]) > XENSTORE_REL_PATH_MAX) {
129
send_error(conn, EINVAL);
132
/* check if valid event */
134
relative = !strstarts(vec[0], "/");
135
vec[0] = canonicalize(conn, vec[0]);
136
if (!is_valid_nodename(vec[0])) {
137
send_error(conn, errno);
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);
151
if (domain_watch(conn) > quota_nb_watch_per_domain) {
152
send_error(conn, E2BIG);
156
watch = talloc(conn, struct watch);
157
watch->node = talloc_strdup(watch, vec[0]);
158
watch->token = talloc_strdup(watch, vec[1]);
160
watch->relative_path = get_implicit_path(conn);
162
watch->relative_path = NULL;
164
INIT_LIST_HEAD(&watch->events);
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);
172
/* We fire once up front: simplifies clients and restart. */
173
add_event(conn, watch, watch->node);
176
void do_unwatch(struct connection *conn, struct buffered_data *in)
181
if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) {
182
send_error(conn, EINVAL);
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);
191
domain_watch_dec(conn);
192
send_ack(conn, XS_UNWATCH);
196
send_error(conn, ENOENT);
199
void conn_delete_all_watches(struct connection *conn)
203
while ((watch = list_top(&conn->watches, struct watch, list))) {
204
list_del(&watch->list);
206
domain_watch_dec(conn);
212
* c-file-style: "linux"
213
* indent-tabs-mode: t