Replace hard coded path /var/run by the tizen-platform-config macro
[platform/core/appfw/vconf.git] / vconftool.c
1 /*
2  * libslp-setting
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Hakjoo Ko <hakjoo.ko@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <glib.h>
26 #include <vconf.h>
27 #include <glib-object.h>
28 #include "vconf-log.h"
29
30 #include <unistd.h>
31 #include <sys/stat.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include <tzplatform_config.h>
37 #include <wordexp.h>
38
39 enum {
40         VCONFTOOL_TYPE_NO = 0x00,
41         VCONFTOOL_TYPE_STRING,
42         VCONFTOOL_TYPE_INT,
43         VCONFTOOL_TYPE_DOUBLE,
44         VCONFTOOL_TYPE_BOOL
45 };
46
47 #define BUFSIZE         1024
48 #define DB_PREFIX tzplatform_getenv(TZ_SYS_CONFIG)
49 #define FILE_PREFIX tzplatform_getenv(TZ_SYS_CONFIG)
50 #define MEMORY_INIT tzplatform_mkpath(TZ_SYS_CONFIG,"memory_init")
51
52 const char *BACKEND_DB_PREFIX = "db/";
53 const char *BACKEND_FILE_PREFIX = "file/";
54 const char *BACKEND_MEMORY_PREFIX = "memory/";
55
56 static char *guid = NULL;
57 static char *uid = NULL;
58 static char *vconf_type = NULL;
59 static int is_recursive = FALSE;
60 static int is_initialization = FALSE;
61 static int is_forced = FALSE;
62 static int get_num = 0;
63
64 static GOptionEntry entries[] = {
65         {"type", 't', 0, G_OPTION_ARG_STRING, &vconf_type, "type of value",
66          "int|bool|double|string"},
67         {"recursive", 'r', 0, G_OPTION_ARG_NONE, &is_recursive,
68          "retrieve keys recursively", NULL},
69         {"guid", 'g', 0, G_OPTION_ARG_STRING, &guid, "group permission", NULL},
70         {"uid", 'u', 0, G_OPTION_ARG_STRING, &uid, "user permission", NULL},
71         {"initialization", 'i', 0, G_OPTION_ARG_NONE, &is_initialization,
72          "memory backend initialization", NULL},
73         {"force", 'f', 0, G_OPTION_ARG_NONE, &is_forced,
74          "overwrite vconf values by force", NULL},
75         {NULL}
76 };
77
78 static void get_operation(char *input);
79 static void recursive_get(char *subDIR, int level);
80 static void print_keylist(keylist_t *keylist, keynode_t *temp_node, int level);
81
82 static void print_help(const char *cmd)
83 {
84         fprintf(stderr, "Usage:\n");
85         fprintf(stderr, "\n");
86         fprintf(stderr, "[Set vconf value]\n");
87         fprintf(stderr,
88                 "       %s set -t <TYPE> <KEY NAME> <VALUE> <OPTIONS>\n", cmd);
89         fprintf(stderr, "                 <TYPE>=int|bool|double|string\n");
90         fprintf(stderr, "\n");
91         fprintf(stderr,
92                 "       Ex) %s set -t string db/testapp/key1 \"This is test\" \n",
93                 cmd);
94         fprintf(stderr, "\n");
95         fprintf(stderr, "       <OPTIONS>\n");
96         fprintf(stderr,
97                 "          -g <GUID> : Set Effective group id. The key's permission will be set to 0664.\n");
98         fprintf(stderr,
99                 "           Ex) %s set -t string db/testapp/key1 \"This is test\" -g 425\n",
100                 cmd);
101         fprintf(stderr,
102                 "           NOTE: -g and -u cannot be userd together. -u ignores -g option.\n");
103         fprintf(stderr, "\n");
104         fprintf(stderr,
105                 "          -u <UID> : Set Effective user id. The key's permission will be set to 0644.\n");
106         fprintf(stderr,
107                 "           Ex) %s set -t string db/testapp/key1 \"This is test\" -u 5000\n",
108                 cmd);
109         fprintf(stderr,
110                 "           NOTE: -g and -u cannot be userd together. -u ignores -g option.\n");
111         fprintf(stderr, "\n");
112         fprintf(stderr,
113                 "          -i : Install memory backend key into flash space for backup.\n");
114         fprintf(stderr,
115                 "           Ex) %s set -t string memory/testapp/key1 \"This is test\" -i\n",
116                 cmd);
117         fprintf(stderr, "\n");
118         fprintf(stderr,
119                 "          -f : Overwrite values by force, even when vconf values are already exist.\n");
120         fprintf(stderr, "\n");
121         fprintf(stderr, "[Get vconf value]\n");
122         fprintf(stderr, "       %s get <OPTIONS> <KEY NAME>\n", cmd);
123         fprintf(stderr, "\n");
124         fprintf(stderr, "       <OPTIONS>\n");
125         fprintf(stderr,
126                 "          -r : retrieve all keys included in sub-directorys \n");
127         fprintf(stderr, "       Ex) %s get db/testapp/key1\n", cmd);
128         fprintf(stderr, "           %s get db/testapp/\n", cmd);
129         fprintf(stderr, "\n");
130         fprintf(stderr, "[Unset vconf value]\n");
131         fprintf(stderr, "       %s unset <KEY NAME>\n", cmd);
132         fprintf(stderr, "\n");
133         fprintf(stderr, "       Ex) %s unset db/testapp/key1\n", cmd);
134         fprintf(stderr, "\n");
135 }
136
137 static int check_type(void)
138 {
139         if (vconf_type) {
140                 if (!strncasecmp(vconf_type, "int", 3))
141                         return VCONFTOOL_TYPE_INT;
142                 else if (!strncasecmp(vconf_type, "string", 6))
143                         return VCONFTOOL_TYPE_STRING;
144                 else if (!strncasecmp(vconf_type, "double", 6))
145                         return VCONFTOOL_TYPE_DOUBLE;
146                 else if (!strncasecmp(vconf_type, "bool", 4))
147                         return VCONFTOOL_TYPE_BOOL;
148         }
149         return VCONFTOOL_TYPE_NO;
150 }
151
152 static int __system(char * cmd)
153 {
154         int status;
155         pid_t cpid;
156
157         if((cpid = fork()) < 0) {
158                 perror("fork");
159                 return -1;
160         }
161
162         if (cpid == 0) {
163                 /* child */
164                 wordexp_t p;
165                 char **w;
166
167                 wordexp(cmd, &p, 0);
168                 w = p.we_wordv;
169
170                 execv(w[0], (char *const *)w);
171
172                 wordfree(&p);
173
174                 _exit(-1);
175         } else {
176                 /* parent */
177                 if (waitpid(cpid, &status, 0) == -1) {
178                         perror("waitpid failed");
179                         return -1;
180                 }
181                 if (WIFSIGNALED(status)) {
182                         printf("signal(%d)\n", WTERMSIG(status));
183                         perror("exit by signal");
184                         return -1;
185                 }
186                 if (!WIFEXITED(status)) {
187                         perror("exit abnormally");
188                         return -1;
189                 }
190                 if (WIFEXITED(status) && WEXITSTATUS(status)) {
191                         perror("child return error");
192                         return -1;
193                 }
194         }
195
196         return 0;
197 }
198
199 static void disable_invalid_char(char* src)
200 {
201         char* tmp;
202
203         for(tmp = src; *tmp; ++tmp)
204         {
205                 if( (*tmp == ';') || (*tmp == '|') )
206                 {
207                         fprintf(stderr,"invalid char is found\n");
208                         *tmp = '_';
209                 }
210         }
211 }
212
213 static int check_file_path_mode(char* file_path)
214 {
215         char szCmd[BUFSIZE] = {0,};
216         int create_file = 0;
217         int set_id = 0;
218         int fd;
219
220         if (guid || uid) {
221                 if (getuid() != 0) {
222                         fprintf(stderr,
223                                 "Error!\t Only root user can use '-g or -u' option\n");
224                         return -1;
225                 }
226
227                 set_id = 1;
228         }
229
230         /* Check file path */
231         if (access(file_path, F_OK) != 0) {
232                 /* fprintf(stderr,"key does not exist\n"); */
233
234                 char szPath[BUFSIZE] = { 0, };
235                 char *pCh = strrchr(file_path, '/');
236                 strncat(szPath, file_path, pCh - file_path);
237                 /* fprintf(stderr, "szPath : %s\n", szPath); */
238
239                 /* Check directory & create it */
240                 if (access(szPath, F_OK) != 0) {
241                         /* fprintf(stderr,"parent dir does not exist\n"); */
242
243                         snprintf(szCmd, BUFSIZE, "/bin/mkdir %s -p --mode=775", szPath);
244                         disable_invalid_char(szCmd);
245                         if (__system(szCmd)) {
246                                 fprintf(stderr,"[%s:%d]Fail mkdir() szCmd=%s\n", __FILE__, __LINE__, szCmd);
247                                 return -1;
248                         }
249
250                         snprintf(szCmd, BUFSIZE, "/bin/chgrp %s %s",tzplatform_getenv(TZ_SYS_USER_GROUP), szPath);
251                         if (__system(szCmd)) {
252                                 fprintf(stderr,"[%s:%d]Fail chgrp() szCmd=%s\n", __FILE__, __LINE__, szCmd);
253                                 return -1;
254                         }
255
256                 }
257
258                 create_file = 1;
259         } else if (!is_forced) {
260                 fprintf(stderr, "Key already exist. Use -f option to force update\n");
261                 return -1;
262         }
263
264         if(create_file) {
265                 /* Create file */
266                 mode_t temp;
267                 temp = umask(0000);
268                 fd = open(file_path, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
269                 umask(temp);
270                 if(fd == -1) {
271                         fprintf(stderr, "open(rdwr,create) error\n");
272                         return -1;
273                 }
274                 close(fd);
275         }
276
277         if(set_id) {
278                 if((fd = open(file_path, O_RDONLY)) == -1) {
279                         fprintf(stderr, "open(rdonly) error\n");
280                         return -1;
281                 }
282
283                 if(uid) {
284                         if (fchown(fd, atoi(uid), atoi(uid)) == -1) {
285                                 fprintf(stderr, "Error!\t Fail to fchown(%d)\n", errno);
286                                 close(fd);
287                                 return -1;
288                         }
289                 } else if (guid) {
290                         if (-1 == fchown(fd, 0, atoi(guid))) {
291                                 fprintf(stderr, "Error!\t Fail to fchown()\n");
292                                 close(fd);
293                                 return -1;
294                         }
295                 }
296
297                 close(fd);
298         }
299
300         return 0;
301 }
302
303 /*
304  * there are three different types of vconf key back-end
305  * 1. filesytem
306  * 2. sqlitefs based on sqlite3
307  * 3. tmpfs based on memory
308  * considering to that tmpfs is volatile so there should be a way
309  * to initialize key into permanent storage. That is the below function
310  * which copy memory back-end key to filesystem back-end, copy other back-end
311  * key to filesystem back-end just makes no sense.
312  */
313 static int copy_memory_key(char *pszKey, char *pszOrigin)
314 {
315         char szCmd[BUFSIZE] = { 0, };
316         char szPath[BUFSIZE] = { 0, };
317         char szFileName[BUFSIZE] = { 0, };
318         char *pCh = strrchr(pszKey, '/');
319         int nLen = strlen(pszKey);
320
321         /* only copy memory/ prefix key */
322         if (strncmp("memory/", pszKey, 7))
323                 return 0;
324
325         /* Get directory path and file name */
326         snprintf(szPath, BUFSIZE, "%s/", MEMORY_INIT);
327         strncat(szPath, pszKey, pCh - pszKey);
328         strncpy(szFileName, pszKey + (pCh - pszKey) + 1, nLen - (pCh - pszKey));
329
330         /* Check directory & create it */
331         if (0 != access(szPath, F_OK)) {
332                 snprintf(szCmd, BUFSIZE, "mkdir %s -p --mode=755", szPath);
333                 if (system(szCmd)) {
334                         printf("[%s:%d]Fail mkdir() szCmd=%s\n", __FILE__,
335                                __LINE__, szCmd);
336                         return -1;
337                 }
338         }
339         /* copy */
340         strncat(szPath, "/", 1);
341         strncat(szPath, szFileName, strlen(szFileName));
342         memset(szCmd, 0x00, BUFSIZE);
343         snprintf(szCmd, BUFSIZE, "cp %s %s -r -p", pszOrigin, szPath);
344         if (system(szCmd)) {
345                 printf("[%s:%d]Fail copy\n", __FILE__, __LINE__);
346                 return -1;
347         }
348         return 0;
349 }
350
351 static int make_file_path(char *pszKey, char *pszBuf)
352 {
353         if (0 ==
354             strncmp(pszKey, BACKEND_DB_PREFIX, strlen(BACKEND_DB_PREFIX))) {
355                 snprintf(pszBuf, BUFSIZE, "%s/%s", DB_PREFIX, pszKey);
356                 return 0;
357         } else if (0 ==
358                    strncmp(pszKey, BACKEND_FILE_PREFIX,
359                            strlen(BACKEND_FILE_PREFIX))) {
360                 snprintf(pszBuf, BUFSIZE, "%s/%s", FILE_PREFIX, pszKey);
361                 return 0;
362         } else if (0 ==
363                    strncmp(pszKey, BACKEND_MEMORY_PREFIX,
364                            strlen(BACKEND_MEMORY_PREFIX))) {
365                 snprintf(pszBuf, BUFSIZE, "%s/%s", tzplatform_getenv(TZ_SYS_RUN), pszKey);
366                 return 0;
367         }
368         return -1;
369 }
370
371 int main(int argc, char **argv)
372 {
373         int set_type;
374         char szFilePath[BUFSIZE] = { 0, };
375         char *psz_key = NULL;
376
377         GError *error = NULL;
378         GOptionContext *context;
379
380         g_type_init();
381         context = g_option_context_new("- vconf library tool");
382         g_option_context_add_main_entries(context, entries, NULL);
383         g_option_context_set_help_enabled(context, FALSE);
384         g_option_context_set_ignore_unknown_options(context, TRUE);
385
386         if (!g_option_context_parse(context, &argc, &argv, &error)) {
387                 g_print("option parsing failed: %s\n", error->message);
388                 exit(1);
389         }
390
391         if (argc < 2) {
392                 print_help(argv[0]);
393                 return 1;
394         }
395
396         if (!strncmp(argv[1], "set", 3)) {
397                 set_type = check_type();
398                 if (argc < 4 || !set_type) {
399                         print_help(argv[0]);
400                         return 1;
401                 }
402
403                 if (make_file_path(argv[2], szFilePath)) {
404                         fprintf(stderr, "Error!\t Bad prefix\n");
405                         return -1;
406                 }
407
408                 if (check_file_path_mode(szFilePath)) {
409                         fprintf(stderr, "Error!\t create key %s\n", argv[2]);
410                         return -1;
411                 }
412
413                 switch (set_type) {
414                         case VCONFTOOL_TYPE_STRING:
415                                 vconf_set_str(argv[2], argv[3]);
416                                 break;
417                         case VCONFTOOL_TYPE_INT:
418                                 vconf_set_int(argv[2], atoi(argv[3]));
419                                 break;
420                         case VCONFTOOL_TYPE_DOUBLE:
421                                 vconf_set_dbl(argv[2], atof(argv[3]));
422                                 break;
423                         case VCONFTOOL_TYPE_BOOL:
424                                 vconf_set_bool(argv[2], !!atoi(argv[3]));
425                                 break;
426                         default:
427                                 fprintf(stderr, "never reach");
428                                 exit(1);
429                 }
430
431                 psz_key = argv[2];
432                 /* Install memory backend key into flash space *******/
433                 if (is_initialization) {
434                         copy_memory_key(psz_key, szFilePath);
435                 }
436                 /* End memory backend key into flash space ***********/
437
438         } else if (!strncmp(argv[1], "get", 3)) {
439                 if (argv[2])
440                         get_operation(argv[2]);
441                 else
442                         print_help(argv[0]);
443         } else if (!strncmp(argv[1], "unset", 5)) {
444                 if (argv[2])
445                         vconf_unset(argv[2]);
446                 else
447                         print_help(argv[0]);
448         } else
449                 fprintf(stderr, "%s is a invalid command\n", argv[1]);
450         return 0;
451 }
452
453 static void get_operation(char *input)
454 {
455         keylist_t *get_keylist;
456         keynode_t *temp_node;
457         char *test;
458
459         get_keylist = vconf_keylist_new();
460         /* ParentDIR parameter of gconf_client_all_entries
461         can not include the last slash. */
462         if ('/' == input[strlen(input) - 1] && strlen(input) > 8)
463                 input[strlen(input) - 1] = '\0';
464
465         vconf_get(get_keylist, input, VCONF_GET_ALL);
466         if (!(temp_node = vconf_keylist_nextnode(get_keylist))) {
467                 test = strrchr(input, '/');
468                 if (NULL != test) {
469                         vconf_keylist_add_null(get_keylist, input);
470                         if (test - input < 7)
471                                 *(test + 1) = '\0';
472                         else
473                                 *test = '\0';
474                         vconf_get(get_keylist, input, VCONF_GET_KEY);
475                         temp_node = vconf_keylist_nextnode(get_keylist);
476                 } else {
477                         fprintf(stderr, "Include at least one slash\"/\"\n");
478                         vconf_keylist_free(get_keylist);
479                         return;
480                 }
481         }
482         get_num = 0;
483         print_keylist(get_keylist, temp_node, 0);
484
485         if (!get_num)
486                 printf("No data\n");
487         vconf_keylist_free(get_keylist);
488 }
489
490 static void recursive_get(char *subDIR, int level)
491 {
492         keylist_t *get_keylist;
493         keynode_t *first_node;
494
495         get_keylist = vconf_keylist_new();
496         vconf_get(get_keylist, subDIR, VCONF_GET_ALL);
497
498         if ((first_node = vconf_keylist_nextnode(get_keylist))) {
499                 print_keylist(get_keylist, first_node, level);
500         }
501         vconf_keylist_free(get_keylist);
502 }
503
504 static void print_keylist(keylist_t *keylist, keynode_t *temp_node, int level)
505 {
506         do {
507                 switch (vconf_keynode_get_type(temp_node))
508                 {
509                         case VCONF_TYPE_INT:
510                                 printf("%s, value = %d (int)\n",
511                                        vconf_keynode_get_name(temp_node),
512                                        vconf_keynode_get_int(temp_node));
513                                 get_num++;
514                                 break;
515                         case VCONF_TYPE_BOOL:
516                                 printf("%s, value = %d (bool)\n",
517                                        vconf_keynode_get_name(temp_node),
518                                        vconf_keynode_get_bool(temp_node));
519                                 get_num++;
520                                 break;
521                         case VCONF_TYPE_DOUBLE:
522                                 printf("%s, value = %f (double)\n",
523                                        vconf_keynode_get_name(temp_node),
524                                        vconf_keynode_get_dbl(temp_node));
525                                 get_num++;
526                                 break;
527                         case VCONF_TYPE_STRING:
528                                 printf("%s, value = %s (string)\n",
529                                        vconf_keynode_get_name(temp_node),
530                                        vconf_keynode_get_str(temp_node));
531                                 get_num++;
532                                 break;
533                         case VCONF_TYPE_DIR:
534                                 printf("%s(Directory)\n",
535                                         vconf_keynode_get_name(temp_node));
536                                 if (is_recursive)
537                                         recursive_get(vconf_keynode_get_name(temp_node),
538                                                       level + 1);
539                                 break;
540                         default:
541                                 /* fprintf(stderr, "Unknown Type(%d)\n", vconf_keynode_get_type(temp_node)); */
542                                 break;
543                 }
544         } while ((temp_node = vconf_keylist_nextnode(keylist)));
545 }