2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
22 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <sys/select.h>
30 #include <sys/smack.h>
31 #include <tzplatform_config.h>
33 //#define TRACE_TAG TRACE_SYNC
34 #define LOG_TAG "SDBD_TRACE_SYNC"
38 #include "file_sync_service.h"
40 #include "sdbd_plugin.h"
44 #define SYNC_TIMEOUT 15
46 /* The typical default value for the umask is S_IWGRP | S_IWOTH (octal 022).
47 * Before use the DIR_PERMISSION, the process umask value should be set 0 using umask().
49 #define DIR_PERMISSION 0777
52 static void set_syncfile_smack_label(char *src) {
53 char *label_transmuted = NULL;
55 char *src_chr = strrchr(src, '/');
56 int pos = src_chr - src + 1;
60 D("need root permission to set smack label: %d\n", getuid());
64 snprintf(dirname, pos, "%s", src);
66 //D("src:[%s], dirname:[%s]\n", src, dirname);
67 int rc = smack_getlabel(dirname, &label_transmuted, SMACK_LABEL_TRANSMUTE);
69 if (rc == 0 && label_transmuted != NULL) {
70 if (!strcmp("TRUE", label_transmuted)) {
71 rc = smack_getlabel(dirname, &label, SMACK_LABEL_ACCESS);
72 if (rc == 0 && label != NULL) {
73 if (smack_setlabel(src, label, SMACK_LABEL_ACCESS) == -1) {
74 D("unable to set sync file smack label %s due to (errno:%d)\n", label, errno);
77 /* Todo: The following code is from tizen 2.4
78 rc = security_server_label_access(src, label);
79 if (rc != SECURITY_SERVER_API_SUCCESS) {
80 D("unable to set sync file smack label %s due to %d\n", label, errno);
86 D("fail to set label, is it transmuted?:%s\n", label_transmuted);
88 free(label_transmuted);
90 if (smack_setlabel(src, SMACK_SYNC_FILE_LABEL, SMACK_LABEL_ACCESS) == -1) {
91 D("unable to set sync file smack label %s due to (errno:%d)\n", SMACK_SYNC_FILE_LABEL, errno);
94 /* Todo: The following code is from tizen 2.4
95 rc = security_server_label_access(src, SMACK_SYNC_FILE_LABEL);
96 if (rc != SECURITY_SERVER_API_SUCCESS) {
97 D("unable to set sync file smack label %s due to %d\n", SMACK_SYNC_FILE_LABEL, errno);
104 static int sync_send_label_notify(int s, const char *path, int success)
106 char buffer[512] = {0,};
107 snprintf(buffer, sizeof(buffer), "%d:%s", success, path);
109 int len = sdb_write(s, buffer, sizeof(buffer));
114 static void sync_read_label_notify(int s)
116 char buffer[512 + 1] = {0,};
119 int len = sdb_read(s, buffer, sizeof(buffer) - 1);
121 D("sync notify read errno:%d\n", errno);
125 if (buffer[0] == '0') {
126 D("sync notify child process exit\n");
133 //set_syncfile_smack_label(path);
137 static int mkdirs(int noti_fd, char *name)
153 ret = sdb_mkdir(name, DIR_PERMISSION);
155 sync_send_label_notify(noti_fd, name, 1);
157 if((ret < 0) && (errno != EEXIST)) {
158 E("mkdir(\"%s\") -> errno:%d\n", name, errno);
167 static int do_stat(int s, const char *path, const char* cmd)
172 msg.stat.id = ID_STAT;
173 if (cmd && !strncmp(cmd, "pull", 4)) {
174 if (!request_validity_to_plugin(PLUGIN_SYNC_CMD_VERIFY_PULL, path)) {
175 D("cannot pull files from this path.\n");
179 return writex(s, &msg.stat, sizeof(msg.stat));
184 if(stat(path, &st)) {
188 D("failed to stat %s due to: errno:%d\n", path, errno);
190 msg.stat.mode = htoll(st.st_mode);
191 msg.stat.size = htoll(st.st_size);
192 msg.stat.time = htoll(st.st_mtime);
195 return writex(s, &msg.stat, sizeof(msg.stat));
198 static int do_list(int s, const char *path)
206 char tmp[1024 + 256 + 1];
209 char dirent_buffer[ sizeof(struct dirent) + 260 + 1 ] = {0,};
210 struct dirent *dirent_r = (struct dirent*)dirent_buffer;
213 memcpy(tmp, path, len);
215 fname = tmp + len + 1;
217 msg.dent.id = ID_DENT;
221 E("failed to open dir due to: errno:%d\n", errno);
225 while((readdir_r(d, dirent_r, &de) == 0) && de) {
226 int len = strlen(de->d_name);
228 /* not supposed to be possible, but
229 if it does happen, let's not buffer overrun */
234 s_strncpy(fname, de->d_name, len + 1);
235 if(lstat(tmp, &st) == 0) {
236 msg.dent.mode = htoll(st.st_mode);
237 msg.dent.size = htoll(st.st_size);
238 msg.dent.time = htoll(st.st_mtime);
239 msg.dent.namelen = htoll(len);
241 if(writex(s, &msg.dent, sizeof(msg.dent)) ||
242 writex(s, de->d_name, len)) {
252 msg.dent.id = ID_DONE;
256 msg.dent.namelen = 0;
257 return writex(s, &msg.dent, sizeof(msg.dent));
260 static int fail_message(int s, const char *reason)
263 size_t len = strlen(reason);
265 E("sync: failure: %s\n", reason);
267 msg.data.id = ID_FAIL;
268 msg.data.size = htoll(len);
270 if(writex(s, &msg.data, sizeof(msg.data)) ||
271 writex(s, reason, len)) {
278 static int fail_errno(int fd, int err_no)
281 char buf[512] = {0, };
283 ret_str = strerror_r(err_no, buf, sizeof(buf));
285 return fail_message(fd, (const char*)ret_str);
288 // FIXME: should get the following paths with api later but, do it for simple and not having dependency on other packages
289 #define VAR_ABS_PATH "/opt/var"
290 #define CMD_MEDIADB_UPDATE tzplatform_mkpath(TZ_SYS_BIN, "mediadb-update")
291 #define MEDIA_CONTENTS_PATH1 tzplatform_getenv(TZ_SYS_STORAGE)
292 #define MEDIA_CONTENTS_PATH2 tzplatform_getenv(TZ_USER_CONTENT)
293 #define MEDIA_CONTENTS_PATH3 tzplatform_mkpath(TZ_SYS_STORAGE, "sdcard")
295 static void sync_mediadb(char *path) {
296 if (access(CMD_MEDIADB_UPDATE, F_OK) != 0) {
297 E("%s: command not found\n", CMD_MEDIADB_UPDATE);
301 if (strstr(path, VAR_ABS_PATH) == path) {
305 if (strstr(path, MEDIA_CONTENTS_PATH1) != NULL) {
306 const char * const arg_list[] = {CMD_MEDIADB_UPDATE, "-r", MEDIA_CONTENTS_PATH1, NULL};
307 spawn(CMD_MEDIADB_UPDATE, (char * const*)arg_list);
308 D("media db update done to %s\n", MEDIA_CONTENTS_PATH1);
309 } else if (strstr(path, MEDIA_CONTENTS_PATH2) != NULL) {
310 const char * const arg_list[] = {CMD_MEDIADB_UPDATE, "-r", MEDIA_CONTENTS_PATH2, NULL};
311 spawn(CMD_MEDIADB_UPDATE, (char * const*)arg_list);
312 D("media db update done to %s\n", MEDIA_CONTENTS_PATH2);
313 } else if (strstr(path, MEDIA_CONTENTS_PATH3) != NULL) {
314 const char * const arg_list[] = {CMD_MEDIADB_UPDATE, "-r", MEDIA_CONTENTS_PATH3, NULL};
315 spawn(CMD_MEDIADB_UPDATE, (char * const*)arg_list);
316 D("media db update done to %s\n", MEDIA_CONTENTS_PATH3);
321 static int handle_send_file(int s, int noti_fd, char *path, mode_t mode, char *buffer)
324 unsigned int timestamp = 0;
327 fd = sdb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
328 if(fd < 0 && errno == ENOENT) {
329 mkdirs(noti_fd, path);
330 fd = sdb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
332 if(fd < 0 && errno == EEXIST) {
333 fd = sdb_open_mode(path, O_WRONLY, mode);
336 if(fail_errno(s, errno))
343 if(readx(s, &msg.data, sizeof(msg.data))) {
346 if(msg.data.id != ID_DATA) {
347 if(msg.data.id == ID_DONE) {
348 timestamp = ltohl(msg.data.size);
351 fail_message(s, "invalid data message");
354 len = ltohl(msg.data.size);
355 if(len > SYNC_DATA_MAX) {
356 fail_message(s, "oversize data message");
359 if(readx(s, buffer, len)) {
360 E("read failed due to unknown reason\n");
367 if(writex(fd, buffer, len)) {
368 int saved_errno = errno;
372 if(fail_errno(s, saved_errno)) return -1;
379 u.actime = timestamp;
380 u.modtime = timestamp;
383 msg.status.id = ID_OKAY;
384 msg.status.msglen = 0;
385 if(writex(s, &msg.status, sizeof(msg.status)))
387 // flush file system buffers due to N_SE-22305
390 E("sync error: %d!!!\n", fd);
393 sync_send_label_notify(noti_fd, path, 1);
405 static int handle_send_link(int s, int noti_fd, char *path, char *buffer)
411 if(readx(s, &msg.data, sizeof(msg.data)))
414 if(msg.data.id != ID_DATA) {
415 fail_message(s, "invalid data message: expected ID_DATA");
419 len = ltohl(msg.data.size);
420 if(len > SYNC_DATA_MAX) {
421 fail_message(s, "oversize data message");
424 if(readx(s, buffer, len))
427 ret = symlink(buffer, path);
428 if(ret && errno == ENOENT) {
429 mkdirs(noti_fd, path);
430 ret = symlink(buffer, path);
433 fail_errno(s, errno);
437 if(readx(s, &msg.data, sizeof(msg.data)))
440 if(msg.data.id == ID_DONE) {
441 msg.status.id = ID_OKAY;
442 msg.status.msglen = 0;
443 if(writex(s, &msg.status, sizeof(msg.status)))
446 fail_message(s, "invalid data message: expected ID_DONE");
452 #endif /* HAVE_SYMLINKS */
454 static int is_support_push()
456 return (!strncmp(g_capabilities.filesync_support, PLUGIN_RET_PUSHPULL, strlen(PLUGIN_RET_PUSHPULL))
457 || !strncmp(g_capabilities.filesync_support, PLUGIN_RET_PUSH, strlen(PLUGIN_RET_PUSH)));
460 static int is_support_pull()
462 return (!strncmp(g_capabilities.filesync_support, PLUGIN_RET_PUSHPULL, strlen(PLUGIN_RET_PUSHPULL))
463 || !strncmp(g_capabilities.filesync_support, PLUGIN_RET_PULL, strlen(PLUGIN_RET_PULL)));
466 static int do_send(int s, int noti_fd, char *path, char *buffer)
475 // Check the capability for file push support.
476 if(!is_support_push()) {
477 fail_message(s, "NO support file push.");
481 if (!request_validity_to_plugin(PLUGIN_SYNC_CMD_VERIFY_PUSH, path)) {
482 fail_message(s, "You cannot push files to this path.");
486 tmp = strrchr(path,',');
490 mode = strtoul(tmp + 1, NULL, 0);
492 is_link = S_ISLNK(mode);
494 // extracts file permission from stat.mode. (ex 100644 & 0777 = 644);
495 mode &= 0777; // combination of (S_IRWXU | S_IRWXG | S_IRWXO)
496 mode |= S_IWOTH; // SDK requirement from N_SE-43337
499 mode = 0644; // set default permission value in most of unix system.
504 if (is_pkg_file_path(path)) {
511 // sdb does not allow to check that file exists or not. After deleting old file and creating new file again unconditionally.
517 ret = handle_send_link(s, noti_fd, path, buffer);
522 /* copy user permission bits to "group" and "other" permissions.
523 * ex) 0644 file will be created copied 0666 file.
524 * the following 2 lines should be commented if sdb process has been set to umask 0.
527 //mode |= ((mode >> 3) & 0070);
528 //mode |= ((mode >> 3) & 0007);
529 ret = handle_send_file(s, noti_fd, path, mode, buffer);
535 static int do_recv(int s, const char *path, char *buffer)
540 // Check the capability for file push support.
541 if (!is_support_pull()) {
542 fail_message(s, "NO support file pull.");
546 if (!request_validity_to_plugin(PLUGIN_SYNC_CMD_VERIFY_PULL, path)) {
547 fail_message(s, "You cannot pull files from this path.");
551 fd = sdb_open(path, O_RDONLY);
553 if(fail_errno(s, errno)) return -1;
557 msg.data.id = ID_DATA;
559 r = sdb_read(fd, buffer, SYNC_DATA_MAX);
562 if(errno == EINTR) continue;
563 r = fail_errno(s, errno);
567 msg.data.size = htoll(r);
568 if(writex(s, &msg.data, sizeof(msg.data)) ||
569 writex(s, buffer, r)) {
577 msg.data.id = ID_DONE;
579 if(writex(s, &msg.data, sizeof(msg.data))) {
586 void file_sync_service(int fd, void *cookie)
592 struct timeval timeout;
595 char* cmd = (char*)cookie;
596 D("file_sync_service cmd: %s\n", cmd);
598 if(sdb_socketpair(s)) {
599 E("cannot create service socket pair\n");
606 sdb_close(s[0]); //close the parent fd
607 sync_read_label_notify(s[1]);
609 } else if (pid > 0) {
612 char *buffer = malloc(SYNC_DATA_MAX);
617 if (should_drop_privileges()) {
618 if (set_sdk_user_privileges(DROP_CAPABILITIES_AFTER_FORK) < 0) {
622 set_root_privileges();
626 D("sync: waiting for command for %d sec\n", SYNC_TIMEOUT);
628 FD_ZERO(&set); /* clear the set */
629 FD_SET(fd, &set); /* add our file descriptor to the set */
631 timeout.tv_sec = SYNC_TIMEOUT;
634 rv = select(fd + 1, &set, NULL, NULL, &timeout);
636 E("sync file descriptor select failed\n");
637 } else if (rv == 0) {
638 D("sync file descriptor timeout: (took %d sec over)\n", SYNC_TIMEOUT);
639 fail_message(fd, "sync timeout");
643 if(readx(fd, &msg.req, sizeof(msg.req))) {
644 fail_message(fd, "command read failure");
647 namelen = ltohl(msg.req.namelen);
649 fail_message(fd, "invalid namelen");
652 if(readx(fd, name, namelen)) {
653 fail_message(fd, "filename read failure");
660 D("sync: '%s' '%s'\n", (char*) &msg.req, name);
664 if(do_stat(fd, name, cmd)) goto fail;
667 if(do_list(fd, name)) goto fail;
670 if(do_send(fd, s[0], name, buffer)) goto fail;
673 if(do_recv(fd, name, buffer)) goto fail;
678 fail_message(fd, "unknown command");
692 sync_send_label_notify(s[0], name, 0);