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