2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4 * Copyright 2021 Olaf Wintermann. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
39 #include <sys/socket.h>
41 #include <sys/fcntl.h>
45 #include <libidav/utils.h>
47 #include <ucx/utils.h>
49 #define OPTSTR "hlpsuv"
51 #define TIMEOUT_IDLE -1
52 #define TIMEOUT_CLIENT 1000
53 #define CLIENT_UPDATE_INTERVALL 1
56 static char *socket_path;
62 int main(int argc, char** argv) {
66 extern int optind, opterr, optopt;
69 memset(&settings, 0, sizeof(CPSettings));
73 int list = 0; // list copying processes
76 while((c = getopt(argc, argv, OPTSTR)) != -1) {
78 case 'l': list = 1; break;
79 case 'p': settings.pause = 1; break;
80 case 's': settings.printsocket = 1; break;
81 case 'u': settings.url = 1; break;
82 case 'v': version = 1; break;
86 int ac = argc - optind;
96 settings.from = argv[optind];
97 settings.to = argv[optind+1];
98 ret = uwcp_copy(&settings);
107 static int check_configdir(void) {
108 char *home = getenv(UWCP_ENV_HOME);
110 cfgdir = util_concat_path(home, UWCP_CFG_DIR);
113 if(stat(cfgdir, &s)) {
114 if(errno == ENOENT) {
115 if(mkdir(cfgdir, S_IRWXU)) {
116 fprintf(stderr, "Cannot create %s: %s", cfgdir, strerror(errno));
120 fprintf(stderr, "Cannot access %s: %s", cfgdir, strerror(errno));
128 static int create_control_socket(void) {
129 char *copydir = util_concat_path(cfgdir, UWCP_COPY_DIR);
132 if(stat(copydir, &s)) {
133 if(errno == ENOENT) {
134 if(mkdir(copydir, S_IRWXU)) {
135 fprintf(stderr, "Cannot create %s: %s", copydir, strerror(errno));
139 fprintf(stderr, "Cannot access %s: %s", copydir, strerror(errno));
144 // create unix domain socket
145 char *random_str = util_random_str();
146 sstr_t socketp = ucx_sprintf("%s/%.*s", copydir, 8, random_str);
148 socket_path = socketp.ptr;
150 struct sockaddr_un addr;
151 if(socketp.length > sizeof(addr.sun_path)-1) {
153 "path '%s' too long for unix domain socket",
158 memset(&addr, 0, sizeof(addr));
159 addr.sun_family = AF_UNIX;
160 memcpy(addr.sun_path, socketp.ptr, socketp.length);
162 srvctrl = socket(AF_UNIX, SOCK_STREAM, 0);
165 "Cannot create server control socket: %s",
169 if(bind(srvctrl, (struct sockaddr*)&addr, sizeof(addr))) {
171 "srvctrl socket bind failed: %s",
181 int uwcp_copy(CPSettings *settings) {
184 if(check_configdir()) {
189 if(create_control_socket()) {
193 if(settings->printsocket) {
194 printf("%s\n", socket_path);
196 printf("copy %s to %s\n", settings->from, settings->to);
197 if(settings->pause) {
209 ret = uwcp_srvctrl(settings);
215 int uwcp_srvctrl(CPSettings *settings) {
217 perror("Cannot create event pipe");
224 struct pollfd *fds = calloc(allocfds, sizeof(struct pollfd));
225 CtrlClient **clients = calloc(allocfds, sizeof(void*));
227 int timeout = TIMEOUT_IDLE;
230 fds[0].events = POLLIN;
234 time_t tbegin = time(NULL);
236 while(poll(fds, numfds, 1000) >= 0) {
237 time_t tend = time(NULL);
238 time_t diff = tend - tbegin;
241 if((fds[0].revents & POLLIN) == POLLIN) {
243 int fd = accept(srvctrl, NULL, 0);
248 //int flags = fcntl(fd, F_GETFL, 0);
249 //flags = flags & ~O_NONBLOCK;
250 //fcntl(fd, F_SETFL, flags);
252 CtrlClient *client = malloc(sizeof(CtrlClient));
253 memset(client, 0, sizeof(CtrlClient));
256 printf("add client: %d\n", client->fd);
258 fds[numfds].fd = client->fd;
259 fds[numfds].events = POLLIN;
260 fds[numfds].revents = 0;
261 clients[numfds] = client;
267 for(int i=1;i<numfds;i++) {
268 if((fds[i].revents & POLLIN) == POLLIN) {
269 CtrlClient *client = clients[i];
270 ssize_t r = read(fds[i].fd, client->buf + client->pos, CLIENT_MSG_BUFSIZE - client->pos);
272 printf("remove client: %d\n", fds[i].fd);
278 int msgret = handle_messages(client);
282 } else if(msgret == -1) {
291 for(int i=1;i<numfds;i++) {
292 if(fds[i].events != 0) {
294 clients[j] = clients[j];
297 client_free(clients[i]);
304 if(diff >= CLIENT_UPDATE_INTERVALL) {
305 for(int i=1;i<numfds;i++) {
306 client_send_status(clients[i]);
312 timeout = numfds > 1 ? TIMEOUT_CLIENT : TIMEOUT_IDLE;
321 void client_free(CtrlClient *client) {
325 int handle_messages(CtrlClient *client) {
326 if(client->pos == CLIENT_MSG_BUFSIZE) {
331 for(int i=0;i<client->pos;i++) {
332 if(client->buf[i] == '\n') {
334 msg.ptr = &client->buf[msgstart];
335 msg.length = i - msgstart;
338 int msgret = handle_client_msg(client, msg);
339 if(msgret) return msgret;
343 if(msgstart < client->pos) {
344 // incomplete message
345 memmove(client->buf, client->buf + msgstart, client->pos - msgstart);
346 client->pos -= msgstart;
354 int handle_client_msg(CtrlClient *client, sstr_t msg) {
355 printf("msg: %.*s\n", (int)msg.length, msg.ptr);
357 if(!sstrcmp(msg, S("abort"))) {
364 void client_send_status(CtrlClient *client) {
366 write(client->fd, msg, strlen(msg));