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
35 #include "file_sync_service.h"
38 #define SYNC_TIMEOUT 15
40 #define APP_INSTALL_PATH_PREFIX1 tzplatform_getenv(TZ_SYS_RW_APP)
41 #define APP_INSTALL_PATH_PREFIX2 tzplatform_getenv(TZ_USER_APP)
43 struct sync_permit_rule
47 int mode; // 0:push, 1: pull, 2: push&push
50 struct sync_permit_rule sdk_sync_permit_rule[] = {
51 // /* 0 */ {"rds", "^((/opt/apps)|(/opt/usr/apps))/[a-zA-Z0-9]{10}/info/\\.sdk_delta\\.info$", 1},
52 /* 1 */ {"unitest", "^((/tmp)|(/opt/apps)|(/opt/usr/apps))/[a-zA-Z0-9]{10}/data/[a-zA-Z0-9_\\-]{1,50}\\.xml$", 1},
53 /* 2 */ {"codecoverage", "^((/tmp)|(/opt/apps)|(/opt/usr/apps))/[a-zA-Z0-9]{10}/data/+(.)*\\.gcda$", 1},
54 /* 3 */ {"da", "^(/tmp/da/)*+[a-zA-Z0-9_\\-\\.]{1,50}\\.png$", 1},
55 /* end */ {NULL, NULL, 0}
58 /* The typical default value for the umask is S_IWGRP | S_IWOTH (octal 022).
59 * Before use the DIR_PERMISSION, the process umask value should be set 0 using umask().
61 #define DIR_PERMISSION 0777
63 void init_sdk_sync_permit_rule_regx(void)
65 asprintf(&sdk_sync_permit_rule[0].regx, "^((/tmp)|(%s)|(%s))/[a-zA-Z0-9]{10}/data/[a-zA-Z0-9_\\-]{1,50}\\.xml$", APP_INSTALL_PATH_PREFIX1, APP_INSTALL_PATH_PREFIX2);
66 asprintf(&sdk_sync_permit_rule[1].regx, "^((/tmp)|(%s)|(%s))/[a-zA-Z0-9]{10}/data/+(.)*\\.gcda$", APP_INSTALL_PATH_PREFIX1, APP_INSTALL_PATH_PREFIX2);
67 asprintf(&sdk_sync_permit_rule[2].regx, "da", "^(/tmp/da/)*+[a-zA-Z0-9_\\-\\.]{1,50}\\.png$");
71 static void set_syncfile_smack_label(char *src) {
72 char *label_transmuted = NULL;
74 char *src_chr = strrchr(src, '/');
75 int pos = src_chr - src + 1;
79 D("need root permission to set smack label: %d\n", getuid());
83 snprintf(dirname, pos, "%s", src);
85 //D("src:[%s], dirname:[%s]\n", src, dirname);
86 int rc = smack_getlabel(dirname, &label_transmuted, SMACK_LABEL_TRANSMUTE);
88 if (rc == 0 && label_transmuted != NULL) {
89 if (!strcmp("TRUE", label_transmuted)) {
90 rc = smack_getlabel(dirname, &label, SMACK_LABEL_ACCESS);
91 if (rc == 0 && label != NULL) {
92 if (smack_setlabel(src, label, SMACK_LABEL_ACCESS) == -1) {
93 D("unable to set sync file smack label %s due to %s\n", label, strerror(errno));
98 D("fail to set label, is it transmuted?:%s\n", label_transmuted);
100 free(label_transmuted);
102 if (smack_setlabel(src, SMACK_SYNC_FILE_LABEL, SMACK_LABEL_ACCESS) == -1) {
103 D("unable to set sync file smack label %s due to %s\n", SMACK_SYNC_FILE_LABEL, strerror(errno));
108 static int sync_send_label_notify(int s, const char *path, int success)
110 char buffer[512] = {0,};
111 snprintf(buffer, sizeof(buffer), "%d:%s", success, path);
113 int len = sdb_write(s, buffer, sizeof(buffer));
118 static void sync_read_label_notify(int s)
120 char buffer[512] = {0,};
123 int len = sdb_read(s, buffer, sizeof(buffer));
125 D("sync notify read error:%s\n", strerror(errno));
129 if (buffer[0] == '0') {
130 D("sync notify child process exit\n");
136 set_syncfile_smack_label(path);
140 static int mkdirs(int noti_fd, char *name)
156 ret = sdb_mkdir(name, DIR_PERMISSION);
158 sync_send_label_notify(noti_fd, name, 1);
160 if((ret < 0) && (errno != EEXIST)) {
161 D("mkdir(\"%s\") -> %s\n", name, strerror(errno));
170 static int do_stat(int s, const char *path)
175 msg.stat.id = ID_STAT;
178 if(stat(path, &st)) {
182 D("failed to stat %s due to: %s\n", path, strerror(errno));
184 msg.stat.mode = htoll(st.st_mode);
185 msg.stat.size = htoll(st.st_size);
186 msg.stat.time = htoll(st.st_mtime);
189 return writex(s, &msg.stat, sizeof(msg.stat));
192 static int do_list(int s, const char *path)
200 char tmp[1024 + 256 + 1];
204 memcpy(tmp, path, len);
206 fname = tmp + len + 1;
208 msg.dent.id = ID_DENT;
212 D("failed to open dir due to: %s\n", strerror(errno));
216 while((de = readdir(d))) {
217 int len = strlen(de->d_name);
219 /* not supposed to be possible, but
220 if it does happen, let's not buffer overrun */
225 strcpy(fname, de->d_name);
226 if(lstat(tmp, &st) == 0) {
227 msg.dent.mode = htoll(st.st_mode);
228 msg.dent.size = htoll(st.st_size);
229 msg.dent.time = htoll(st.st_mtime);
230 msg.dent.namelen = htoll(len);
232 if(writex(s, &msg.dent, sizeof(msg.dent)) ||
233 writex(s, de->d_name, len)) {
243 msg.dent.id = ID_DONE;
247 msg.dent.namelen = 0;
248 return writex(s, &msg.dent, sizeof(msg.dent));
251 static int fail_message(int s, const char *reason)
254 int len = strlen(reason);
256 D("sync: failure: %s\n", reason);
258 msg.data.id = ID_FAIL;
259 msg.data.size = htoll(len);
260 if(writex(s, &msg.data, sizeof(msg.data)) ||
261 writex(s, reason, len)) {
268 static int fail_errno(int s)
270 return fail_message(s, strerror(errno));
273 static int handle_send_file(int s, int noti_fd, char *path, mode_t mode, char *buffer)
276 unsigned int timestamp = 0;
279 fd = sdb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
280 if(fd < 0 && errno == ENOENT) {
281 mkdirs(noti_fd, path);
282 fd = sdb_open_mode(path, O_WRONLY | O_CREAT | O_EXCL, mode);
284 if(fd < 0 && errno == EEXIST) {
285 fd = sdb_open_mode(path, O_WRONLY, mode);
295 if(readx(s, &msg.data, sizeof(msg.data))) {
298 if(msg.data.id != ID_DATA) {
299 if(msg.data.id == ID_DONE) {
300 timestamp = ltohl(msg.data.size);
303 fail_message(s, "invalid data message");
306 len = ltohl(msg.data.size);
307 if(len > SYNC_DATA_MAX) {
308 fail_message(s, "oversize data message");
311 if(readx(s, buffer, len)) {
312 D("read failed due to unknown reason\n");
319 if(writex(fd, buffer, len)) {
320 int saved_errno = errno;
325 if(fail_errno(s)) return -1;
332 u.actime = timestamp;
333 u.modtime = timestamp;
336 msg.status.id = ID_OKAY;
337 msg.status.msglen = 0;
338 if(writex(s, &msg.status, sizeof(msg.status)))
340 // flush file system buffers due to N_SE-22305
343 D("sync error: %d!!!\n", fd);
346 sync_send_label_notify(noti_fd, path, 1);
357 static int handle_send_link(int s, int noti_fd, char *path, char *buffer)
363 if(readx(s, &msg.data, sizeof(msg.data)))
366 if(msg.data.id != ID_DATA) {
367 fail_message(s, "invalid data message: expected ID_DATA");
371 len = ltohl(msg.data.size);
372 if(len > SYNC_DATA_MAX) {
373 fail_message(s, "oversize data message");
376 if(readx(s, buffer, len))
379 ret = symlink(buffer, path);
380 if(ret && errno == ENOENT) {
381 mkdirs(noti_fd, path);
382 ret = symlink(buffer, path);
389 if(readx(s, &msg.data, sizeof(msg.data)))
392 if(msg.data.id == ID_DONE) {
393 msg.status.id = ID_OKAY;
394 msg.status.msglen = 0;
395 if(writex(s, &msg.status, sizeof(msg.status)))
398 fail_message(s, "invalid data message: expected ID_DONE");
404 #endif /* HAVE_SYMLINKS */
406 static int do_send(int s, int noti_fd, char *path, char *buffer)
412 tmp = strrchr(path,',');
416 mode = strtoul(tmp + 1, NULL, 0);
417 #ifndef HAVE_SYMLINKS
420 is_link = S_ISLNK(mode);
422 // extracts file permission from stat.mode. (ex 100644 & 0777 = 644);
423 mode &= 0777; // combination of (S_IRWXU | S_IRWXG | S_IRWXO)
424 mode |= S_IWOTH; // SDK requirement from N_SE-43337
427 mode = 0644; // set default permission value in most of unix system.
431 // sdb does not allow to check that file exists or not. After deleting old file and creating new file again unconditionally.
437 ret = handle_send_link(s, noti_fd, path, buffer);
442 /* copy user permission bits to "group" and "other" permissions.
443 * ex) 0644 file will be created copied 0666 file.
444 * the following 2 lines should be commented if sdb process has been set to umask 0.
447 //mode |= ((mode >> 3) & 0070);
448 //mode |= ((mode >> 3) & 0007);
449 ret = handle_send_file(s, noti_fd, path, mode, buffer);
455 static int do_recv(int s, const char *path, char *buffer)
460 fd = sdb_open(path, O_RDONLY);
462 if(fail_errno(s)) return -1;
466 msg.data.id = ID_DATA;
468 r = sdb_read(fd, buffer, SYNC_DATA_MAX);
471 if(errno == EINTR) continue;
476 msg.data.size = htoll(r);
477 if(writex(s, &msg.data, sizeof(msg.data)) ||
478 writex(s, buffer, r)) {
486 msg.data.id = ID_DONE;
488 if(writex(s, &msg.data, sizeof(msg.data))) {
494 static int verify_sync_rule(const char* path) {
500 init_sdk_sync_permit_rule_regx();
501 for (i=0; sdk_sync_permit_rule[i].regx != NULL; i++) {
502 ret = regcomp(®ex, sdk_sync_permit_rule[i].regx, REG_EXTENDED);
506 // execute regular expression
507 ret = regexec(®ex, path, 0, NULL, 0);
510 D("found matched rule(%s) from %s path\n", sdk_sync_permit_rule[i].name, path);
512 } else if( ret == REG_NOMATCH ){
515 regerror(ret, ®ex, buf, sizeof(buf));
516 D("regex match failed(%s): %s\n",sdk_sync_permit_rule[i].name, buf);
520 for (i = 0; i <= 3; i++){
521 free(sdk_sync_permit_rule[i].regx);
526 void file_sync_service(int fd, void *cookie)
532 struct timeval timeout;
536 if(sdb_socketpair(s)) {
537 D("cannot create service socket pair\n");
540 char *buffer = malloc(SYNC_DATA_MAX);
545 FD_ZERO(&set); /* clear the set */
546 FD_SET(fd, &set); /* add our file descriptor to the set */
548 timeout.tv_sec = SYNC_TIMEOUT;
554 sdb_close(s[0]); //close the parent fd
555 sync_read_label_notify(s[1]);
556 } else if (pid > 0) {
559 D("sync: waiting for command for %d sec\n", SYNC_TIMEOUT);
561 rv = select(fd + 1, &set, NULL, NULL, &timeout);
563 D("sync file descriptor select failed\n");
564 } else if (rv == 0) {
565 D("sync file descriptor timeout: (took %d sec over)\n", SYNC_TIMEOUT);
566 fail_message(fd, "sync timeout");
570 if(readx(fd, &msg.req, sizeof(msg.req))) {
571 fail_message(fd, "command read failure");
574 namelen = ltohl(msg.req.namelen);
576 fail_message(fd, "invalid namelen");
579 if(readx(fd, name, namelen)) {
580 fail_message(fd, "filename read failure");
586 D("sync: '%s' '%s'\n", (char*) &msg.req, name);
588 if (should_drop_privileges() && !verify_sync_rule(name)) {
589 set_developer_privileges();
594 if(do_stat(fd, name)) goto fail;
597 if(do_list(fd, name)) goto fail;
600 if(do_send(fd, s[0], name, buffer)) goto fail;
603 if(do_recv(fd, name, buffer)) goto fail;
608 fail_message(fd, "unknown command");
620 sync_send_label_notify(s[0], name, 0);