a51019ecb61c436fcc2e83125f0acb1ba3fb8e0c
[platform/core/appfw/pkgmgr-info.git] / src / pkgmgrinfo_db.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <ctype.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <fcntl.h>
9 #include <grp.h>
10 #include <dirent.h>
11 #include <libgen.h>
12
13 #include <sqlite3.h>
14
15 #include <tzplatform_config.h>
16 #include <db-util.h>
17
18 #include "pkgmgr-info.h"
19 #include "pkgmgrinfo_debug.h"
20 #include "pkgmgrinfo_private.h"
21 #include "pkgmgr_parser.h"
22 #include "pkgmgr_parser_db.h"
23
24 __thread db_handle manifest_db;
25 __thread db_handle cert_db;
26
27 typedef int (*sqlite_query_callback)(void *data, int ncols, char **coltxt, char **colname);
28
29 static int _mkdir_for_user(const char* dir, uid_t uid, gid_t gid)
30 {
31         int ret;
32         char *fullpath;
33         char *subpath;
34         char buf[1024];
35         int fd;
36         struct stat sb;
37
38         fullpath = strdup(dir);
39         if (fullpath == NULL)
40                 return -1;
41         subpath = dirname(fullpath);
42         if (strlen(subpath) > 1 && strcmp(subpath, fullpath) != 0) {
43                 ret = _mkdir_for_user(fullpath, uid, gid);
44                 if (ret == -1) {
45                         free(fullpath);
46                         return ret;
47                 }
48         }
49
50         ret = mkdir(dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IXOTH);
51         if (ret && errno != EEXIST) {
52                 free(fullpath);
53                 return ret;
54         } else if (ret && errno == EEXIST) {
55                 free(fullpath);
56                 return 0;
57         }
58
59         if (getuid() == ROOT_UID) {
60                 fd = open(dir, O_RDONLY);
61                 if (fd == -1) {
62                         _LOGE("FAIL : open %s : %s", dir,
63                                         strerror_r(errno, buf, sizeof(buf)));
64                         return -1;
65                 }
66                 ret = fstat(fd, &sb);
67                 if (ret == -1) {
68                         _LOGE("FAIL : fstat %s : %s", dir,
69                                         strerror_r(errno, buf, sizeof(buf)));
70                         close(fd);
71                         return -1;
72                 }
73                 if (S_ISLNK(sb.st_mode)) {
74                         _LOGE("FAIL : %s is symlink!", dir);
75                         close(fd);
76                         return -1;
77                 }
78                 ret = fchown(fd, uid, gid);
79                 if (ret == -1) {
80                         _LOGE("FAIL : fchown %s %d.%d, because %s", dir, uid,
81                                         gid, strerror_r(errno, buf, sizeof(buf)));
82                         close(fd);
83                         return -1;
84                 }
85                 close(fd);
86         }
87
88         free(fullpath);
89
90         return 0;
91 }
92
93 static char *_get_db_path(uid_t uid)
94 {
95         const char *db_path;
96         char path[PATH_MAX];
97
98         db_path = tzplatform_getenv(TZ_SYS_DB);
99         if (db_path == NULL) {
100                 _LOGE("Failed to get TZ_SYS_DB path");
101                 return NULL;
102         }
103
104         if (uid == GLOBAL_USER || uid == ROOT_UID)
105                 return strdup(db_path);
106
107         snprintf(path, sizeof(path), "%s/user/%d", db_path, uid);
108
109         return strdup(path);
110 }
111
112 static int __attach_and_create_view(sqlite3 *handle, const char *db, const char *tables[], uid_t uid)
113 {
114         int i;
115         char *err = NULL;
116         char query[MAX_QUERY_LEN];
117
118         if (uid != GLOBAL_USER && uid != ROOT_UID) {
119                 snprintf(query, sizeof(query), "ATTACH DATABASE '%s' AS Global", db);
120                 if (SQLITE_OK != sqlite3_exec(handle, query, NULL, NULL, &err)) {
121                         _LOGD("Don't execute query = %s error message = %s\n", query, err);
122                         sqlite3_free(err);
123                         return SQLITE_ERROR;
124                 }
125         }
126
127         for (i = 0; tables[i]; i++) {
128                 if (uid != GLOBAL_USER && uid != ROOT_UID)
129                         snprintf(query, sizeof(query), "CREATE TEMP VIEW '%s' AS SELECT * \
130                                         FROM (SELECT *,0 AS for_all_users FROM main.'%s' UNION \
131                                         SELECT *,1 AS for_all_users FROM Global.'%s')",
132                                         tables[i], tables[i], tables[i]);
133                 else
134                         snprintf(query, sizeof(query), "CREATE TEMP VIEW '%s' AS SELECT * \
135                                         FROM (SELECT *,1 AS for_all_users FROM main.'%s')",
136                                         tables[i], tables[i]);
137                 if (SQLITE_OK != sqlite3_exec(handle, query, NULL, NULL, &err)) {
138                         _LOGD("Don't execute query = %s error message = %s\n", query, err);
139                         sqlite3_free(err);
140                 }
141         }
142
143         return SQLITE_OK;
144 }
145
146 int _check_create_cert_db(void)
147 {
148         return pkgmgr_parser_initialize_cert_db();
149 }
150
151 static gid_t _get_gid(const char *name)
152 {
153         char buf[BUFSIZE];
154         struct group entry;
155         struct group *ge;
156         int ret;
157
158         ret = getgrnam_r(name, &entry, buf, sizeof(buf), &ge);
159         if (ret || ge == NULL) {
160                 _LOGE("fail to get gid of %s", name);
161                 return -1;
162         }
163
164         return entry.gr_gid;
165 }
166
167 API const char *getIconPath(uid_t uid, bool readonly)
168 {
169         const char *path = NULL;
170         uid_t uid_caller = getuid();
171         gid_t gid = ROOT_UID;
172
173         if (uid != GLOBAL_USER && uid != ROOT_UID) {
174                 _LOGD("not supported target user");
175                 return NULL;
176         }
177
178         if (readonly)
179                 path = tzplatform_mkpath(TZ_SYS_RO_ICONS, "/");
180
181         /* just allow certain users to create the icon directory if needed. */
182         if (path && (uid_caller == ROOT_UID  ||
183                 uid_caller == APPFW_UID || uid_caller == uid))
184                 _mkdir_for_user(path, uid, gid);
185
186         return path;
187 }
188
189 API char *getUserPkgParserDBPath(void)
190 {
191         return getUserPkgParserDBPathUID(_getuid());
192 }
193
194 API char *getUserPkgParserDBPathUID(uid_t uid)
195 {
196         char pkgmgr_parser_db[PATH_MAX];
197         uid_t uid_caller = getuid();
198         gid_t gid = ROOT_UID;
199         char *db_path;
200
201         db_path = _get_db_path(uid);
202         if (db_path == NULL) {
203                 _LOGE("Failed to get db path %d", uid);
204                 return NULL;
205         }
206         snprintf(pkgmgr_parser_db, sizeof(pkgmgr_parser_db),
207                         "%s/.pkgmgr_parser.db", db_path);
208         if (access(db_path, F_OK) != 0) {
209                 if (uid != GLOBAL_USER && uid != ROOT_UID) {
210                         tzplatform_set_user(uid);
211                         gid = _get_gid(tzplatform_getenv(TZ_SYS_USER_GROUP));
212                         tzplatform_reset_user();
213                 }
214                 /* just allow certain users to create the dbspace directory if needed. */
215                 if (uid_caller == ROOT_UID || uid_caller == APPFW_UID ||
216                                 uid_caller == uid)
217                         _mkdir_for_user(db_path, uid, gid);
218         }
219         free(db_path);
220
221         return strdup(pkgmgr_parser_db);
222 }
223
224 API char *getUserPkgCertDBPath(void)
225 {
226          return getUserPkgCertDBPathUID(_getuid());
227 }
228
229 API char *getUserPkgCertDBPathUID(uid_t uid)
230 {
231         char pkgmgr_cert_db[PATH_MAX];
232         uid_t uid_caller = getuid();
233         gid_t gid = ROOT_UID;
234         char *db_path;
235
236         db_path = _get_db_path(uid);
237         if (db_path == NULL) {
238                 _LOGE("Failed to get db path %d", uid);
239                 return NULL;
240         }
241         snprintf(pkgmgr_cert_db, sizeof(pkgmgr_cert_db),
242                         "%s/.pkgmgr_cert.db", db_path);
243
244         if (uid != GLOBAL_USER && uid != ROOT_UID) {
245                 tzplatform_set_user(uid);
246                 gid = _get_gid(tzplatform_getenv(TZ_SYS_USER_GROUP));
247                 tzplatform_reset_user();
248         }
249
250         /* just allow certain users to create the dbspace directory if needed. */
251         if (uid_caller == ROOT_UID || uid_caller == APPFW_UID || uid_caller == uid)
252                 _mkdir_for_user(db_path, uid, gid);
253
254         free(db_path);
255
256         return strdup(pkgmgr_cert_db);
257 }
258
259 API const char *getUserManifestPath(uid_t uid, bool readonly)
260 {
261         const char *path = NULL;
262         uid_t uid_caller = getuid();
263         gid_t gid = ROOT_UID;
264
265         if (uid != GLOBAL_USER && uid != ROOT_UID) {
266                 tzplatform_set_user(uid);
267                 path = tzplatform_mkpath(TZ_USER_PACKAGES, "/");
268                 gid = _get_gid(tzplatform_getenv(TZ_SYS_USER_GROUP));
269                 tzplatform_reset_user();
270         } else {
271                 if (readonly)
272                         path = tzplatform_mkpath(TZ_SYS_RO_PACKAGES, "/");
273                 else
274                         path = tzplatform_mkpath(TZ_SYS_RW_PACKAGES, "/");
275         }
276
277         /* just allow certain users to create the icon directory if needed. */
278         if (uid_caller == ROOT_UID || uid_caller == APPFW_UID || uid_caller == uid)
279                 _mkdir_for_user(path, uid, gid);
280
281         return path;
282 }
283
284 int __close_manifest_db(void)
285 {
286         if (manifest_db.ref) {
287                 if (--manifest_db.ref == 0)
288                         sqlite3_close(GET_DB(manifest_db));
289                 return 0;
290         }
291         return -1;
292 }
293
294 static const char *parserdb_tables[] = {
295         "package_app_app_category",
296         "package_app_info",
297         "package_app_app_control",
298         "package_app_localized_info",
299         "package_app_app_metadata",
300         "package_app_share_allowed",
301         "package_app_app_permission",
302         "package_app_share_request",
303         "package_info",
304         "package_app_data_control",
305         "package_localized_info",
306         "package_app_icon_section_info",
307         "package_privilege_info",
308         "package_app_image_info",
309         "package_app_data_control_privilege",
310         NULL
311 };
312
313 int __open_manifest_db(uid_t uid, bool readonly)
314 {
315         int ret;
316         char *user_pkg_parser;
317         int flags;
318
319         if (manifest_db.ref) {
320                 manifest_db.ref++;
321                 return 0;
322         }
323
324         user_pkg_parser = getUserPkgParserDBPathUID(uid);
325         if (user_pkg_parser == NULL) {
326                 _LOGE("Failed to get pkg parser db path - %d", uid);
327                 return -1;
328         }
329
330         if (access(user_pkg_parser, F_OK) != 0) {
331                 _LOGE("Manifest DB does not exists !!");
332                 free(user_pkg_parser);
333                 return -1;
334         }
335
336         flags = readonly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE;
337         ret = db_util_open_with_options(user_pkg_parser, &GET_DB(manifest_db),
338                         flags, NULL);
339         if (ret != SQLITE_OK) {
340                 _LOGE("connect db [%s] failed!\n", user_pkg_parser);
341                 free(user_pkg_parser);
342                 return -1;
343         }
344
345         manifest_db.ref++;
346         if (readonly) {
347                 ret = __attach_and_create_view(GET_DB(manifest_db), MANIFEST_DB,
348                                 parserdb_tables, uid);
349                 if (ret != SQLITE_OK) {
350                         _LOGE("attach db [%s] failed!\n", user_pkg_parser);
351                         free(user_pkg_parser);
352                         return -1;
353                 }
354         }
355
356         free(user_pkg_parser);
357
358         return 0;
359 }
360
361 int __close_cert_db(void)
362 {
363         if (cert_db.ref) {
364                 if (--cert_db.ref == 0)
365                         sqlite3_close_v2(GET_DB(cert_db));
366                 return 0;
367         }
368         _LOGE("Certificate DB is already closed !!\n");
369         return -1;
370 }
371
372 static const char *certdb_tables[] = {
373         "package_cert_index_info",
374         "package_cert_info",
375         NULL
376 };
377
378 int __open_cert_db(uid_t uid, bool readonly)
379 {
380         int ret;
381         char *user_cert_parser;
382         int flags;
383
384         if (cert_db.ref) {
385                 cert_db.ref++;
386                 return 0;
387         }
388
389         user_cert_parser = getUserPkgCertDBPathUID(uid);
390         if (user_cert_parser == NULL) {
391                 _LOGE("Failed to get pkg cert db path - %d", uid);
392                 return -1;
393         }
394
395         if (access(user_cert_parser, F_OK) != 0) {
396                 _LOGE("Cert DB does not exists !!");
397                 free(user_cert_parser);
398                 return -1;
399         }
400
401         flags = readonly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE;
402         ret = db_util_open_with_options(user_cert_parser, &GET_DB(cert_db),
403                         flags, NULL);
404         if (ret != SQLITE_OK) {
405                 _LOGE("connect db [%s] failed!", user_cert_parser);
406                 free(user_cert_parser);
407                 return -1;
408         }
409         cert_db.ref++;
410         if (readonly) {
411                 ret = __attach_and_create_view(GET_DB(cert_db), CERT_DB,
412                                 certdb_tables, uid);
413                 if (ret != SQLITE_OK) {
414                         _LOGE("attach db [%s] failed!", user_cert_parser);
415                         free(user_cert_parser);
416                         return -1;
417                 }
418         }
419
420         free(user_cert_parser);
421
422         return 0;
423 }
424
425 void _save_column_int(sqlite3_stmt *stmt, int idx, int *i)
426 {
427         *i = sqlite3_column_int(stmt, idx);
428 }
429
430 inline void _save_column_str(sqlite3_stmt *stmt, int idx, char **str)
431 {
432         const char *val;
433
434         val = (const char *)sqlite3_column_text(stmt, idx);
435         if (val)
436                 *str = strdup(val);
437 }
438
439 API int pkgmgrinfo_pkginfo_set_usr_installed_storage(const char *pkgid, INSTALL_LOCATION location, const char *external_pkg_path, uid_t uid)
440 {
441         retvm_if(pkgid == NULL, PMINFO_R_EINVAL, "pkgid is NULL\n");
442         int ret = -1;
443         sqlite3 *pkgmgr_parser_db = NULL;
444         char *query = NULL;
445         char *db_path;
446
447         db_path = getUserPkgParserDBPathUID(uid);
448         if (db_path == NULL) {
449                 _LOGE("Failed to get pkg parser db path - %d", uid);
450                 return PMINFO_R_ERROR;
451         }
452
453         ret = db_util_open_with_options(db_path, &pkgmgr_parser_db,
454                         SQLITE_OPEN_READWRITE, NULL);
455         if (ret != SQLITE_OK) {
456                 _LOGE("connect db failed!");
457                 free(db_path);
458                 return PMINFO_R_ERROR;
459         }
460         free(db_path);
461
462         /*Begin transaction*/
463         /* Setting Manifest DB */
464         ret = sqlite3_exec(pkgmgr_parser_db, "BEGIN EXCLUSIVE", NULL, NULL, NULL);
465         tryvm_if(ret != SQLITE_OK, ret = PMINFO_R_ERROR, "Failed to begin transaction\n");
466         _LOGD("Transaction Begin\n");
467
468         /* pkgcakge_info table */
469         query = sqlite3_mprintf(
470                         "update package_info set installed_storage=%Q, external_path=%Q where package=%Q",
471                         location ? "installed_external" : "installed_internal", external_pkg_path, pkgid);
472
473         ret = sqlite3_exec(pkgmgr_parser_db, query, NULL, NULL, NULL);
474         tryvm_if(ret != SQLITE_OK, ret = PMINFO_R_ERROR, "Don't execute query = %s\n", query);
475         sqlite3_free(query);
476
477         /* package_app_info table */
478         query = sqlite3_mprintf(
479                         "update package_app_info set app_installed_storage=%Q, app_external_path=%Q where package=%Q",
480                         location ? "installed_external" : "installed_internal", external_pkg_path, pkgid);
481
482         ret = sqlite3_exec(pkgmgr_parser_db, query, NULL, NULL, NULL);
483         tryvm_if(ret != SQLITE_OK, ret = PMINFO_R_ERROR, "Don't execute query = %s\n", query);
484
485         /*Commit transaction*/
486         ret = sqlite3_exec(pkgmgr_parser_db, "COMMIT", NULL, NULL, NULL);
487         if (ret != SQLITE_OK) {
488                 _LOGE("Failed to commit transaction. Rollback now\n");
489                 ret = sqlite3_exec(pkgmgr_parser_db, "ROLLBACK", NULL, NULL, NULL);
490                 tryvm_if(ret != SQLITE_OK, ret = PMINFO_R_ERROR, "Don't execute query = %s\n", query);
491         }
492         _LOGD("Transaction Commit and End\n");
493
494         ret = PMINFO_R_OK;
495 catch:
496         sqlite3_close(pkgmgr_parser_db);
497         sqlite3_free(query);
498         return ret;
499 }
500
501 API int pkgmgrinfo_pkginfo_set_installed_storage(const char *pkgid, INSTALL_LOCATION location, const char *external_pkg_path)
502 {
503         return pkgmgrinfo_pkginfo_set_usr_installed_storage(pkgid, location, external_pkg_path, _getuid());
504 }