7c95b1c5a59c526c2305d7496fae1e18715e58e6
[apps/livebox/data-provider-master.git] / src / util.c
1 /*
2  * Copyright 2013  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.1 (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
7  *
8  * http://floralicense.org/license/
9  *
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.
15  */
16
17 #define _GNU_SOURCE
18
19 #include <stdio.h>
20 #include <sys/time.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <sys/vfs.h>
26 #include <sys/types.h>
27 #include <dirent.h>
28 #include <ctype.h>
29 #include <sys/statvfs.h>
30 #include <sys/mount.h>
31
32 #include <sys/smack.h>
33 #include <dlog.h>
34 #include <Eina.h>
35 #include <Ecore.h>
36 #if defined(HAVE_LIVEBOX)
37 #include <livebox-errno.h>
38 #else
39 #include "lite-errno.h"
40 #endif
41
42 #include "util.h"
43 #include "debug.h"
44 #include "conf.h"
45
46 static struct info {
47         int emergency_mounted;
48 } s_info = {
49         .emergency_mounted = 0,
50 };
51
52 int errno;
53
54 HAPI unsigned long util_string_hash(const char *str)
55 {
56         unsigned long ret = 0;
57
58         while (*str) {
59                 ret += (unsigned long)(*str++);
60         }
61
62         ret %= 371773;
63         return ret;
64 }
65
66 HAPI double util_timestamp(void)
67 {
68 #if defined(_USE_ECORE_TIME_GET)
69         return ecore_time_get();
70 #else
71         struct timeval tv;
72         if (gettimeofday(&tv, NULL) < 0) {
73                 static unsigned long internal_count = 0;
74                 ErrPrint("failed to get time of day: %s\n", strerror(errno));
75                 tv.tv_sec = internal_count++;
76                 tv.tv_usec = 0;
77         }
78
79         return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0f;
80 #endif
81 }
82
83 HAPI int util_check_ext(const char *filename, const char *check_ptr)
84 {
85         int name_len;
86
87         name_len = strlen(filename);
88         while (--name_len >= 0 && *check_ptr) {
89                 if (filename[name_len] != *check_ptr) {
90                         return LB_STATUS_ERROR_INVALID;
91                 }
92
93                 check_ptr ++;
94         }
95
96         return LB_STATUS_SUCCESS;
97 }
98
99 static inline int check_native_livebox(const char *pkgname)
100 {
101         int len;
102         char *path;
103
104         len = strlen(pkgname) * 2;
105         len += strlen(ROOT_PATH);
106         len += strlen("%s/libexec/liblive-%s.so");
107
108         path = malloc(len + 1);
109         if (!path) {
110                 ErrPrint("Heap: %s\n", strerror(errno));
111                 return LB_STATUS_ERROR_MEMORY;
112         }
113
114         snprintf(path, len, "%s%s/libexec/liblive-%s.so", ROOT_PATH, pkgname, pkgname);
115         if (access(path, F_OK | R_OK) != 0) {
116                 ErrPrint("%s is not a valid package\n", pkgname);
117                 DbgFree(path);
118                 return LB_STATUS_ERROR_INVALID;
119         }
120
121         DbgFree(path);
122         return LB_STATUS_SUCCESS;
123 }
124
125 static inline int check_web_livebox(const char *pkgname)
126 {
127         int len;
128         char *path;
129
130         len = strlen(pkgname) * 2;
131         len += strlen("/opt/usr/apps/%s/res/wgt/livebox/index.html");
132
133         path = malloc(len + 1);
134         if (!path) {
135                 ErrPrint("Heap: %s\n", strerror(errno));
136                 return LB_STATUS_ERROR_MEMORY;
137         }
138
139         snprintf(path, len, "/opt/usr/apps/%s/res/wgt/livebox/index.html", pkgname);
140         if (access(path, F_OK | R_OK) != 0) {
141                 ErrPrint("%s is not a valid package\n", pkgname);
142                 DbgFree(path);
143                 return LB_STATUS_ERROR_INVALID;
144         }
145
146         DbgFree(path);
147         return LB_STATUS_SUCCESS;
148 }
149
150 HAPI int util_validate_livebox_package(const char *pkgname)
151 {
152         if (!pkgname) {
153                 ErrPrint("Invalid argument\n");
154                 return LB_STATUS_ERROR_INVALID;
155         }
156
157         if (!check_native_livebox(pkgname) || !check_web_livebox(pkgname)) {
158                 return LB_STATUS_SUCCESS;
159         }
160
161         return LB_STATUS_ERROR_INVALID;
162 }
163
164 HAPI int util_unlink(const char *filename)
165 {
166         char *descfile;
167         int desclen;
168         int ret;
169
170         if (!filename) {
171                 return LB_STATUS_ERROR_INVALID;
172         }
173
174         desclen = strlen(filename) + 6; /* .desc */
175         descfile = malloc(desclen);
176         if (!descfile) {
177                 ErrPrint("Heap: %s\n", strerror(errno));
178                 return LB_STATUS_ERROR_MEMORY;
179         }
180
181         ret = snprintf(descfile, desclen, "%s.desc", filename);
182         if (ret < 0) {
183                 ErrPrint("Error: %s\n", strerror(errno));
184                 DbgFree(descfile);
185                 return LB_STATUS_ERROR_FAULT;
186         }
187
188         (void)unlink(descfile);
189         DbgFree(descfile);
190         (void)unlink(filename);
191
192         return LB_STATUS_SUCCESS;
193 }
194
195 HAPI char *util_slavename(void)
196 {
197         char slavename[BUFSIZ];
198         static unsigned long idx = 0;
199
200         snprintf(slavename, sizeof(slavename), "%lu_%lf", idx++, util_timestamp());
201         return strdup(slavename);
202 }
203
204 HAPI const char *util_basename(const char *name)
205 {
206         int length;
207         length = name ? strlen(name) : 0;
208         if (!length) {
209                 return ".";
210         }
211
212         while (--length > 0 && name[length] != '/');
213
214         return length <= 0 ? name : (name + length + (name[length] == '/'));
215 }
216
217 /*!
218  * Return size of stroage in Bytes unit.
219  */
220 HAPI unsigned long long util_free_space(const char *path)
221 {
222         struct statvfs st;
223         unsigned long long space;
224
225         if (statvfs(path, &st) < 0) {
226                 ErrPrint("statvfs: %s\n", strerror(errno));
227                 return 0lu;
228         }
229
230         space = (unsigned long long)st.f_bsize * (unsigned long long)st.f_bavail;
231         DbgPrint("Available size: %llu, f_bsize: %lu, f_bavail: %lu\n", space, st.f_bsize, st.f_bavail);
232         /*!
233          * \note
234          * Must have to check the overflow
235          */
236
237         return space;
238 }
239
240 static inline char *extend_heap(char *buffer, int *sz, int incsz)
241 {
242         char *tmp;
243
244         *sz += incsz;
245         tmp = realloc(buffer, *sz);
246         if (!tmp) {
247                 ErrPrint("Heap: %s\n", strerror(errno));
248                 return NULL;
249         }
250
251         return tmp;
252 }
253
254 HAPI char *util_replace_string(const char *src, const char *pattern, const char *replace)
255 {
256         const char *ptr;
257         char *tmp;
258         char *ret = NULL;
259         int idx = 0;
260         int out_idx;
261         int out_sz;
262         enum {
263                 STATE_START,
264                 STATE_FIND,
265                 STATE_CHECK,
266                 STATE_END
267         } state;
268
269         if (!src || !pattern) {
270                 return NULL;
271         }
272
273         out_sz = strlen(src);
274         ret = strdup(src);
275         if (!ret) {
276                 ErrPrint("Heap: %s\n", strerror(errno));
277                 return NULL;
278         }
279
280         out_idx = 0;
281         for (state = STATE_START, ptr = src; state != STATE_END; ptr++) {
282                 switch (state) {
283                 case STATE_START:
284                         if (*ptr == '\0') {
285                                 state = STATE_END;
286                         } else if (!isblank(*ptr)) {
287                                 state = STATE_FIND;
288                                 ptr--;
289                         }
290                         break;
291                 case STATE_FIND:
292                         if (*ptr == '\0') {
293                                 state = STATE_END;
294                         } else if (*ptr == *pattern) {
295                                 state = STATE_CHECK;
296                                 ptr--;
297                                 idx = 0;
298                         } else {
299                                 ret[out_idx] = *ptr;
300                                 out_idx++;
301                                 if (out_idx == out_sz) {
302                                         tmp = extend_heap(ret, &out_sz, strlen(replace) + 1);
303                                         if (!tmp) {
304                                                 DbgFree(ret);
305                                                 return NULL;
306                                         }
307                                         ret = tmp;
308                                 }
309                         }
310                         break;
311                 case STATE_CHECK:
312                         if (!pattern[idx]) {
313                                 /*!
314                                  * If there is no space for copying the replacement,
315                                  * Extend size of the return buffer.
316                                  */
317                                 if (out_sz - out_idx < strlen(replace) + 1) {
318                                         tmp = extend_heap(ret, &out_sz, strlen(replace) + 1);
319                                         if (!tmp) {
320                                                 DbgFree(ret);
321                                                 return NULL;
322                                         }
323                                         ret = tmp;
324                                 }
325
326                                 strcpy(ret + out_idx, replace);
327                                 out_idx += strlen(replace);
328
329                                 state = STATE_FIND;
330                                 ptr--;
331                         } else if (*ptr != pattern[idx]) {
332                                 ptr -= idx;
333
334                                 /* Copy the first matched character */
335                                 ret[out_idx] = *ptr;
336                                 out_idx++;
337                                 if (out_idx == out_sz) {
338                                         tmp = extend_heap(ret, &out_sz, strlen(replace) + 1);
339                                         if (!tmp) {
340                                                 DbgFree(ret);
341                                                 return NULL;
342                                         }
343
344                                         ret = tmp;
345                                 }
346
347                                 state = STATE_FIND;
348                         } else {
349                                 idx++;
350                         }
351                         break;
352                 default:
353                         break;
354                 }
355         }
356
357         return ret;
358 }
359
360 HAPI const char *util_uri_to_path(const char *uri)
361 {
362         int len;
363
364         len = strlen(SCHEMA_FILE);
365         if (strncasecmp(uri, SCHEMA_FILE, len)) {
366                 return NULL;
367         }
368
369         return uri + len;
370 }
371
372 HAPI double util_time_delay_for_compensation(double period)
373 {
374         unsigned long long curtime;
375         unsigned long long _period;
376         unsigned long long remain;
377         struct timeval tv;
378         double ret;
379
380         if (period == 0.0f) {
381                 DbgPrint("Period is ZERO\n");
382                 return 0.0f;
383         }
384
385         if (gettimeofday(&tv, NULL) < 0){
386                 ErrPrint("gettimeofday: %s\n", strerror(errno));
387                 return period;
388         }
389
390         curtime = (unsigned long long)tv.tv_sec * 1000000llu + (unsigned long long)tv.tv_usec;
391
392         _period = (unsigned long long)(period * (double)1000000);
393         if (_period == 0llu) {
394                 ErrPrint("%lf <> %llu\n", period, _period);
395                 return period;
396         }
397
398         remain = curtime % _period;
399
400         ret = (double)remain / (double)1000000;
401         return period - ret;
402 }
403
404 HAPI void *util_timer_add(double interval, Eina_Bool (*cb)(void *data), void *data)
405 {
406         Ecore_Timer *timer;
407         double delay;
408
409         timer = ecore_timer_add(interval, cb, data);
410         if (!timer) {
411                 return NULL;
412         }
413
414         delay = util_time_delay_for_compensation(interval) - interval;
415         ecore_timer_delay(timer, delay);
416         DbgPrint("Compensate timer: %lf\n", delay);
417
418         return timer;
419 }
420
421 HAPI void util_timer_interval_set(void *timer, double interval)
422 {
423         double delay;
424         ecore_timer_interval_set(timer, interval);
425
426         delay = util_time_delay_for_compensation(interval) - interval;
427         ecore_timer_delay(timer, delay);
428 }
429
430 HAPI int util_unlink_files(const char *folder)
431 {
432         struct stat info;
433         DIR *handle;
434         struct dirent *entry;
435         char *abspath;
436         int len;
437
438         if (lstat(folder, &info) < 0) {
439                 ErrPrint("Error: %s\n", strerror(errno));
440                 return LB_STATUS_ERROR_IO;
441         }
442
443         if (!S_ISDIR(info.st_mode)) {
444                 ErrPrint("Error: %s is not a folder", folder);
445                 return LB_STATUS_ERROR_INVALID;
446         }
447
448         handle = opendir(folder);
449         if (!handle) {
450                 ErrPrint("Error: %s\n", strerror(errno));
451                 return LB_STATUS_ERROR_IO;
452         }
453
454         while ((entry = readdir(handle))) {
455                 if (!strcmp(entry->d_name, ".")) {
456                         continue;
457                 }
458
459                 if (!strcmp(entry->d_name, "..")) {
460                         continue;
461                 }
462
463                 len = strlen(folder) + strlen(entry->d_name) + 3;
464                 abspath = calloc(1, len);
465                 if (!abspath) {
466                         ErrPrint("Heap: %s\n", strerror(errno));
467                         continue;
468                 }
469                 snprintf(abspath, len - 1, "%s/%s", folder, entry->d_name);
470
471                 if (unlink(abspath) < 0) {
472                         DbgPrint("unlink: %s\n", strerror(errno));
473                 }
474
475                 DbgFree(abspath);
476         }
477
478         if (closedir(handle) < 0) {
479                 ErrPrint("closedir: %s\n", strerror(errno));
480         }
481         return LB_STATUS_SUCCESS;
482 }
483
484 HAPI void util_remove_emergency_disk(void)
485 {
486         int ret;
487         ret = umount(IMAGE_PATH);
488         if (ret < 0) {
489                 ErrPrint("umount: %s\n", strerror(errno));
490         }
491
492         DbgPrint("Try to unmount[%s] %d\n", IMAGE_PATH, ret);
493         s_info.emergency_mounted = 0;
494 }
495
496 HAPI void util_prepare_emergency_disk(void)
497 {
498         char *buf;
499         char *source = NULL;
500         char *type = NULL;
501         char *option = NULL;
502         char *ptr;
503         char *rollback_ptr;
504         int tag_idx;
505         int idx;
506         int len;
507         int ret;
508         static const char *tag[] = {
509                 "source",
510                 "type",
511                 "option",
512                 NULL,
513         };
514         enum tag_type {
515                 TAG_SOURCE,
516                 TAG_TYPE,
517                 TAG_OPTION,
518                 TAG_ERROR
519         };
520
521         buf = strdup(EMERGENCY_DISK);
522         if (!buf) {
523                 ErrPrint("Failed to prepare emergency disk info\n");
524                 return;
525         }
526
527         rollback_ptr = ptr = buf;
528         idx = 0;
529         tag_idx = 0;
530         len = strlen(ptr);
531
532         while (tag[tag_idx] != NULL && ptr != (buf + len)) {
533                 if (tag[tag_idx][idx] == '\0') {
534                         if (*ptr == '=' || isblank(*ptr)) {
535                                 switch (tag_idx) {
536                                 case TAG_SOURCE:
537                                         if (source) {
538                                                 ErrPrint("source[%s] is overrided\n", source);
539                                         }
540
541                                         while ((*ptr != '\0' && *ptr != ';') && (*ptr == '=' || isblank(*ptr))) {
542                                                 ptr++;
543                                         }
544
545                                         source = ptr;
546                                         while (*ptr != '\0' && *ptr != ';') {
547                                                 ptr++;
548                                         }
549
550                                         if (*source == '\0') {
551                                                 type = NULL;
552                                         }
553
554                                         *ptr = '\0';
555                                         rollback_ptr = ptr + 1;
556                                         idx = 0;
557                                         break;
558                                 case TAG_TYPE:
559                                         if (type) {
560                                                 ErrPrint("type[%s] is overrided\n", type);
561                                         }
562
563                                         while ((*ptr != '\0' && *ptr != ';') && (*ptr == '=' || isblank(*ptr))) {
564                                                 ptr++;
565                                         }
566
567                                         type = ptr;
568                                         while (*ptr != '\0' && *ptr != ';') {
569                                                 ptr++;
570                                         }
571
572                                         if (*type == '\0') {
573                                                 type = NULL;
574                                         }
575
576                                         *ptr = '\0';
577                                         rollback_ptr = ptr + 1;
578                                         idx = 0;
579                                         break;
580                                 case TAG_OPTION:
581                                         if (option) {
582                                                 ErrPrint("option[%s] is overrided\n", option);
583                                         }
584
585                                         while ((*ptr != '\0' && *ptr != ';') && (*ptr == '=' || isblank(*ptr))) {
586                                                 ptr++;
587                                         }
588
589                                         option = ptr;
590                                         while (*ptr != '\0' && *ptr != ';') {
591                                                 ptr++;
592                                         }
593
594                                         if (*option == '\0') {
595                                                 option = NULL;
596                                         }
597
598                                         *ptr = '\0';
599                                         rollback_ptr = ptr + 1;
600                                         idx = 0;
601                                         break;
602                                 default:
603                                         break;
604                                 }
605                         } else {
606                                 ptr = rollback_ptr;
607                                 tag_idx++;
608                                 idx = 0;
609                         }
610                 } else if (tag[tag_idx][idx] != *ptr) {
611                         ptr = rollback_ptr;
612                         tag_idx++;
613                         idx = 0;
614                 } else {
615                         ptr++;
616                         idx++;
617                 } // tag
618         }
619
620         DbgPrint("source[%s] type[%s] option[%s]\n", source, type, option);
621
622         ret = mount(source, IMAGE_PATH, type, MS_NOSUID | MS_NOEXEC, option);
623         DbgFree(buf);
624         if (ret < 0) {
625                 ErrPrint("Failed to mount: %s\n", strerror(errno));
626                 return;
627         }
628
629         MINIMUM_SPACE = 0;
630
631         ErrPrint("Disk space is not enough, use the tmpfs. Currently required minimum space is %lu bytes\n", MINIMUM_SPACE);
632         if (chmod(IMAGE_PATH, 0750) < 0) {
633                 ErrPrint("chmod: %s\n", strerror(errno));
634         }
635
636         if (chown(IMAGE_PATH, 5000, 5000) < 0) {
637                 ErrPrint("chown: %s\n", strerror(errno));
638         }
639
640         ret = smack_setlabel(IMAGE_PATH, DATA_SHARE_LABEL, SMACK_LABEL_ACCESS);
641         if (ret != 0) {
642                 ErrPrint("Failed to set SMACK for %s (%d)\n", IMAGE_PATH, ret);
643         } else {
644                 ret = smack_setlabel(IMAGE_PATH, "1", SMACK_LABEL_TRANSMUTE);
645                 DbgPrint("[%s] is successfully created (t: %d)\n", IMAGE_PATH, ret);
646         }
647
648         if (mkdir(ALWAYS_PATH, 0755) < 0) {
649                 ErrPrint("mkdir: (%s) %s\n", ALWAYS_PATH, strerror(errno));
650         } else {
651                 if (chmod(ALWAYS_PATH, 0750) < 0) {
652                         ErrPrint("chmod: %s\n", strerror(errno));
653                 }
654
655                 if (chown(ALWAYS_PATH, 5000, 5000) < 0) {
656                         ErrPrint("chown: %s\n", strerror(errno));
657                 }
658
659                 ret = smack_setlabel(ALWAYS_PATH, DATA_SHARE_LABEL, SMACK_LABEL_ACCESS);
660                 if (ret != 0) {
661                         ErrPrint("Failed to set SMACK for %s (%d)\n", ALWAYS_PATH, ret);
662                 } else {
663                         ret = smack_setlabel(ALWAYS_PATH, "1", SMACK_LABEL_TRANSMUTE);
664                         DbgPrint("[%s] is successfully created (t: %d)\n", ALWAYS_PATH, ret);
665                 }
666         }
667
668         if (mkdir(READER_PATH, 0755) < 0) {
669                 ErrPrint("mkdir: (%s) %s\n", READER_PATH, strerror(errno));
670         } else {
671                 if (chmod(READER_PATH, 0750) < 0) {
672                         ErrPrint("chmod: %s\n", strerror(errno));
673                 }
674
675                 if (chown(READER_PATH, 5000, 5000) < 0) {
676                         ErrPrint("chown: %s\n", strerror(errno));
677                 }
678
679                 ret = smack_setlabel(READER_PATH, DATA_SHARE_LABEL, SMACK_LABEL_ACCESS);
680                 if (ret != 0) {
681                         ErrPrint("Failed to set SMACK for %s (%d)\n", READER_PATH, ret);
682                 } else {
683                         ret = smack_setlabel(READER_PATH, "1", SMACK_LABEL_TRANSMUTE);
684                         DbgPrint("[%s] is successfully created (t: %d)\n", READER_PATH, ret);
685                 }
686         }
687
688         s_info.emergency_mounted = 1;
689 }
690
691 HAPI int util_emergency_disk_is_mounted(void)
692 {
693         return s_info.emergency_mounted;
694 }
695
696 HAPI void util_setup_log_disk(void)
697 {
698         int ret;
699
700         if (access(SLAVE_LOG_PATH, R_OK | W_OK | X_OK) == 0) {
701                 DbgPrint("[%s] is already accessible\n", SLAVE_LOG_PATH);
702                 return;
703         }
704
705         DbgPrint("Initiate the critical log folder [%s]\n", SLAVE_LOG_PATH);
706         if (mkdir(SLAVE_LOG_PATH, 0755) < 0) {
707                 ErrPrint("mkdir: %s\n", strerror(errno));
708         } else {
709                 if (chmod(SLAVE_LOG_PATH, 0750) < 0) {
710                         ErrPrint("chmod: %s\n", strerror(errno));
711                 }
712
713                 if (chown(SLAVE_LOG_PATH, 5000, 5000) < 0) {
714                         ErrPrint("chown: %s\n", strerror(errno));
715                 }
716
717                 ret = smack_setlabel(SLAVE_LOG_PATH, DATA_SHARE_LABEL, SMACK_LABEL_ACCESS);
718                 if (ret != 0) {
719                         ErrPrint("Failed to set SMACK for %s (%d)\n", SLAVE_LOG_PATH, ret);
720                 } else {
721                         ret = smack_setlabel(SLAVE_LOG_PATH, "1", SMACK_LABEL_TRANSMUTE);
722                         DbgPrint("[%s] is successfully created (t: %d)\n", SLAVE_LOG_PATH, ret);
723                 }
724         }
725 }
726
727 HAPI int util_service_is_enabled(const char *tag)
728 {
729         return !!strcasestr(SERVICES, tag);
730 }
731
732 /* End of a file */