blob: 9d0dc5316c6dc859e64bac78764e5a82ab781b17 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2** Copyright 2008, The Android Open Source Project
3**
4** Licensed under the Apache License, Version 2.0 (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://www.apache.org/licenses/LICENSE-2.0
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#include "installd.h"
Kenny Root33b22642010-11-30 13:49:32 -080018#include <diskusage/dirsize.h>
Stephen Smalley0b58e6a2012-01-13 08:27:42 -050019#include <selinux/android.h>
Stephen Smalley0b58e6a2012-01-13 08:27:42 -050020
Kenny Root86c95842011-03-31 13:16:12 -070021/* Directory records that are used in execution of commands. */
22dir_rec_t android_data_dir;
23dir_rec_t android_asec_dir;
24dir_rec_t android_app_dir;
25dir_rec_t android_app_private_dir;
26dir_rec_array_t android_system_dirs;
27
Kenny Root35ab3ad2011-02-02 16:42:14 -080028int install(const char *pkgname, uid_t uid, gid_t gid)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029{
30 char pkgdir[PKG_PATH_MAX];
31 char libdir[PKG_PATH_MAX];
32
33 if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
Steve Block3762c312012-01-06 19:20:56 +000034 ALOGE("invalid uid/gid: %d %d\n", uid, gid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036 }
Oscar Montemayora8529f62009-11-18 10:14:20 -080037
Kenny Root86c95842011-03-31 13:16:12 -070038 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
Steve Block3762c312012-01-06 19:20:56 +000039 ALOGE("cannot create package path\n");
Kenny Root35ab3ad2011-02-02 16:42:14 -080040 return -1;
Kenny Root86c95842011-03-31 13:16:12 -070041 }
42
43 if (create_pkg_path(libdir, pkgname, PKG_LIB_POSTFIX, 0)) {
Steve Block3762c312012-01-06 19:20:56 +000044 ALOGE("cannot create package lib path\n");
Kenny Root35ab3ad2011-02-02 16:42:14 -080045 return -1;
Kenny Root86c95842011-03-31 13:16:12 -070046 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047
David 'Digit' Turner0dd50e62010-02-09 19:02:38 -080048 if (mkdir(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000049 ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050 return -errno;
51 }
Nick Kralevichf68327e2011-04-14 16:20:03 -070052 if (chmod(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000053 ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
Nick Kralevichf68327e2011-04-14 16:20:03 -070054 unlink(pkgdir);
55 return -errno;
56 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -050057
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058 if (mkdir(libdir, 0755) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000059 ALOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060 unlink(pkgdir);
61 return -errno;
62 }
Nick Kralevichf68327e2011-04-14 16:20:03 -070063 if (chmod(libdir, 0755) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000064 ALOGE("cannot chmod dir '%s': %s\n", libdir, strerror(errno));
Nick Kralevichf68327e2011-04-14 16:20:03 -070065 unlink(libdir);
66 unlink(pkgdir);
67 return -errno;
68 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069 if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000070 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071 unlink(libdir);
72 unlink(pkgdir);
73 return -errno;
74 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -050075
Kenny Rootc9a1aab2012-10-16 23:28:21 -070076 if (selinux_android_setfilecon(libdir, pkgname, uid) < 0) {
Joshua Brindle365861e2012-07-10 10:22:36 -040077 ALOGE("cannot setfilecon dir '%s': %s\n", libdir, strerror(errno));
Stephen Smalley0b58e6a2012-01-13 08:27:42 -050078 unlink(libdir);
79 unlink(pkgdir);
80 return -errno;
81 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -050082
Kenny Root4503cf62012-06-14 13:05:18 -070083 if (chown(pkgdir, uid, gid) < 0) {
84 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
85 unlink(libdir);
86 unlink(pkgdir);
87 return -errno;
88 }
Kenny Root33ef4ee2012-06-18 10:26:36 -070089
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 return 0;
91}
92
Amith Yamasani0b285492011-04-14 17:35:23 -070093int uninstall(const char *pkgname, uid_t persona)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094{
95 char pkgdir[PKG_PATH_MAX];
96
Amith Yamasani0b285492011-04-14 17:35:23 -070097 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
Kenny Root35ab3ad2011-02-02 16:42:14 -080098 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099
Amith Yamasani0b285492011-04-14 17:35:23 -0700100 /* delete contents AND directory, no exceptions */
101 return delete_dir_contents(pkgdir, 1, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102}
103
Kenny Root35ab3ad2011-02-02 16:42:14 -0800104int renamepkg(const char *oldpkgname, const char *newpkgname)
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800105{
106 char oldpkgdir[PKG_PATH_MAX];
107 char newpkgdir[PKG_PATH_MAX];
108
Kenny Root86c95842011-03-31 13:16:12 -0700109 if (create_pkg_path(oldpkgdir, oldpkgname, PKG_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800110 return -1;
Kenny Root86c95842011-03-31 13:16:12 -0700111 if (create_pkg_path(newpkgdir, newpkgname, PKG_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800112 return -1;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800113
114 if (rename(oldpkgdir, newpkgdir) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000115 ALOGE("cannot rename dir '%s' to '%s': %s\n", oldpkgdir, newpkgdir, strerror(errno));
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800116 return -errno;
117 }
118 return 0;
119}
120
Dianne Hackbornd0c5f512012-06-07 16:53:59 -0700121int fix_uid(const char *pkgname, uid_t uid, gid_t gid)
122{
123 char pkgdir[PKG_PATH_MAX];
124 struct stat s;
125 int rc = 0;
126
127 if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
128 ALOGE("invalid uid/gid: %d %d\n", uid, gid);
129 return -1;
130 }
131
132 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
133 ALOGE("cannot create package path\n");
134 return -1;
135 }
136
137 if (stat(pkgdir, &s) < 0) return -1;
138
139 if (s.st_uid != 0 || s.st_gid != 0) {
140 ALOGE("fixing uid of non-root pkg: %s %d %d\n", pkgdir, s.st_uid, s.st_gid);
141 return -1;
142 }
143
144 if (chmod(pkgdir, 0751) < 0) {
145 ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
146 unlink(pkgdir);
147 return -errno;
148 }
149 if (chown(pkgdir, uid, gid) < 0) {
150 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
151 unlink(pkgdir);
152 return -errno;
153 }
154
155 return 0;
156}
157
Amith Yamasani0b285492011-04-14 17:35:23 -0700158int delete_user_data(const char *pkgname, uid_t persona)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159{
160 char pkgdir[PKG_PATH_MAX];
161
Amith Yamasani0b285492011-04-14 17:35:23 -0700162 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800163 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164
Amith Yamasani0b285492011-04-14 17:35:23 -0700165 /* delete contents, excluding "lib", but not the directory itself */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166 return delete_dir_contents(pkgdir, 0, "lib");
167}
168
Amith Yamasani0b285492011-04-14 17:35:23 -0700169int make_user_data(const char *pkgname, uid_t uid, uid_t persona)
170{
171 char pkgdir[PKG_PATH_MAX];
172 char real_libdir[PKG_PATH_MAX];
173
174 // Create the data dir for the package
175 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona)) {
176 return -1;
177 }
178 if (mkdir(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000179 ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
Amith Yamasani0b285492011-04-14 17:35:23 -0700180 return -errno;
181 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500182 if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
Joshua Brindle365861e2012-07-10 10:22:36 -0400183 ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500184 unlink(pkgdir);
185 return -errno;
186 }
Kenny Rootc9a1aab2012-10-16 23:28:21 -0700187 if (chown(pkgdir, uid, uid) < 0) {
188 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
189 unlink(pkgdir);
190 return -errno;
191 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500192
Amith Yamasani0b285492011-04-14 17:35:23 -0700193 return 0;
194}
195
196int delete_persona(uid_t persona)
197{
198 char pkgdir[PKG_PATH_MAX];
199
200 if (create_persona_path(pkgdir, persona))
201 return -1;
202
203 return delete_dir_contents(pkgdir, 1, NULL);
204}
205
Amith Yamasani742a6712011-05-04 14:49:28 -0700206int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy)
207{
208 char src_data_dir[PKG_PATH_MAX];
209 char pkg_path[PKG_PATH_MAX];
210 DIR *d;
211 struct dirent *de;
212 struct stat s;
213 uid_t uid;
214
215 if (create_persona_path(src_data_dir, src_persona)) {
216 return -1;
217 }
218
219 d = opendir(src_data_dir);
220 if (d != NULL) {
221 while ((de = readdir(d))) {
222 const char *name = de->d_name;
223
224 if (de->d_type == DT_DIR) {
225 int subfd;
226 /* always skip "." and ".." */
227 if (name[0] == '.') {
228 if (name[1] == 0) continue;
229 if ((name[1] == '.') && (name[2] == 0)) continue;
230 }
231 /* Create the full path to the package's data dir */
232 create_pkg_path(pkg_path, name, PKG_DIR_POSTFIX, src_persona);
233 /* Get the file stat */
234 if (stat(pkg_path, &s) < 0) continue;
235 /* Get the uid of the package */
236 ALOGI("Adding datadir for uid = %d\n", s.st_uid);
237 uid = (uid_t) s.st_uid % PER_USER_RANGE;
238 /* Create the directory for the target */
239 make_user_data(name, uid + target_persona * PER_USER_RANGE,
240 target_persona);
241 }
242 }
243 closedir(d);
244 }
245 return 0;
246}
247
Kenny Root35ab3ad2011-02-02 16:42:14 -0800248int delete_cache(const char *pkgname)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249{
250 char cachedir[PKG_PATH_MAX];
251
Kenny Root86c95842011-03-31 13:16:12 -0700252 if (create_pkg_path(cachedir, pkgname, CACHE_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800253 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254
255 /* delete contents, not the directory, no exceptions */
256 return delete_dir_contents(cachedir, 0, 0);
257}
258
Kenny Root3e319a92010-09-07 13:58:28 -0700259static int64_t disk_free()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260{
261 struct statfs sfs;
Kenny Root86c95842011-03-31 13:16:12 -0700262 if (statfs(android_data_dir.path, &sfs) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 return sfs.f_bavail * sfs.f_bsize;
264 } else {
Steve Block3762c312012-01-06 19:20:56 +0000265 ALOGE("Couldn't statfs %s: %s\n", android_data_dir.path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 return -1;
267 }
268}
269
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270/* Try to ensure free_size bytes of storage are available.
271 * Returns 0 on success.
272 * This is rather simple-minded because doing a full LRU would
273 * be potentially memory-intensive, and without atime it would
274 * also require that apps constantly modify file metadata even
275 * when just reading from the cache, which is pretty awful.
276 */
Kenny Root3e319a92010-09-07 13:58:28 -0700277int free_cache(int64_t free_size)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278{
279 const char *name;
280 int dfd, subfd;
281 DIR *d;
282 struct dirent *de;
Kenny Root3e319a92010-09-07 13:58:28 -0700283 int64_t avail;
Kenny Rootad757e92011-11-29 15:54:55 -0800284 char datadir[PKG_PATH_MAX];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285
286 avail = disk_free();
287 if (avail < 0) return -1;
288
Steve Block6215d3f2012-01-04 20:05:49 +0000289 ALOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290 if (avail >= free_size) return 0;
291
Kenny Rootad757e92011-11-29 15:54:55 -0800292 if (create_persona_path(datadir, 0)) {
Steve Block3762c312012-01-06 19:20:56 +0000293 ALOGE("couldn't get directory for persona 0");
Kenny Rootad757e92011-11-29 15:54:55 -0800294 return -1;
295 }
296
297 d = opendir(datadir);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298 if (d == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000299 ALOGE("cannot open %s: %s\n", datadir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300 return -1;
301 }
302 dfd = dirfd(d);
303
304 while ((de = readdir(d))) {
305 if (de->d_type != DT_DIR) continue;
306 name = de->d_name;
307
Oscar Montemayora8529f62009-11-18 10:14:20 -0800308 /* always skip "." and ".." */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800309 if (name[0] == '.') {
310 if (name[1] == 0) continue;
311 if ((name[1] == '.') && (name[2] == 0)) continue;
312 }
313
314 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
315 if (subfd < 0) continue;
316
317 delete_dir_contents_fd(subfd, "cache");
318 close(subfd);
319
320 avail = disk_free();
321 if (avail >= free_size) {
322 closedir(d);
323 return 0;
324 }
325 }
326 closedir(d);
Oscar Montemayora8529f62009-11-18 10:14:20 -0800327
328 /* Fail case - not possible to free space */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 return -1;
330}
331
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332int move_dex(const char *src, const char *dst)
333{
334 char src_dex[PKG_PATH_MAX];
335 char dst_dex[PKG_PATH_MAX];
336
Kenny Root86c95842011-03-31 13:16:12 -0700337 if (validate_apk_path(src)) return -1;
338 if (validate_apk_path(dst)) return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339
340 if (create_cache_path(src_dex, src)) return -1;
341 if (create_cache_path(dst_dex, dst)) return -1;
342
Steve Block71f2cf12011-10-20 11:56:00 +0100343 ALOGV("move %s -> %s\n", src_dex, dst_dex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344 if (rename(src_dex, dst_dex) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000345 ALOGE("Couldn't move %s: %s\n", src_dex, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 return -1;
347 } else {
348 return 0;
349 }
350}
351
352int rm_dex(const char *path)
353{
354 char dex_path[PKG_PATH_MAX];
355
Kenny Root86c95842011-03-31 13:16:12 -0700356 if (validate_apk_path(path)) return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 if (create_cache_path(dex_path, path)) return -1;
358
Steve Block71f2cf12011-10-20 11:56:00 +0100359 ALOGV("unlink %s\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 if (unlink(dex_path) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000361 ALOGE("Couldn't unlink %s: %s\n", dex_path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 return -1;
363 } else {
364 return 0;
365 }
366}
367
368int protect(char *pkgname, gid_t gid)
369{
370 struct stat s;
371 char pkgpath[PKG_PATH_MAX];
372
373 if (gid < AID_SYSTEM) return -1;
374
Kenny Root86c95842011-03-31 13:16:12 -0700375 if (create_pkg_path_in_dir(pkgpath, &android_app_private_dir, pkgname, ".apk"))
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376 return -1;
377
378 if (stat(pkgpath, &s) < 0) return -1;
379
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 if (chmod(pkgpath, S_IRUSR|S_IWUSR|S_IRGRP) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000381 ALOGE("failed to chmod '%s': %s\n", pkgpath, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 return -1;
383 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500384 if (selinux_android_setfilecon(pkgpath, pkgname, s.st_uid) < 0) {
Joshua Brindle365861e2012-07-10 10:22:36 -0400385 ALOGE("cannot setfilecon dir '%s': %s\n", pkgpath, strerror(errno));
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500386 return -1;
387 }
Kenny Rootc9a1aab2012-10-16 23:28:21 -0700388 if (chown(pkgpath, s.st_uid, gid) < 0) {
389 ALOGE("failed to chgrp '%s': %s\n", pkgpath, strerror(errno));
390 return -1;
391 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500392
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393 return 0;
394}
395
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396int get_size(const char *pkgname, const char *apkpath,
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700397 const char *fwdlock_apkpath, const char *asecpath,
398 int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize,
399 int64_t* _asecsize)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400{
401 DIR *d;
402 int dfd;
403 struct dirent *de;
404 struct stat s;
405 char path[PKG_PATH_MAX];
406
Kenny Root3e319a92010-09-07 13:58:28 -0700407 int64_t codesize = 0;
408 int64_t datasize = 0;
409 int64_t cachesize = 0;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700410 int64_t asecsize = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411
412 /* count the source apk as code -- but only if it's not
Suchi Amalapurapu8a9ab242010-03-11 16:49:16 -0800413 * on the /system partition and its not on the sdcard.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 */
Kenny Root86c95842011-03-31 13:16:12 -0700415 if (validate_system_app_path(apkpath) &&
416 strncmp(apkpath, android_asec_dir.path, android_asec_dir.len) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 if (stat(apkpath, &s) == 0) {
418 codesize += stat_size(&s);
419 }
420 }
421 /* count the forward locked apk as code if it is given
422 */
423 if (fwdlock_apkpath != NULL && fwdlock_apkpath[0] != '!') {
424 if (stat(fwdlock_apkpath, &s) == 0) {
425 codesize += stat_size(&s);
426 }
427 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 /* count the cached dexfile as code */
429 if (!create_cache_path(path, apkpath)) {
430 if (stat(path, &s) == 0) {
431 codesize += stat_size(&s);
432 }
433 }
434
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700435 /* compute asec size if it is given
436 */
437 if (asecpath != NULL && asecpath[0] != '!') {
438 if (stat(asecpath, &s) == 0) {
439 asecsize += stat_size(&s);
440 }
441 }
442
Kenny Root86c95842011-03-31 13:16:12 -0700443 if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, 0)) {
Kenny Root35ab3ad2011-02-02 16:42:14 -0800444 goto done;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800445 }
446
447 d = opendir(path);
448 if (d == NULL) {
449 goto done;
450 }
451 dfd = dirfd(d);
452
Kenny Root86c95842011-03-31 13:16:12 -0700453 /* most stuff in the pkgdir is data, except for the "cache"
454 * directory and below, which is cache, and the "lib" directory
455 * and below, which is code...
456 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 while ((de = readdir(d))) {
458 const char *name = de->d_name;
459
460 if (de->d_type == DT_DIR) {
461 int subfd;
462 /* always skip "." and ".." */
463 if (name[0] == '.') {
464 if (name[1] == 0) continue;
465 if ((name[1] == '.') && (name[2] == 0)) continue;
466 }
467 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
468 if (subfd >= 0) {
Kenny Root3e319a92010-09-07 13:58:28 -0700469 int64_t size = calculate_dir_size(subfd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800470 if (!strcmp(name,"lib")) {
471 codesize += size;
472 } else if(!strcmp(name,"cache")) {
473 cachesize += size;
474 } else {
475 datasize += size;
476 }
477 }
478 } else {
479 if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
480 datasize += stat_size(&s);
481 }
482 }
483 }
484 closedir(d);
485done:
486 *_codesize = codesize;
487 *_datasize = datasize;
488 *_cachesize = cachesize;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700489 *_asecsize = asecsize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490 return 0;
491}
492
493
494/* a simpler version of dexOptGenerateCacheFileName() */
495int create_cache_path(char path[PKG_PATH_MAX], const char *src)
496{
497 char *tmp;
498 int srclen;
499 int dstlen;
500
501 srclen = strlen(src);
502
503 /* demand that we are an absolute path */
504 if ((src == 0) || (src[0] != '/') || strstr(src,"..")) {
505 return -1;
506 }
507
508 if (srclen > PKG_PATH_MAX) { // XXX: PKG_NAME_MAX?
509 return -1;
510 }
511
512 dstlen = srclen + strlen(DALVIK_CACHE_PREFIX) +
513 strlen(DALVIK_CACHE_POSTFIX) + 1;
514
515 if (dstlen > PKG_PATH_MAX) {
516 return -1;
517 }
518
519 sprintf(path,"%s%s%s",
520 DALVIK_CACHE_PREFIX,
521 src + 1, /* skip the leading / */
522 DALVIK_CACHE_POSTFIX);
523
524 for(tmp = path + strlen(DALVIK_CACHE_PREFIX); *tmp; tmp++) {
525 if (*tmp == '/') {
526 *tmp = '@';
527 }
528 }
529
530 return 0;
531}
532
533static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name,
534 const char* dexopt_flags)
535{
536 static const char* DEX_OPT_BIN = "/system/bin/dexopt";
537 static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
538 char zip_num[MAX_INT_LEN];
539 char odex_num[MAX_INT_LEN];
540
541 sprintf(zip_num, "%d", zip_fd);
542 sprintf(odex_num, "%d", odex_fd);
543
544 execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name,
545 dexopt_flags, (char*) NULL);
Steve Block3762c312012-01-06 19:20:56 +0000546 ALOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800547}
548
549static int wait_dexopt(pid_t pid, const char* apk_path)
550{
551 int status;
552 pid_t got_pid;
553
554 /*
555 * Wait for the optimization process to finish.
556 */
557 while (1) {
558 got_pid = waitpid(pid, &status, 0);
559 if (got_pid == -1 && errno == EINTR) {
560 printf("waitpid interrupted, retrying\n");
561 } else {
562 break;
563 }
564 }
565 if (got_pid != pid) {
Steve Block8564c8d2012-01-05 23:22:43 +0000566 ALOGW("waitpid failed: wanted %d, got %d: %s\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 (int) pid, (int) got_pid, strerror(errno));
568 return 1;
569 }
570
571 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100572 ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 return 0;
574 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000575 ALOGW("DexInv: --- END '%s' --- status=0x%04x, process failed\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576 apk_path, status);
577 return status; /* always nonzero */
578 }
579}
580
581int dexopt(const char *apk_path, uid_t uid, int is_public)
582{
583 struct utimbuf ut;
584 struct stat apk_stat, dex_stat;
585 char dex_path[PKG_PATH_MAX];
586 char dexopt_flags[PROPERTY_VALUE_MAX];
587 char *end;
588 int res, zip_fd=-1, odex_fd=-1;
589
590 /* Before anything else: is there a .odex file? If so, we have
591 * pre-optimized the apk and there is nothing to do here.
592 */
593 if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
594 return -1;
595 }
596
597 /* platform-specific flags affecting optimization and verification */
598 property_get("dalvik.vm.dexopt-flags", dexopt_flags, "");
599
600 strcpy(dex_path, apk_path);
601 end = strrchr(dex_path, '.');
602 if (end != NULL) {
603 strcpy(end, ".odex");
604 if (stat(dex_path, &dex_stat) == 0) {
605 return 0;
606 }
607 }
608
609 if (create_cache_path(dex_path, apk_path)) {
610 return -1;
611 }
612
613 memset(&apk_stat, 0, sizeof(apk_stat));
614 stat(apk_path, &apk_stat);
615
616 zip_fd = open(apk_path, O_RDONLY, 0);
617 if (zip_fd < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000618 ALOGE("dexopt cannot open '%s' for input\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619 return -1;
620 }
621
622 unlink(dex_path);
623 odex_fd = open(dex_path, O_RDWR | O_CREAT | O_EXCL, 0644);
624 if (odex_fd < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000625 ALOGE("dexopt cannot open '%s' for output\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800626 goto fail;
627 }
628 if (fchown(odex_fd, AID_SYSTEM, uid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000629 ALOGE("dexopt cannot chown '%s'\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800630 goto fail;
631 }
632 if (fchmod(odex_fd,
633 S_IRUSR|S_IWUSR|S_IRGRP |
634 (is_public ? S_IROTH : 0)) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000635 ALOGE("dexopt cannot chmod '%s'\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 goto fail;
637 }
638
Steve Block71f2cf12011-10-20 11:56:00 +0100639 ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800640
641 pid_t pid;
642 pid = fork();
643 if (pid == 0) {
644 /* child -- drop privileges before continuing */
645 if (setgid(uid) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000646 ALOGE("setgid(%d) failed during dexopt\n", uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647 exit(64);
648 }
649 if (setuid(uid) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000650 ALOGE("setuid(%d) during dexopt\n", uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800651 exit(65);
652 }
653 if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000654 ALOGE("flock(%s) failed: %s\n", dex_path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800655 exit(66);
656 }
657
658 run_dexopt(zip_fd, odex_fd, apk_path, dexopt_flags);
659 exit(67); /* only get here on exec failure */
660 } else {
661 res = wait_dexopt(pid, apk_path);
662 if (res != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000663 ALOGE("dexopt failed on '%s' res = %d\n", dex_path, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 goto fail;
665 }
666 }
667
668 ut.actime = apk_stat.st_atime;
669 ut.modtime = apk_stat.st_mtime;
670 utime(dex_path, &ut);
671
672 close(odex_fd);
673 close(zip_fd);
674 return 0;
675
676fail:
677 if (odex_fd >= 0) {
678 close(odex_fd);
679 unlink(dex_path);
680 }
681 if (zip_fd >= 0) {
682 close(zip_fd);
683 }
684 return -1;
685}
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800686
Dianne Hackbornc1552392010-03-03 16:19:01 -0800687void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid,
688 struct stat* statbuf)
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800689{
690 while (path[basepos] != 0) {
691 if (path[basepos] == '/') {
692 path[basepos] = 0;
Dianne Hackbornc1552392010-03-03 16:19:01 -0800693 if (lstat(path, statbuf) < 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100694 ALOGV("Making directory: %s\n", path);
Dianne Hackbornc1552392010-03-03 16:19:01 -0800695 if (mkdir(path, mode) == 0) {
696 chown(path, uid, gid);
697 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000698 ALOGW("Unable to make directory %s: %s\n", path, strerror(errno));
Dianne Hackbornc1552392010-03-03 16:19:01 -0800699 }
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800700 }
701 path[basepos] = '/';
702 basepos++;
703 }
704 basepos++;
705 }
706}
707
Dianne Hackbornc1552392010-03-03 16:19:01 -0800708int movefileordir(char* srcpath, char* dstpath, int dstbasepos,
709 int dstuid, int dstgid, struct stat* statbuf)
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800710{
711 DIR *d;
712 struct dirent *de;
713 int res;
714
715 int srcend = strlen(srcpath);
716 int dstend = strlen(dstpath);
717
718 if (lstat(srcpath, statbuf) < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000719 ALOGW("Unable to stat %s: %s\n", srcpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800720 return 1;
721 }
722
723 if ((statbuf->st_mode&S_IFDIR) == 0) {
Dianne Hackbornc1552392010-03-03 16:19:01 -0800724 mkinnerdirs(dstpath, dstbasepos, S_IRWXU|S_IRWXG|S_IXOTH,
725 dstuid, dstgid, statbuf);
Steve Block71f2cf12011-10-20 11:56:00 +0100726 ALOGV("Renaming %s to %s (uid %d)\n", srcpath, dstpath, dstuid);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800727 if (rename(srcpath, dstpath) >= 0) {
728 if (chown(dstpath, dstuid, dstgid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000729 ALOGE("cannot chown %s: %s\n", dstpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800730 unlink(dstpath);
731 return 1;
732 }
733 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000734 ALOGW("Unable to rename %s to %s: %s\n",
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800735 srcpath, dstpath, strerror(errno));
736 return 1;
737 }
738 return 0;
739 }
740
741 d = opendir(srcpath);
742 if (d == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000743 ALOGW("Unable to opendir %s: %s\n", srcpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800744 return 1;
745 }
746
747 res = 0;
748
749 while ((de = readdir(d))) {
750 const char *name = de->d_name;
751 /* always skip "." and ".." */
752 if (name[0] == '.') {
753 if (name[1] == 0) continue;
754 if ((name[1] == '.') && (name[2] == 0)) continue;
755 }
756
757 if ((srcend+strlen(name)) >= (PKG_PATH_MAX-2)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000758 ALOGW("Source path too long; skipping: %s/%s\n", srcpath, name);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800759 continue;
760 }
761
762 if ((dstend+strlen(name)) >= (PKG_PATH_MAX-2)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000763 ALOGW("Destination path too long; skipping: %s/%s\n", dstpath, name);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800764 continue;
765 }
766
767 srcpath[srcend] = dstpath[dstend] = '/';
768 strcpy(srcpath+srcend+1, name);
769 strcpy(dstpath+dstend+1, name);
770
Dianne Hackbornc1552392010-03-03 16:19:01 -0800771 if (movefileordir(srcpath, dstpath, dstbasepos, dstuid, dstgid, statbuf) != 0) {
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800772 res = 1;
773 }
774
775 // Note: we will be leaving empty directories behind in srcpath,
776 // but that is okay, the package manager will be erasing all of the
777 // data associated with .apks that disappear.
778
779 srcpath[srcend] = dstpath[dstend] = 0;
780 }
781
782 closedir(d);
783 return res;
784}
785
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800786int movefiles()
787{
788 DIR *d;
789 int dfd, subfd;
790 struct dirent *de;
791 struct stat s;
792 char buf[PKG_PATH_MAX+1];
793 int bufp, bufe, bufi, readlen;
794
795 char srcpkg[PKG_NAME_MAX];
796 char dstpkg[PKG_NAME_MAX];
797 char srcpath[PKG_PATH_MAX];
798 char dstpath[PKG_PATH_MAX];
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800799 int dstuid=-1, dstgid=-1;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800800 int hasspace;
801
802 d = opendir(UPDATE_COMMANDS_DIR_PREFIX);
803 if (d == NULL) {
804 goto done;
805 }
806 dfd = dirfd(d);
807
808 /* Iterate through all files in the directory, executing the
809 * file movements requested there-in.
810 */
811 while ((de = readdir(d))) {
812 const char *name = de->d_name;
813
814 if (de->d_type == DT_DIR) {
815 continue;
816 } else {
817 subfd = openat(dfd, name, O_RDONLY);
818 if (subfd < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000819 ALOGW("Unable to open update commands at %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800820 UPDATE_COMMANDS_DIR_PREFIX, name);
821 continue;
822 }
823
824 bufp = 0;
825 bufe = 0;
826 buf[PKG_PATH_MAX] = 0;
827 srcpkg[0] = dstpkg[0] = 0;
828 while (1) {
829 bufi = bufp;
830 while (bufi < bufe && buf[bufi] != '\n') {
831 bufi++;
832 }
833 if (bufi < bufe) {
834 buf[bufi] = 0;
Steve Block71f2cf12011-10-20 11:56:00 +0100835 ALOGV("Processing line: %s\n", buf+bufp);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800836 hasspace = 0;
837 while (bufp < bufi && isspace(buf[bufp])) {
838 hasspace = 1;
839 bufp++;
840 }
841 if (buf[bufp] == '#' || bufp == bufi) {
842 // skip comments and empty lines.
843 } else if (hasspace) {
844 if (dstpkg[0] == 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000845 ALOGW("Path before package line in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800846 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
847 } else if (srcpkg[0] == 0) {
848 // Skip -- source package no longer exists.
849 } else {
Steve Block71f2cf12011-10-20 11:56:00 +0100850 ALOGV("Move file: %s (from %s to %s)\n", buf+bufp, srcpkg, dstpkg);
Kenny Root86c95842011-03-31 13:16:12 -0700851 if (!create_move_path(srcpath, srcpkg, buf+bufp, 0) &&
852 !create_move_path(dstpath, dstpkg, buf+bufp, 0)) {
Dianne Hackbornc1552392010-03-03 16:19:01 -0800853 movefileordir(srcpath, dstpath,
854 strlen(dstpath)-strlen(buf+bufp),
855 dstuid, dstgid, &s);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800856 }
857 }
858 } else {
859 char* div = strchr(buf+bufp, ':');
860 if (div == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000861 ALOGW("Bad package spec in %s%s; no ':' sep: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800862 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
863 } else {
864 *div = 0;
865 div++;
866 if (strlen(buf+bufp) < PKG_NAME_MAX) {
867 strcpy(dstpkg, buf+bufp);
868 } else {
869 srcpkg[0] = dstpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000870 ALOGW("Package name too long in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800871 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
872 }
873 if (strlen(div) < PKG_NAME_MAX) {
874 strcpy(srcpkg, div);
875 } else {
876 srcpkg[0] = dstpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000877 ALOGW("Package name too long in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800878 UPDATE_COMMANDS_DIR_PREFIX, name, div);
879 }
880 if (srcpkg[0] != 0) {
Kenny Root86c95842011-03-31 13:16:12 -0700881 if (!create_pkg_path(srcpath, srcpkg, PKG_DIR_POSTFIX, 0)) {
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800882 if (lstat(srcpath, &s) < 0) {
883 // Package no longer exists -- skip.
884 srcpkg[0] = 0;
885 }
886 } else {
887 srcpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000888 ALOGW("Can't create path %s in %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800889 div, UPDATE_COMMANDS_DIR_PREFIX, name);
890 }
891 if (srcpkg[0] != 0) {
Kenny Root86c95842011-03-31 13:16:12 -0700892 if (!create_pkg_path(dstpath, dstpkg, PKG_DIR_POSTFIX, 0)) {
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800893 if (lstat(dstpath, &s) == 0) {
894 dstuid = s.st_uid;
895 dstgid = s.st_gid;
896 } else {
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800897 // Destination package doesn't
898 // exist... due to original-package,
899 // this is normal, so don't be
900 // noisy about it.
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800901 srcpkg[0] = 0;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800902 }
903 } else {
904 srcpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000905 ALOGW("Can't create path %s in %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800906 div, UPDATE_COMMANDS_DIR_PREFIX, name);
907 }
908 }
Steve Block71f2cf12011-10-20 11:56:00 +0100909 ALOGV("Transfering from %s to %s: uid=%d\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800910 srcpkg, dstpkg, dstuid);
911 }
912 }
913 }
914 bufp = bufi+1;
915 } else {
916 if (bufp == 0) {
917 if (bufp < bufe) {
Steve Block8564c8d2012-01-05 23:22:43 +0000918 ALOGW("Line too long in %s%s, skipping: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800919 UPDATE_COMMANDS_DIR_PREFIX, name, buf);
920 }
921 } else if (bufp < bufe) {
922 memcpy(buf, buf+bufp, bufe-bufp);
923 bufe -= bufp;
924 bufp = 0;
925 }
926 readlen = read(subfd, buf+bufe, PKG_PATH_MAX-bufe);
927 if (readlen < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000928 ALOGW("Failure reading update commands in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800929 UPDATE_COMMANDS_DIR_PREFIX, name, strerror(errno));
930 break;
931 } else if (readlen == 0) {
932 break;
933 }
934 bufe += readlen;
935 buf[bufe] = 0;
Steve Block71f2cf12011-10-20 11:56:00 +0100936 ALOGV("Read buf: %s\n", buf);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800937 }
938 }
939 close(subfd);
940 }
941 }
942 closedir(d);
943done:
944 return 0;
945}
Kenny Root6a6b0072010-10-07 16:46:10 -0700946
947int linklib(const char* dataDir, const char* asecLibDir)
948{
949 char libdir[PKG_PATH_MAX];
950 struct stat s, libStat;
951 int rc = 0;
952
953 const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
954 if (libdirLen >= PKG_PATH_MAX) {
Steve Block3762c312012-01-06 19:20:56 +0000955 ALOGE("library dir len too large");
Kenny Root0332d1c2010-10-21 16:14:06 -0700956 return -1;
Kenny Root6a6b0072010-10-07 16:46:10 -0700957 }
958
959 if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
Steve Block3762c312012-01-06 19:20:56 +0000960 ALOGE("library dir not written successfully: %s\n", strerror(errno));
Kenny Root0332d1c2010-10-21 16:14:06 -0700961 return -1;
Kenny Root6a6b0072010-10-07 16:46:10 -0700962 }
963
964 if (stat(dataDir, &s) < 0) return -1;
965
966 if (chown(dataDir, 0, 0) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000967 ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700968 return -1;
969 }
970
971 if (chmod(dataDir, 0700) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000972 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700973 rc = -1;
974 goto out;
975 }
976
977 if (lstat(libdir, &libStat) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000978 ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700979 rc = -1;
980 goto out;
981 }
982
983 if (S_ISDIR(libStat.st_mode)) {
984 if (delete_dir_contents(libdir, 1, 0) < 0) {
985 rc = -1;
986 goto out;
987 }
988 } else if (S_ISLNK(libStat.st_mode)) {
989 if (unlink(libdir) < 0) {
990 rc = -1;
991 goto out;
992 }
993 }
994
995 if (symlink(asecLibDir, libdir) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000996 ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libdir, asecLibDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700997 rc = -errno;
998 goto out;
999 }
1000
1001 if (lchown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001002 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001003 unlink(libdir);
1004 rc = -errno;
1005 goto out;
1006 }
1007
1008out:
1009 if (chmod(dataDir, s.st_mode) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001010 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Dianne Hackbornd0c5f512012-06-07 16:53:59 -07001011 rc = -errno;
Kenny Root6a6b0072010-10-07 16:46:10 -07001012 }
1013
1014 if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001015 ALOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001016 return -errno;
1017 }
1018
1019 return rc;
1020}
1021
1022int unlinklib(const char* dataDir)
1023{
1024 char libdir[PKG_PATH_MAX];
1025 struct stat s, libStat;
1026 int rc = 0;
1027
1028 const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
1029 if (libdirLen >= PKG_PATH_MAX) {
1030 return -1;
1031 }
1032
1033 if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
Steve Block3762c312012-01-06 19:20:56 +00001034 ALOGE("library dir not written successfully: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001035 return -1;
1036 }
1037
1038 if (stat(dataDir, &s) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001039 ALOGE("couldn't state data dir");
Kenny Root6a6b0072010-10-07 16:46:10 -07001040 return -1;
1041 }
1042
1043 if (chown(dataDir, 0, 0) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001044 ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001045 return -1;
1046 }
1047
1048 if (chmod(dataDir, 0700) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001049 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001050 rc = -1;
1051 goto out;
1052 }
1053
1054 if (lstat(libdir, &libStat) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001055 ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001056 rc = -1;
1057 goto out;
1058 }
1059
1060 if (S_ISDIR(libStat.st_mode)) {
1061 if (delete_dir_contents(libdir, 1, 0) < 0) {
1062 rc = -1;
1063 goto out;
1064 }
1065 } else if (S_ISLNK(libStat.st_mode)) {
1066 if (unlink(libdir) < 0) {
1067 rc = -1;
1068 goto out;
1069 }
1070 }
1071
1072 if (mkdir(libdir, 0755) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001073 ALOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001074 rc = -errno;
1075 goto out;
1076 }
Kenny Root515087d2012-07-30 15:00:16 -07001077 if (chmod(libdir, 0755) < 0) {
1078 ALOGE("cannot chmod dir '%s': %s\n", libdir, strerror(errno));
1079 unlink(libdir);
1080 rc = -errno;
1081 goto out;
1082 }
Kenny Root6a6b0072010-10-07 16:46:10 -07001083 if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001084 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001085 unlink(libdir);
1086 rc = -errno;
1087 goto out;
1088 }
1089
1090out:
1091 if (chmod(dataDir, s.st_mode) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001092 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Dianne Hackbornd0c5f512012-06-07 16:53:59 -07001093 rc = -1;
Kenny Root6a6b0072010-10-07 16:46:10 -07001094 }
1095
1096 if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001097 ALOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001098 return -1;
1099 }
1100
1101 return rc;
1102}