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