debuggers.hg

view tools/xenstore/xenstored_watch.c @ 22848:6341fe0f4e5a

Added tag 4.1.0-rc2 for changeset 9dca60d88c63
author Keir Fraser <keir@xen.org>
date Tue Jan 25 14:06:55 2011 +0000 (2011-01-25)
parents dcdb3805262a
children
line source
1 /*
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
18 */
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"
34 extern int quota_nb_watch_per_domain;
36 struct watch
37 {
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;
47 char *token;
48 char *node;
49 };
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;
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 }
75 if (watch->relative_path) {
76 name += strlen(watch->relative_path);
77 if (*name == '/') /* Could be "" */
78 name++;
79 }
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 }
89 void fire_watches(struct connection *conn, const char *name, bool recurse)
90 {
91 struct connection *i;
92 struct watch *watch;
94 /* During transactions, don't fire watches. */
95 if (conn && conn->transaction)
96 return;
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 }
109 static int destroy_watch(void *_watch)
110 {
111 trace_destroy(_watch, "watch");
112 return 0;
113 }
115 void do_watch(struct connection *conn, struct buffered_data *in)
116 {
117 struct watch *watch;
118 char *vec[2];
119 bool relative;
121 if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) {
122 send_error(conn, EINVAL);
123 return;
124 }
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, EINVAL);
138 return;
139 }
140 }
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 }
151 if (domain_watch(conn) > quota_nb_watch_per_domain) {
152 send_error(conn, E2BIG);
153 return;
154 }
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;
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);
174 }
176 void do_unwatch(struct connection *conn, struct buffered_data *in)
177 {
178 struct watch *watch;
179 char *node, *vec[2];
181 if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) {
182 send_error(conn, EINVAL);
183 return;
184 }
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 }
199 void conn_delete_all_watches(struct connection *conn)
200 {
201 struct watch *watch;
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 }
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 */