0ead442398a572b154eaf6d785352cc5f65d105d
[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         NULL
310 };
311
312 int __open_manifest_db(uid_t uid, bool readonly)
313 {
314         int ret;
315         char *user_pkg_parser;
316         int flags;
317
318         if (manifest_db.ref) {
319                 manifest_db.ref++;
320                 return 0;
321         }
322
323         user_pkg_parser = getUserPkgParserDBPathUID(uid);
324         if (user_pkg_parser == NULL) {
325                 _LOGE("Failed to get pkg parser db path - %d", uid);
326                 return -1;
327         }
328
329         if (access(user_pkg_parser, F_OK) != 0) {
330                 _LOGE("Manifest DB does not exists !!");
331                 free(user_pkg_parser);
332                 return -1;
333         }
334
335         flags = readonly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE;
336         ret = db_util_open_with_options(user_pkg_parser, &GET_DB(manifest_db),
337                         flags, NULL);
338         if (ret != SQLITE_OK) {
339                 _LOGE("connect db [%s] failed!\n", user_pkg_parser);
340                 free(user_pkg_parser);
341                 return -1;
342         }
343
344         manifest_db.ref++;
345         if (readonly) {
346                 ret = __attach_and_create_view(GET_DB(manifest_db), MANIFEST_DB,
347                                 parserdb_tables, uid);
348                 if (ret != SQLITE_OK) {
349                         _LOGE("attach db [%s] failed!\n", user_pkg_parser);
350                         free(user_pkg_parser);
351                         return -1;
352                 }
353         }
354
355         free(user_pkg_parser);
356
357         return 0;
358 }
359
360 int __close_cert_db(void)
361 {
362         if (cert_db.ref) {
363                 if (--cert_db.ref == 0)
364                         sqlite3_close_v2(GET_DB(cert_db));
365                 return 0;
366         }
367         _LOGE("Certificate DB is already closed !!\n");
368         return -1;
369 }
370
371 static const char *certdb_tables[] = {
372         "package_cert_index_info",
373         "package_cert_info",
374         NULL
375 };
376
377 int __open_cert_db(uid_t uid, bool readonly)
378 {
379         int ret;
380         char *user_cert_parser;
381         int flags;
382
383         if (cert_db.ref) {
384                 cert_db.ref++;
385                 return 0;
386         }
387
388         user_cert_parser = getUserPkgCertDBPathUID(uid);
389         if (user_cert_parser == NULL) {
390                 _LOGE("Failed to get pkg cert db path - %d", uid);
391                 return -1;
392         }
393
394         if (access(user_cert_parser, F_OK) != 0) {
395                 _LOGE("Cert DB does not exists !!");
396                 free(user_cert_parser);
397                 return -1;
398         }
399
400         flags = readonly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE;
401         ret = db_util_open_with_options(user_cert_parser, &GET_DB(cert_db),
402                         flags, NULL);
403         if (ret != SQLITE_OK) {
404                 _LOGE("connect db [%s] failed!", user_cert_parser);
405                 free(user_cert_parser);
406                 return -1;
407         }
408         cert_db.ref++;
409         if (readonly) {
410                 ret = __attach_and_create_view(GET_DB(cert_db), CERT_DB,
411                                 certdb_tables, uid);
412                 if (ret != SQLITE_OK) {
413                         _LOGE("attach db [%s] failed!", user_cert_parser);
414                         free(user_cert_parser);
415                         return -1;
416                 }
417         }
418
419         free(user_cert_parser);
420
421         return 0;
422 }
423
424 void _save_column_int(sqlite3_stmt *stmt, int idx, int *i)
425 {
426         *i = sqlite3_column_int(stmt, idx);
427 }
428
429 inline void _save_column_str(sqlite3_stmt *stmt, int idx, char **str)
430 {
431         const char *val;
432
433         val = (const char *)sqlite3_column_text(stmt, idx);
434         if (val)
435                 *str = strdup(val);
436 }
437
438 API int pkgmgrinfo_pkginfo_set_usr_installed_storage(const char *pkgid, INSTALL_LOCATION location, const char *external_pkg_path, uid_t uid)
439 {
440         retvm_if(pkgid == NULL, PMINFO_R_EINVAL, "pkgid is NULL\n");
441         int ret = -1;
442         sqlite3 *pkgmgr_parser_db = NULL;
443         char *query = NULL;
444         char *db_path;
445
446         db_path = getUserPkgParserDBPathUID(uid);
447         if (db_path == NULL) {
448                 _LOGE("Failed to get pkg parser db path - %d", uid);
449                 return PMINFO_R_ERROR;
450         }
451
452         ret = db_util_open_with_options(db_path, &pkgmgr_parser_db,
453                         SQLITE_OPEN_READWRITE, NULL);
454         if (ret != SQLITE_OK) {
455                 _LOGE("connect db failed!");
456                 free(db_path);
457                 return PMINFO_R_ERROR;
458         }
459         free(db_path);
460
461         /*Begin transaction*/
462         /* Setting Manifest DB */
463         ret = sqlite3_exec(pkgmgr_parser_db, "BEGIN EXCLUSIVE", NULL, NULL, NULL);
464         tryvm_if(ret != SQLITE_OK, ret = PMINFO_R_ERROR, "Failed to begin transaction\n");
465         _LOGD("Transaction Begin\n");
466
467         /* pkgcakge_info table */
468         query = sqlite3_mprintf(
469                         "update package_info set installed_storage=%Q, external_path=%Q where package=%Q",
470                         location ? "installed_external" : "installed_internal", external_pkg_path, pkgid);
471
472         ret = sqlite3_exec(pkgmgr_parser_db, query, NULL, NULL, NULL);
473         tryvm_if(ret != SQLITE_OK, ret = PMINFO_R_ERROR, "Don't execute query = %s\n", query);
474         sqlite3_free(query);
475
476         /* package_app_info table */
477         query = sqlite3_mprintf(
478                         "update package_app_info set app_installed_storage=%Q, app_external_path=%Q where package=%Q",
479                         location ? "installed_external" : "installed_internal", external_pkg_path, pkgid);
480
481         ret = sqlite3_exec(pkgmgr_parser_db, query, NULL, NULL, NULL);
482         tryvm_if(ret != SQLITE_OK, ret = PMINFO_R_ERROR, "Don't execute query = %s\n", query);
483
484         /*Commit transaction*/
485         ret = sqlite3_exec(pkgmgr_parser_db, "COMMIT", NULL, NULL, NULL);
486         if (ret != SQLITE_OK) {
487                 _LOGE("Failed to commit transaction. Rollback now\n");
488                 ret = sqlite3_exec(pkgmgr_parser_db, "ROLLBACK", NULL, NULL, NULL);
489                 tryvm_if(ret != SQLITE_OK, ret = PMINFO_R_ERROR, "Don't execute query = %s\n", query);
490         }
491         _LOGD("Transaction Commit and End\n");
492
493         ret = PMINFO_R_OK;
494 catch:
495         sqlite3_close(pkgmgr_parser_db);
496         sqlite3_free(query);
497         return ret;
498 }
499
500 API int pkgmgrinfo_pkginfo_set_installed_storage(const char *pkgid, INSTALL_LOCATION location, const char *external_pkg_path)
501 {
502         return pkgmgrinfo_pkginfo_set_usr_installed_storage(pkgid, location, external_pkg_path, _getuid());
503 }