ia64/xen-unstable

view tools/xenstore/xenstored_watch.c @ 8740:3d7ea7972b39

Update patches for linux 2.6.15.

Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Thu Feb 02 17:16:00 2006 +0000 (2006-02-02)
parents 74d56b7ff46c
children e7d769001b4b
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_test.h"
33 #include "xenstored_domain.h"
35 struct watch
36 {
37 /* Watches on this connection */
38 struct list_head list;
40 /* Current outstanding events applying to this watch. */
41 struct list_head events;
43 /* Is this relative to connnection's implicit path? */
44 const char *relative_path;
46 char *token;
47 char *node;
48 };
50 static void add_event(struct connection *conn,
51 struct watch *watch,
52 const char *name)
53 {
54 /* Data to send (node\0token\0). */
55 unsigned int len;
56 char *data;
58 if (!check_event_node(name)) {
59 /* Can this conn load node, or see that it doesn't exist? */
60 struct node *node = get_node(conn, name, XS_PERM_READ);
61 if (!node && errno != ENOENT)
62 return;
63 }
65 if (watch->relative_path) {
66 name += strlen(watch->relative_path);
67 if (*name == '/') /* Could be "" */
68 name++;
69 }
71 len = strlen(name) + 1 + strlen(watch->token) + 1;
72 data = talloc_array(watch, char, len);
73 strcpy(data, name);
74 strcpy(data + strlen(name) + 1, watch->token);
75 send_reply(conn, XS_WATCH_EVENT, data, len);
76 talloc_free(data);
77 }
79 /* FIXME: we fail to fire on out of memory. Should drop connections. */
80 void fire_watches(struct connection *conn, const char *name, bool recurse)
81 {
82 struct connection *i;
83 struct watch *watch;
85 /* During transactions, don't fire watches. */
86 if (conn && conn->transaction)
87 return;
89 /* Create an event for each watch. */
90 list_for_each_entry(i, &connections, list) {
91 list_for_each_entry(watch, &i->watches, list) {
92 if (is_child(name, watch->node))
93 add_event(i, watch, name);
94 else if (recurse && is_child(watch->node, name))
95 add_event(i, watch, watch->node);
96 }
97 }
98 }
100 static int destroy_watch(void *_watch)
101 {
102 trace_destroy(_watch, "watch");
103 return 0;
104 }
106 void do_watch(struct connection *conn, struct buffered_data *in)
107 {
108 struct watch *watch;
109 char *vec[2];
110 bool relative;
112 if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) {
113 send_error(conn, EINVAL);
114 return;
115 }
117 if (strstarts(vec[0], "@")) {
118 relative = false;
119 /* check if valid event */
120 } else {
121 relative = !strstarts(vec[0], "/");
122 vec[0] = canonicalize(conn, vec[0]);
123 if (!is_valid_nodename(vec[0])) {
124 send_error(conn, errno);
125 return;
126 }
127 }
129 /* Check for duplicates. */
130 list_for_each_entry(watch, &conn->watches, list) {
131 if (streq(watch->node, vec[0]) &&
132 streq(watch->token, vec[1])) {
133 send_error(conn, EEXIST);
134 return;
135 }
136 }
138 watch = talloc(conn, struct watch);
139 watch->node = talloc_strdup(watch, vec[0]);
140 watch->token = talloc_strdup(watch, vec[1]);
141 if (relative)
142 watch->relative_path = get_implicit_path(conn);
143 else
144 watch->relative_path = NULL;
146 INIT_LIST_HEAD(&watch->events);
148 list_add_tail(&watch->list, &conn->watches);
149 trace_create(watch, "watch");
150 talloc_set_destructor(watch, destroy_watch);
151 send_ack(conn, XS_WATCH);
153 /* We fire once up front: simplifies clients and restart. */
154 add_event(conn, watch, watch->node);
155 }
157 void do_unwatch(struct connection *conn, struct buffered_data *in)
158 {
159 struct watch *watch;
160 char *node, *vec[2];
162 if (get_strings(in, vec, ARRAY_SIZE(vec)) != ARRAY_SIZE(vec)) {
163 send_error(conn, EINVAL);
164 return;
165 }
167 node = canonicalize(conn, vec[0]);
168 list_for_each_entry(watch, &conn->watches, list) {
169 if (streq(watch->node, node) && streq(watch->token, vec[1])) {
170 list_del(&watch->list);
171 talloc_free(watch);
172 send_ack(conn, XS_UNWATCH);
173 return;
174 }
175 }
176 send_error(conn, ENOENT);
177 }
179 #ifdef TESTING
180 void dump_watches(struct connection *conn)
181 {
182 struct watch *watch;
184 list_for_each_entry(watch, &conn->watches, list)
185 printf(" watch on %s token %s\n",
186 watch->node, watch->token);
187 }
188 #endif
190 /*
191 * Local variables:
192 * c-file-style: "linux"
193 * indent-tabs-mode: t
194 * c-indent-level: 8
195 * c-basic-offset: 8
196 * tab-width: 8
197 * End:
198 */