1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
5 * Authors: Michael Zucchi <notzed@ximian.com>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of version 2 of the GNU Lesser General Public
9 * License as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
33 #include <sys/types.h>
36 #include "camel-lock-client.h"
37 #include "camel-lock-helper.h"
38 #include "camel-object.h"
42 /* dunno where this thing is got from */
43 /* see also camel-lock.c */
46 static GMutex lock_lock;
47 #define LOCK() g_mutex_lock(&lock_lock)
48 #define UNLOCK() g_mutex_unlock(&lock_lock)
50 static gint lock_sequence;
51 static gint lock_helper_pid = -1;
52 static gint lock_stdin_pipe[2], lock_stdout_pipe[2];
54 static gint read_n (gint fd, gpointer buffer, gint inlen)
57 gint len, left = inlen;
60 len = read (fd, p, left);
68 } while (left > 0 && len != 0);
73 static gint write_n (gint fd, gpointer buffer, gint inlen)
76 gint len, left = inlen;
79 len = write (fd, p, left);
93 lock_helper_init (GError **error)
97 lock_stdin_pipe[0] = -1;
98 lock_stdin_pipe[1] = -1;
99 lock_stdout_pipe[0] = -1;
100 lock_stdout_pipe[1] = -1;
101 if (pipe (lock_stdin_pipe) == -1
102 || pipe (lock_stdout_pipe) == -1) {
105 g_io_error_from_errno (errno),
106 _("Cannot build locking helper pipe: %s"),
108 if (lock_stdin_pipe[0] != -1)
109 close (lock_stdin_pipe[0]);
110 if (lock_stdin_pipe[1] != -1)
111 close (lock_stdin_pipe[1]);
112 if (lock_stdout_pipe[0] != -1)
113 close (lock_stdout_pipe[0]);
114 if (lock_stdout_pipe[1] != -1)
115 close (lock_stdout_pipe[1]);
120 lock_helper_pid = fork ();
121 switch (lock_helper_pid) {
123 close (lock_stdin_pipe[0]);
124 close (lock_stdin_pipe[1]);
125 close (lock_stdout_pipe[0]);
126 close (lock_stdout_pipe[1]);
129 g_io_error_from_errno (errno),
130 _("Cannot fork locking helper: %s"),
134 close (STDIN_FILENO);
135 dup (lock_stdin_pipe[0]);
136 close (STDOUT_FILENO);
137 dup (lock_stdout_pipe[1]);
138 close (lock_stdin_pipe[0]);
139 close (lock_stdin_pipe[1]);
140 close (lock_stdout_pipe[0]);
141 close (lock_stdout_pipe[1]);
142 for (i = 3; i < 255; i++)
144 execl (CAMEL_LIBEXECDIR "/camel-lock-helper-" API_VERSION, "camel-lock-helper", NULL);
145 /* it'll pick this up when it tries to use us */
148 close (lock_stdin_pipe[0]);
149 close (lock_stdout_pipe[1]);
151 /* so the child knows when we vanish */
152 fcntl (lock_stdin_pipe[1], F_SETFD, FD_CLOEXEC);
153 fcntl (lock_stdout_pipe[0], F_SETFD, FD_CLOEXEC);
160 camel_lock_helper_lock (const gchar *path,
163 struct _CamelLockHelperMsg *msg;
164 gint len = strlen (path);
170 if (lock_helper_pid == -1) {
171 if (lock_helper_init (error) == -1) {
177 msg = alloca (len + sizeof (*msg));
179 msg->magic = CAMEL_LOCK_HELPER_MAGIC;
180 msg->seq = lock_sequence;
181 msg->id = CAMEL_LOCK_HELPER_LOCK;
183 memcpy (msg + 1, path, len);
185 write_n (lock_stdin_pipe[1], msg, len + sizeof (*msg));
188 /* should also have a timeout here? cancellation? */
189 len = read_n (lock_stdout_pipe[0], msg, sizeof (*msg));
191 /* child quit, do we try ressurect it? */
192 res = CAMEL_LOCK_HELPER_STATUS_PROTOCOL;
193 /* if the child exited, this should get it, waidpid returns 0 if the child hasn't */
194 if (waitpid (lock_helper_pid, NULL, WNOHANG) > 0) {
195 lock_helper_pid = -1;
196 close (lock_stdout_pipe[0]);
197 close (lock_stdin_pipe[1]);
198 lock_stdout_pipe[0] = -1;
199 lock_stdin_pipe[1] = -1;
204 if (msg->magic != CAMEL_LOCK_HELPER_RETURN_MAGIC
205 || msg->seq > lock_sequence) {
206 res = CAMEL_LOCK_HELPER_STATUS_PROTOCOL;
207 d (printf ("lock child protocol error\n"));
211 _("Could not lock '%s': protocol "
212 "error with lock-helper"), path);
215 } while (msg->seq < lock_sequence);
217 if (msg->seq == lock_sequence) {
219 case CAMEL_LOCK_HELPER_STATUS_OK:
220 d (printf ("lock child locked ok, id is %d\n", msg->data));
227 _("Could not lock '%s'"), path);
228 d (printf ("locking failed ! status = %d\n", msg->id));
231 } else if (retry > 0) {
232 d (printf ("sequence failure, lost message? retry?\n"));
239 _("Could not lock '%s': protocol "
240 "error with lock-helper"), path);
251 gint camel_lock_helper_unlock (gint lockid)
253 struct _CamelLockHelperMsg *msg;
258 d (printf ("unlocking lock id %d\n", lockid));
262 /* impossible to unlock if we haven't locked yet */
263 if (lock_helper_pid == -1) {
268 msg = alloca (sizeof (*msg));
270 msg->magic = CAMEL_LOCK_HELPER_MAGIC;
271 msg->seq = lock_sequence;
272 msg->id = CAMEL_LOCK_HELPER_UNLOCK;
275 write_n (lock_stdin_pipe[1], msg, sizeof (*msg));
278 /* should also have a timeout here? cancellation? */
279 len = read_n (lock_stdout_pipe[0], msg, sizeof (*msg));
281 /* child quit, do we try ressurect it? */
282 res = CAMEL_LOCK_HELPER_STATUS_PROTOCOL;
283 if (waitpid (lock_helper_pid, NULL, WNOHANG) > 0) {
284 lock_helper_pid = -1;
285 close (lock_stdout_pipe[0]);
286 close (lock_stdin_pipe[1]);
287 lock_stdout_pipe[0] = -1;
288 lock_stdin_pipe[1] = -1;
293 if (msg->magic != CAMEL_LOCK_HELPER_RETURN_MAGIC
294 || msg->seq > lock_sequence) {
297 } while (msg->seq < lock_sequence);
299 if (msg->seq == lock_sequence) {
301 case CAMEL_LOCK_HELPER_STATUS_OK:
302 d (printf ("lock child unlocked ok\n"));
306 d (printf ("locking failed !\n"));
309 } else if (retry > 0) {
310 d (printf ("sequence failure, lost message? retry?\n"));
325 gint main (gint argc, gchar **argv)
329 d (printf ("locking started\n"));
332 id1 = camel_lock_helper_lock ("1 path 1");
334 d (printf ("lock ok, unlock\n"));
335 camel_lock_helper_unlock (id1);
338 id1 = camel_lock_helper_lock ("2 path 1");
339 id2 = camel_lock_helper_lock ("2 path 2");
340 camel_lock_helper_unlock (id2);
341 camel_lock_helper_unlock (id1);
343 id1 = camel_lock_helper_lock ("3 path 1");
344 id2 = camel_lock_helper_lock ("3 path 2");
345 camel_lock_helper_unlock (id1);