Blame view

control.c 6.24 KB
redmine authored
1
/*
redmine authored
2
    clsync - file tree sync utility based on inotify
redmine authored
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
    
    Copyright (C) 2013  Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
    
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "common.h"

#include <sys/un.h>	// for "struct sockaddr_un"
redmine authored
23 24 25 26
#include <sys/stat.h>	// mkdir()
#include <sys/types.h>	// mkdir()
#include <fcntl.h>	// mkdirat()
#include <glib.h>	// g_hash_table_foreach()
redmine authored
27

redmine authored
28 29

#include "indexes.h"
redmine authored
30
#include "main.h"
redmine authored
31
#include "ctx.h"
redmine authored
32
#include "error.h"
redmine authored
33 34
#include "sync.h"
#include "control.h"
redmine authored
35
#include "socket.h"
redmine authored
36 37 38

static pthread_t pthread_control;

redmine authored
39

redmine authored
40
static inline int control_error(clsyncsock_t *clsyncsock_p, sockcmd_t *sockcmd_p, const char *const funct, const char *const args) {
redmine authored
41
	debug(3, "%s(%s): %u: %s", funct, args, errno, strerror(errno));
redmine authored
42
	return socket_reply(clsyncsock_p, sockcmd_p, SOCKCMD_REPLY_ECUSTOM, funct, args, errno, strerror(errno));
redmine authored
43 44 45 46 47 48
}


int control_dump(ctx_t *ctx_p, clsyncsock_t *clsyncsock_p, sockcmd_t *sockcmd_p) {
	sockcmd_dat_dump_t *dat		= sockcmd_p->data;

redmine authored
49
	debug(3, "%s", dat->dir_path);
redmine authored
50

redmine authored
51
	return (sync_dump(ctx_p, dat->dir_path)) ? 
redmine authored
52 53
		control_error(clsyncsock_p, sockcmd_p, "sync_dump", dat->dir_path) :
		socket_reply(clsyncsock_p, sockcmd_p, SOCKCMD_REPLY_DUMP);
redmine authored
54 55
}

redmine authored
56
int control_procclsyncsock(socket_sockthreaddata_t *arg, sockcmd_t *sockcmd_p) {
redmine authored
57
	int rc;
redmine authored
58 59
	clsyncsock_t	*clsyncsock_p =          arg->clsyncsock_p;
	ctx_t		*ctx_p        = (ctx_t *)arg->arg;
redmine authored
60 61

	switch(sockcmd_p->cmd_id) {
redmine authored
62
		case SOCKCMD_REQUEST_DUMP:
redmine authored
63
			rc = control_dump(ctx_p, clsyncsock_p, sockcmd_p);
redmine authored
64 65
			break;
		case SOCKCMD_REQUEST_INFO:
redmine authored
66
			rc = socket_reply(clsyncsock_p, sockcmd_p, SOCKCMD_REPLY_INFO, ctx_p->config_block, ctx_p->label, ctx_p->flags, ctx_p->flags_set);
redmine authored
67
			break;
redmine authored
68 69 70 71
		case SOCKCMD_REQUEST_SET: {
			sockcmd_dat_set_t *dat = sockcmd_p->data;
			rc = ctx_set(ctx_p, dat->key, dat->value);
			if (rc) {
redmine authored
72
				control_error(clsyncsock_p, sockcmd_p, "ctx_set", dat->key);
redmine authored
73 74
				break;
			}
redmine authored
75
			rc = socket_reply(clsyncsock_p, sockcmd_p, SOCKCMD_REPLY_SET);
redmine authored
76 77
			break;
		}
redmine authored
78
		case SOCKCMD_REQUEST_DIE:
redmine authored
79
			rc = sync_term(SIGTERM);
redmine authored
80
			break;
redmine authored
81 82
		default:
			return EINVAL;
redmine authored
83 84
	}

redmine authored
85 86
	debug(3, "rc == %u", rc);
	return rc;
redmine authored
87 88
}

redmine authored
89 90 91 92
static inline void closecontrol(ctx_t *ctx_p) {
	if(ctx_p->socket) {
		close(ctx_p->socket);
		ctx_p->socket = 0;
redmine authored
93 94 95
	}
}

redmine authored
96
int control_loop(ctx_t *ctx_p) {
redmine authored
97 98 99

	// Starting

redmine authored
100
	debug(1, "started (ctx_p->socket == %u)", ctx_p->socket);
redmine authored
101 102
	int s;

redmine authored
103
	while((s=ctx_p->socket)) {
redmine authored
104 105 106

		// Check if the socket is still alive
		if(socket_check_bysock(s)) {
redmine authored
107
			error("Control socket closed [case 0]");
redmine authored
108
			closecontrol(ctx_p);
redmine authored
109 110 111 112
			continue;
		}

		// Waiting for event
redmine authored
113
		debug(3, "waiting for events on the socket");
redmine authored
114 115 116 117 118 119 120 121
		fd_set rfds;

		FD_ZERO(&rfds);
		FD_SET(s, &rfds);

		int count = select(s+1, &rfds, NULL, NULL, NULL);

		// Processing the events
redmine authored
122
		debug(2, "got %i events with select()", count);
redmine authored
123 124 125

		// Processing the events: checks
		if(count == 0) {
redmine authored
126
			debug(2, "select() timed out.");
redmine authored
127 128 129 130
			continue;
		}

		if(count < 0) {
redmine authored
131
			debug(1, "Got negative events count. Closing the socket.");
redmine authored
132
			closecontrol(ctx_p);
redmine authored
133 134 135 136
			continue;
		}

		if(!FD_ISSET(s, &rfds)) {
redmine authored
137
			error("Got event, but not on the control socket. Closing the socket (cannot use \"select()\").");
redmine authored
138
			closecontrol(ctx_p);
redmine authored
139 140 141
			continue;
		}

redmine authored
142
		// Processing the events: accepting new clsyncsock
redmine authored
143

redmine authored
144 145
		clsyncsock_t *clsyncsock_p = socket_accept(s);
		if(clsyncsock_p == NULL) {
redmine authored
146 147 148 149 150

			if(errno == EUSERS)	// Too many connections. Just ignoring the new one.
				continue;

			// Got unknown error. Closing control socket just in case.
redmine authored
151
			error("Cannot socket_accept()");
redmine authored
152
			closecontrol(ctx_p);
redmine authored
153 154 155
			continue;
		}

redmine authored
156
		debug(2, "Starting new thread for new connection.");
redmine authored
157
		socket_sockthreaddata_t *threaddata_p = socket_thread_attach(clsyncsock_p);
redmine authored
158

redmine authored
159
		if (threaddata_p == NULL) {
redmine authored
160
			error("Cannot create a thread for connection");
redmine authored
161
			closecontrol(ctx_p);
redmine authored
162 163 164
			continue;
		}

redmine authored
165 166
		threaddata_p->procfunct		=  control_procclsyncsock;
		threaddata_p->clsyncsock_p	=  clsyncsock_p;
redmine authored
167 168 169
		threaddata_p->arg		=  ctx_p;
		threaddata_p->running		= &ctx_p->socket;
		threaddata_p->authtype		=  ctx_p->flags[SOCKETAUTH];
redmine authored
170
		threaddata_p->flags		=  0;
redmine authored
171

redmine authored
172
		if (socket_thread_start(threaddata_p)) {
redmine authored
173
			error("Cannot start a thread for connection");
redmine authored
174
			closecontrol(ctx_p);
redmine authored
175 176 177
			continue;
		}
#ifdef DEBUG
redmine authored
178
		// To prevent too often connections
redmine authored
179 180 181 182 183 184
		sleep(1);
#endif
	}

	// Cleanup

redmine authored
185
	debug(1, "control_loop() finished");
redmine authored
186 187 188
	return 0;
}

redmine authored
189 190
int control_run(ctx_t *ctx_p) {
	if(ctx_p->socketpath != NULL) {
redmine authored
191 192
		int ret =  0;
		int s   = -1;
redmine authored
193 194

		// initializing clsync-socket subsystem
redmine authored
195
		if ((ret = socket_init()))
redmine authored
196
			error("Cannot init clsync-sockets subsystem.");
redmine authored
197 198


redmine authored
199
		if (!ret) {
redmine authored
200
			clsyncsock_t *clsyncsock = socket_listen_unix(ctx_p->socketpath);
redmine authored
201
			if (clsyncsock == NULL) {
redmine authored
202
				ret = errno;
redmine authored
203 204 205 206
			} else {
				s = clsyncsock->sock;
				socket_cleanup(clsyncsock);
			}
redmine authored
207 208 209
		}

		// fixing privileges
redmine authored
210
		if (!ret) {
redmine authored
211 212
			if(ctx_p->flags[SOCKETMOD])
				if(chmod(ctx_p->socketpath, ctx_p->socketmod)) {
redmine authored
213
					error("Error, Cannot chmod(\"%s\", %o)", 
redmine authored
214
						ctx_p->socketpath, ctx_p->socketmod);
redmine authored
215 216
					ret = errno;
				}
redmine authored
217 218
			if(ctx_p->flags[SOCKETOWN])
				if(chown(ctx_p->socketpath, ctx_p->socketuid, ctx_p->socketgid)) {
redmine authored
219
					error("Error, Cannot chown(\"%s\", %u, %u)", 
redmine authored
220
						ctx_p->socketpath, ctx_p->socketuid, ctx_p->socketgid);
redmine authored
221 222 223 224 225
					ret = errno;
				}
		}

		// finish
redmine authored
226
		if (ret) {
redmine authored
227 228 229 230
			close(s);
			return ret;
		}

redmine authored
231
		ctx_p->socket = s;
redmine authored
232

redmine authored
233
		debug(2, "ctx_p->socket = %u", ctx_p->socket);
redmine authored
234

redmine authored
235
		ret = pthread_create(&pthread_control, NULL, (void *(*)(void *))control_loop, ctx_p);
redmine authored
236 237 238 239 240
	}
	
	return 0;
}

redmine authored
241 242 243 244
int control_cleanup(ctx_t *ctx_p) {
	if(ctx_p->socketpath != NULL) {
		unlink(ctx_p->socketpath);
		closecontrol(ctx_p);
redmine authored
245 246 247 248 249 250 251
		// TODO: kill pthread_control and join
//		pthread_join(pthread_control, NULL);
		socket_deinit();
	}
	return 0;
}