blob: 1bb49353d9bce445ee597de7d234941c4ffcd613 [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>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019
Stephen Smalley0b58e6a2012-01-13 08:27:42 -050020#ifdef HAVE_SELINUX
21#include <selinux/android.h>
22#endif
23
Kenny Root86c95842011-03-31 13:16:12 -070024/* Directory records that are used in execution of commands. */
25dir_rec_t android_data_dir;
26dir_rec_t android_asec_dir;
27dir_rec_t android_app_dir;
28dir_rec_t android_app_private_dir;
29dir_rec_array_t android_system_dirs;
30
Kenny Root35ab3ad2011-02-02 16:42:14 -080031int install(const char *pkgname, uid_t uid, gid_t gid)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032{
33 char pkgdir[PKG_PATH_MAX];
34 char libdir[PKG_PATH_MAX];
35
36 if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
Steve Block3762c312012-01-06 19:20:56 +000037 ALOGE("invalid uid/gid: %d %d\n", uid, gid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039 }
Oscar Montemayora8529f62009-11-18 10:14:20 -080040
Kenny Root86c95842011-03-31 13:16:12 -070041 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
Steve Block3762c312012-01-06 19:20:56 +000042 ALOGE("cannot create package path\n");
Kenny Root35ab3ad2011-02-02 16:42:14 -080043 return -1;
Kenny Root86c95842011-03-31 13:16:12 -070044 }
45
46 if (create_pkg_path(libdir, pkgname, PKG_LIB_POSTFIX, 0)) {
Steve Block3762c312012-01-06 19:20:56 +000047 ALOGE("cannot create package lib path\n");
Kenny Root35ab3ad2011-02-02 16:42:14 -080048 return -1;
Kenny Root86c95842011-03-31 13:16:12 -070049 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050
David 'Digit' Turner0dd50e62010-02-09 19:02:38 -080051 if (mkdir(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000052 ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053 return -errno;
54 }
Nick Kralevichf68327e2011-04-14 16:20:03 -070055 if (chmod(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000056 ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
Nick Kralevichf68327e2011-04-14 16:20:03 -070057 unlink(pkgdir);
58 return -errno;
59 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -050060
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061 if (mkdir(libdir, 0755) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000062 ALOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063 unlink(pkgdir);
64 return -errno;
65 }
Nick Kralevichf68327e2011-04-14 16:20:03 -070066 if (chmod(libdir, 0755) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000067 ALOGE("cannot chmod dir '%s': %s\n", libdir, strerror(errno));
Nick Kralevichf68327e2011-04-14 16:20:03 -070068 unlink(libdir);
69 unlink(pkgdir);
70 return -errno;
71 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072 if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000073 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074 unlink(libdir);
75 unlink(pkgdir);
76 return -errno;
77 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -050078
79#ifdef HAVE_SELINUX
80 if (selinux_android_setfilecon(libdir, pkgname, AID_SYSTEM) < 0) {
81 LOGE("cannot setfilecon dir '%s': %s\n", libdir, strerror(errno));
82 unlink(libdir);
83 unlink(pkgdir);
84 return -errno;
85 }
86#endif
87
Kenny Root4503cf62012-06-14 13:05:18 -070088 if (chown(pkgdir, uid, gid) < 0) {
89 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
90 unlink(libdir);
91 unlink(pkgdir);
92 return -errno;
93 }
Kenny Root33ef4ee2012-06-18 10:26:36 -070094
95#ifdef HAVE_SELINUX
96 if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
97 LOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
98 unlink(libdir);
99 unlink(pkgdir);
100 return -errno;
101 }
102#endif
103
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 return 0;
105}
106
Amith Yamasani0b285492011-04-14 17:35:23 -0700107int uninstall(const char *pkgname, uid_t persona)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108{
109 char pkgdir[PKG_PATH_MAX];
110
Amith Yamasani0b285492011-04-14 17:35:23 -0700111 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800112 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113
Amith Yamasani0b285492011-04-14 17:35:23 -0700114 /* delete contents AND directory, no exceptions */
115 return delete_dir_contents(pkgdir, 1, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116}
117
Kenny Root35ab3ad2011-02-02 16:42:14 -0800118int renamepkg(const char *oldpkgname, const char *newpkgname)
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800119{
120 char oldpkgdir[PKG_PATH_MAX];
121 char newpkgdir[PKG_PATH_MAX];
122
Kenny Root86c95842011-03-31 13:16:12 -0700123 if (create_pkg_path(oldpkgdir, oldpkgname, PKG_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800124 return -1;
Kenny Root86c95842011-03-31 13:16:12 -0700125 if (create_pkg_path(newpkgdir, newpkgname, PKG_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800126 return -1;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800127
128 if (rename(oldpkgdir, newpkgdir) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000129 ALOGE("cannot rename dir '%s' to '%s': %s\n", oldpkgdir, newpkgdir, strerror(errno));
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800130 return -errno;
131 }
132 return 0;
133}
134
Dianne Hackbornd0c5f512012-06-07 16:53:59 -0700135int fix_uid(const char *pkgname, uid_t uid, gid_t gid)
136{
137 char pkgdir[PKG_PATH_MAX];
138 struct stat s;
139 int rc = 0;
140
141 if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
142 ALOGE("invalid uid/gid: %d %d\n", uid, gid);
143 return -1;
144 }
145
146 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
147 ALOGE("cannot create package path\n");
148 return -1;
149 }
150
151 if (stat(pkgdir, &s) < 0) return -1;
152
153 if (s.st_uid != 0 || s.st_gid != 0) {
154 ALOGE("fixing uid of non-root pkg: %s %d %d\n", pkgdir, s.st_uid, s.st_gid);
155 return -1;
156 }
157
158 if (chmod(pkgdir, 0751) < 0) {
159 ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
160 unlink(pkgdir);
161 return -errno;
162 }
163 if (chown(pkgdir, uid, gid) < 0) {
164 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
165 unlink(pkgdir);
166 return -errno;
167 }
168
169 return 0;
170}
171
Amith Yamasani0b285492011-04-14 17:35:23 -0700172int delete_user_data(const char *pkgname, uid_t persona)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173{
174 char pkgdir[PKG_PATH_MAX];
175
Amith Yamasani0b285492011-04-14 17:35:23 -0700176 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800177 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178
Amith Yamasani0b285492011-04-14 17:35:23 -0700179 /* delete contents, excluding "lib", but not the directory itself */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 return delete_dir_contents(pkgdir, 0, "lib");
181}
182
Amith Yamasani0b285492011-04-14 17:35:23 -0700183int make_user_data(const char *pkgname, uid_t uid, uid_t persona)
184{
185 char pkgdir[PKG_PATH_MAX];
186 char real_libdir[PKG_PATH_MAX];
187
188 // Create the data dir for the package
189 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona)) {
190 return -1;
191 }
192 if (mkdir(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000193 ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
Amith Yamasani0b285492011-04-14 17:35:23 -0700194 return -errno;
195 }
196 if (chown(pkgdir, uid, uid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000197 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
Amith Yamasani0b285492011-04-14 17:35:23 -0700198 unlink(pkgdir);
199 return -errno;
200 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500201
202#ifdef HAVE_SELINUX
203 if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
204 LOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
205 unlink(pkgdir);
206 return -errno;
207 }
208#endif
209
Amith Yamasani0b285492011-04-14 17:35:23 -0700210 return 0;
211}
212
213int delete_persona(uid_t persona)
214{
215 char pkgdir[PKG_PATH_MAX];
216
217 if (create_persona_path(pkgdir, persona))
218 return -1;
219
220 return delete_dir_contents(pkgdir, 1, NULL);
221}
222
Amith Yamasani742a6712011-05-04 14:49:28 -0700223int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy)
224{
225 char src_data_dir[PKG_PATH_MAX];
226 char pkg_path[PKG_PATH_MAX];
227 DIR *d;
228 struct dirent *de;
229 struct stat s;
230 uid_t uid;
231
232 if (create_persona_path(src_data_dir, src_persona)) {
233 return -1;
234 }
235
236 d = opendir(src_data_dir);
237 if (d != NULL) {
238 while ((de = readdir(d))) {
239 const char *name = de->d_name;
240
241 if (de->d_type == DT_DIR) {
242 int subfd;
243 /* always skip "." and ".." */
244 if (name[0] == '.') {
245 if (name[1] == 0) continue;
246 if ((name[1] == '.') && (name[2] == 0)) continue;
247 }
248 /* Create the full path to the package's data dir */
249 create_pkg_path(pkg_path, name, PKG_DIR_POSTFIX, src_persona);
250 /* Get the file stat */
251 if (stat(pkg_path, &s) < 0) continue;
252 /* Get the uid of the package */
253 ALOGI("Adding datadir for uid = %d\n", s.st_uid);
254 uid = (uid_t) s.st_uid % PER_USER_RANGE;
255 /* Create the directory for the target */
256 make_user_data(name, uid + target_persona * PER_USER_RANGE,
257 target_persona);
258 }
259 }
260 closedir(d);
261 }
262 return 0;
263}
264
Kenny Root35ab3ad2011-02-02 16:42:14 -0800265int delete_cache(const char *pkgname)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266{
267 char cachedir[PKG_PATH_MAX];
268
Kenny Root86c95842011-03-31 13:16:12 -0700269 if (create_pkg_path(cachedir, pkgname, CACHE_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800270 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800271
272 /* delete contents, not the directory, no exceptions */
273 return delete_dir_contents(cachedir, 0, 0);
274}
275
Kenny Root3e319a92010-09-07 13:58:28 -0700276static int64_t disk_free()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277{
278 struct statfs sfs;
Kenny Root86c95842011-03-31 13:16:12 -0700279 if (statfs(android_data_dir.path, &sfs) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280 return sfs.f_bavail * sfs.f_bsize;
281 } else {
Steve Block3762c312012-01-06 19:20:56 +0000282 ALOGE("Couldn't statfs %s: %s\n", android_data_dir.path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283 return -1;
284 }
285}
286
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287/* Try to ensure free_size bytes of storage are available.
288 * Returns 0 on success.
289 * This is rather simple-minded because doing a full LRU would
290 * be potentially memory-intensive, and without atime it would
291 * also require that apps constantly modify file metadata even
292 * when just reading from the cache, which is pretty awful.
293 */
Kenny Root3e319a92010-09-07 13:58:28 -0700294int free_cache(int64_t free_size)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800295{
296 const char *name;
297 int dfd, subfd;
298 DIR *d;
299 struct dirent *de;
Kenny Root3e319a92010-09-07 13:58:28 -0700300 int64_t avail;
Kenny Rootad757e92011-11-29 15:54:55 -0800301 char datadir[PKG_PATH_MAX];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302
303 avail = disk_free();
304 if (avail < 0) return -1;
305
Steve Block6215d3f2012-01-04 20:05:49 +0000306 ALOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800307 if (avail >= free_size) return 0;
308
Kenny Rootad757e92011-11-29 15:54:55 -0800309 if (create_persona_path(datadir, 0)) {
Steve Block3762c312012-01-06 19:20:56 +0000310 ALOGE("couldn't get directory for persona 0");
Kenny Rootad757e92011-11-29 15:54:55 -0800311 return -1;
312 }
313
314 d = opendir(datadir);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315 if (d == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000316 ALOGE("cannot open %s: %s\n", datadir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317 return -1;
318 }
319 dfd = dirfd(d);
320
321 while ((de = readdir(d))) {
322 if (de->d_type != DT_DIR) continue;
323 name = de->d_name;
324
Oscar Montemayora8529f62009-11-18 10:14:20 -0800325 /* always skip "." and ".." */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326 if (name[0] == '.') {
327 if (name[1] == 0) continue;
328 if ((name[1] == '.') && (name[2] == 0)) continue;
329 }
330
331 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
332 if (subfd < 0) continue;
333
334 delete_dir_contents_fd(subfd, "cache");
335 close(subfd);
336
337 avail = disk_free();
338 if (avail >= free_size) {
339 closedir(d);
340 return 0;
341 }
342 }
343 closedir(d);
Oscar Montemayora8529f62009-11-18 10:14:20 -0800344
345 /* Fail case - not possible to free space */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 return -1;
347}
348
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349int move_dex(const char *src, const char *dst)
350{
351 char src_dex[PKG_PATH_MAX];
352 char dst_dex[PKG_PATH_MAX];
353
Kenny Root86c95842011-03-31 13:16:12 -0700354 if (validate_apk_path(src)) return -1;
355 if (validate_apk_path(dst)) return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356
357 if (create_cache_path(src_dex, src)) return -1;
358 if (create_cache_path(dst_dex, dst)) return -1;
359
Steve Block71f2cf12011-10-20 11:56:00 +0100360 ALOGV("move %s -> %s\n", src_dex, dst_dex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 if (rename(src_dex, dst_dex) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000362 ALOGE("Couldn't move %s: %s\n", src_dex, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 return -1;
364 } else {
365 return 0;
366 }
367}
368
369int rm_dex(const char *path)
370{
371 char dex_path[PKG_PATH_MAX];
372
Kenny Root86c95842011-03-31 13:16:12 -0700373 if (validate_apk_path(path)) return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800374 if (create_cache_path(dex_path, path)) return -1;
375
Steve Block71f2cf12011-10-20 11:56:00 +0100376 ALOGV("unlink %s\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377 if (unlink(dex_path) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000378 ALOGE("Couldn't unlink %s: %s\n", dex_path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 return -1;
380 } else {
381 return 0;
382 }
383}
384
385int protect(char *pkgname, gid_t gid)
386{
387 struct stat s;
388 char pkgpath[PKG_PATH_MAX];
389
390 if (gid < AID_SYSTEM) return -1;
391
Kenny Root86c95842011-03-31 13:16:12 -0700392 if (create_pkg_path_in_dir(pkgpath, &android_app_private_dir, pkgname, ".apk"))
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393 return -1;
394
395 if (stat(pkgpath, &s) < 0) return -1;
396
397 if (chown(pkgpath, s.st_uid, gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000398 ALOGE("failed to chgrp '%s': %s\n", pkgpath, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 return -1;
400 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 if (chmod(pkgpath, S_IRUSR|S_IWUSR|S_IRGRP) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000402 ALOGE("failed to chmod '%s': %s\n", pkgpath, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403 return -1;
404 }
405
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500406#ifdef HAVE_SELINUX
407 if (selinux_android_setfilecon(pkgpath, pkgname, s.st_uid) < 0) {
408 LOGE("cannot setfilecon dir '%s': %s\n", pkgpath, strerror(errno));
409 return -1;
410 }
411#endif
412
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 return 0;
414}
415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416int get_size(const char *pkgname, const char *apkpath,
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700417 const char *fwdlock_apkpath, const char *asecpath,
418 int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize,
419 int64_t* _asecsize)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420{
421 DIR *d;
422 int dfd;
423 struct dirent *de;
424 struct stat s;
425 char path[PKG_PATH_MAX];
426
Kenny Root3e319a92010-09-07 13:58:28 -0700427 int64_t codesize = 0;
428 int64_t datasize = 0;
429 int64_t cachesize = 0;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700430 int64_t asecsize = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431
432 /* count the source apk as code -- but only if it's not
Suchi Amalapurapu8a9ab242010-03-11 16:49:16 -0800433 * on the /system partition and its not on the sdcard.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434 */
Kenny Root86c95842011-03-31 13:16:12 -0700435 if (validate_system_app_path(apkpath) &&
436 strncmp(apkpath, android_asec_dir.path, android_asec_dir.len) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800437 if (stat(apkpath, &s) == 0) {
438 codesize += stat_size(&s);
439 }
440 }
441 /* count the forward locked apk as code if it is given
442 */
443 if (fwdlock_apkpath != NULL && fwdlock_apkpath[0] != '!') {
444 if (stat(fwdlock_apkpath, &s) == 0) {
445 codesize += stat_size(&s);
446 }
447 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448 /* count the cached dexfile as code */
449 if (!create_cache_path(path, apkpath)) {
450 if (stat(path, &s) == 0) {
451 codesize += stat_size(&s);
452 }
453 }
454
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700455 /* compute asec size if it is given
456 */
457 if (asecpath != NULL && asecpath[0] != '!') {
458 if (stat(asecpath, &s) == 0) {
459 asecsize += stat_size(&s);
460 }
461 }
462
Kenny Root86c95842011-03-31 13:16:12 -0700463 if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, 0)) {
Kenny Root35ab3ad2011-02-02 16:42:14 -0800464 goto done;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465 }
466
467 d = opendir(path);
468 if (d == NULL) {
469 goto done;
470 }
471 dfd = dirfd(d);
472
Kenny Root86c95842011-03-31 13:16:12 -0700473 /* most stuff in the pkgdir is data, except for the "cache"
474 * directory and below, which is cache, and the "lib" directory
475 * and below, which is code...
476 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800477 while ((de = readdir(d))) {
478 const char *name = de->d_name;
479
480 if (de->d_type == DT_DIR) {
481 int subfd;
482 /* always skip "." and ".." */
483 if (name[0] == '.') {
484 if (name[1] == 0) continue;
485 if ((name[1] == '.') && (name[2] == 0)) continue;
486 }
487 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
488 if (subfd >= 0) {
Kenny Root3e319a92010-09-07 13:58:28 -0700489 int64_t size = calculate_dir_size(subfd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490 if (!strcmp(name,"lib")) {
491 codesize += size;
492 } else if(!strcmp(name,"cache")) {
493 cachesize += size;
494 } else {
495 datasize += size;
496 }
497 }
498 } else {
499 if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
500 datasize += stat_size(&s);
501 }
502 }
503 }
504 closedir(d);
505done:
506 *_codesize = codesize;
507 *_datasize = datasize;
508 *_cachesize = cachesize;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700509 *_asecsize = asecsize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800510 return 0;
511}
512
513
514/* a simpler version of dexOptGenerateCacheFileName() */
515int create_cache_path(char path[PKG_PATH_MAX], const char *src)
516{
517 char *tmp;
518 int srclen;
519 int dstlen;
520
521 srclen = strlen(src);
522
523 /* demand that we are an absolute path */
524 if ((src == 0) || (src[0] != '/') || strstr(src,"..")) {
525 return -1;
526 }
527
528 if (srclen > PKG_PATH_MAX) { // XXX: PKG_NAME_MAX?
529 return -1;
530 }
531
532 dstlen = srclen + strlen(DALVIK_CACHE_PREFIX) +
533 strlen(DALVIK_CACHE_POSTFIX) + 1;
534
535 if (dstlen > PKG_PATH_MAX) {
536 return -1;
537 }
538
539 sprintf(path,"%s%s%s",
540 DALVIK_CACHE_PREFIX,
541 src + 1, /* skip the leading / */
542 DALVIK_CACHE_POSTFIX);
543
544 for(tmp = path + strlen(DALVIK_CACHE_PREFIX); *tmp; tmp++) {
545 if (*tmp == '/') {
546 *tmp = '@';
547 }
548 }
549
550 return 0;
551}
552
553static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name,
554 const char* dexopt_flags)
555{
556 static const char* DEX_OPT_BIN = "/system/bin/dexopt";
557 static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
558 char zip_num[MAX_INT_LEN];
559 char odex_num[MAX_INT_LEN];
560
561 sprintf(zip_num, "%d", zip_fd);
562 sprintf(odex_num, "%d", odex_fd);
563
564 execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name,
565 dexopt_flags, (char*) NULL);
Steve Block3762c312012-01-06 19:20:56 +0000566 ALOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567}
568
569static int wait_dexopt(pid_t pid, const char* apk_path)
570{
571 int status;
572 pid_t got_pid;
573
574 /*
575 * Wait for the optimization process to finish.
576 */
577 while (1) {
578 got_pid = waitpid(pid, &status, 0);
579 if (got_pid == -1 && errno == EINTR) {
580 printf("waitpid interrupted, retrying\n");
581 } else {
582 break;
583 }
584 }
585 if (got_pid != pid) {
Steve Block8564c8d2012-01-05 23:22:43 +0000586 ALOGW("waitpid failed: wanted %d, got %d: %s\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800587 (int) pid, (int) got_pid, strerror(errno));
588 return 1;
589 }
590
591 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100592 ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 return 0;
594 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000595 ALOGW("DexInv: --- END '%s' --- status=0x%04x, process failed\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 apk_path, status);
597 return status; /* always nonzero */
598 }
599}
600
601int dexopt(const char *apk_path, uid_t uid, int is_public)
602{
603 struct utimbuf ut;
604 struct stat apk_stat, dex_stat;
605 char dex_path[PKG_PATH_MAX];
606 char dexopt_flags[PROPERTY_VALUE_MAX];
607 char *end;
608 int res, zip_fd=-1, odex_fd=-1;
609
610 /* Before anything else: is there a .odex file? If so, we have
611 * pre-optimized the apk and there is nothing to do here.
612 */
613 if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
614 return -1;
615 }
616
617 /* platform-specific flags affecting optimization and verification */
618 property_get("dalvik.vm.dexopt-flags", dexopt_flags, "");
619
620 strcpy(dex_path, apk_path);
621 end = strrchr(dex_path, '.');
622 if (end != NULL) {
623 strcpy(end, ".odex");
624 if (stat(dex_path, &dex_stat) == 0) {
625 return 0;
626 }
627 }
628
629 if (create_cache_path(dex_path, apk_path)) {
630 return -1;
631 }
632
633 memset(&apk_stat, 0, sizeof(apk_stat));
634 stat(apk_path, &apk_stat);
635
636 zip_fd = open(apk_path, O_RDONLY, 0);
637 if (zip_fd < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000638 ALOGE("dexopt cannot open '%s' for input\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 return -1;
640 }
641
642 unlink(dex_path);
643 odex_fd = open(dex_path, O_RDWR | O_CREAT | O_EXCL, 0644);
644 if (odex_fd < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000645 ALOGE("dexopt cannot open '%s' for output\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800646 goto fail;
647 }
648 if (fchown(odex_fd, AID_SYSTEM, uid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000649 ALOGE("dexopt cannot chown '%s'\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 goto fail;
651 }
652 if (fchmod(odex_fd,
653 S_IRUSR|S_IWUSR|S_IRGRP |
654 (is_public ? S_IROTH : 0)) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000655 ALOGE("dexopt cannot chmod '%s'\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800656 goto fail;
657 }
658
Steve Block71f2cf12011-10-20 11:56:00 +0100659 ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660
661 pid_t pid;
662 pid = fork();
663 if (pid == 0) {
664 /* child -- drop privileges before continuing */
665 if (setgid(uid) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000666 ALOGE("setgid(%d) failed during dexopt\n", uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 exit(64);
668 }
669 if (setuid(uid) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000670 ALOGE("setuid(%d) during dexopt\n", uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 exit(65);
672 }
673 if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000674 ALOGE("flock(%s) failed: %s\n", dex_path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800675 exit(66);
676 }
677
678 run_dexopt(zip_fd, odex_fd, apk_path, dexopt_flags);
679 exit(67); /* only get here on exec failure */
680 } else {
681 res = wait_dexopt(pid, apk_path);
682 if (res != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000683 ALOGE("dexopt failed on '%s' res = %d\n", dex_path, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800684 goto fail;
685 }
686 }
687
688 ut.actime = apk_stat.st_atime;
689 ut.modtime = apk_stat.st_mtime;
690 utime(dex_path, &ut);
691
692 close(odex_fd);
693 close(zip_fd);
694 return 0;
695
696fail:
697 if (odex_fd >= 0) {
698 close(odex_fd);
699 unlink(dex_path);
700 }
701 if (zip_fd >= 0) {
702 close(zip_fd);
703 }
704 return -1;
705}
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800706
Dianne Hackbornc1552392010-03-03 16:19:01 -0800707void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid,
708 struct stat* statbuf)
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800709{
710 while (path[basepos] != 0) {
711 if (path[basepos] == '/') {
712 path[basepos] = 0;
Dianne Hackbornc1552392010-03-03 16:19:01 -0800713 if (lstat(path, statbuf) < 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100714 ALOGV("Making directory: %s\n", path);
Dianne Hackbornc1552392010-03-03 16:19:01 -0800715 if (mkdir(path, mode) == 0) {
716 chown(path, uid, gid);
717 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000718 ALOGW("Unable to make directory %s: %s\n", path, strerror(errno));
Dianne Hackbornc1552392010-03-03 16:19:01 -0800719 }
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800720 }
721 path[basepos] = '/';
722 basepos++;
723 }
724 basepos++;
725 }
726}
727
Dianne Hackbornc1552392010-03-03 16:19:01 -0800728int movefileordir(char* srcpath, char* dstpath, int dstbasepos,
729 int dstuid, int dstgid, struct stat* statbuf)
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800730{
731 DIR *d;
732 struct dirent *de;
733 int res;
734
735 int srcend = strlen(srcpath);
736 int dstend = strlen(dstpath);
737
738 if (lstat(srcpath, statbuf) < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000739 ALOGW("Unable to stat %s: %s\n", srcpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800740 return 1;
741 }
742
743 if ((statbuf->st_mode&S_IFDIR) == 0) {
Dianne Hackbornc1552392010-03-03 16:19:01 -0800744 mkinnerdirs(dstpath, dstbasepos, S_IRWXU|S_IRWXG|S_IXOTH,
745 dstuid, dstgid, statbuf);
Steve Block71f2cf12011-10-20 11:56:00 +0100746 ALOGV("Renaming %s to %s (uid %d)\n", srcpath, dstpath, dstuid);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800747 if (rename(srcpath, dstpath) >= 0) {
748 if (chown(dstpath, dstuid, dstgid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000749 ALOGE("cannot chown %s: %s\n", dstpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800750 unlink(dstpath);
751 return 1;
752 }
753 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000754 ALOGW("Unable to rename %s to %s: %s\n",
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800755 srcpath, dstpath, strerror(errno));
756 return 1;
757 }
758 return 0;
759 }
760
761 d = opendir(srcpath);
762 if (d == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000763 ALOGW("Unable to opendir %s: %s\n", srcpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800764 return 1;
765 }
766
767 res = 0;
768
769 while ((de = readdir(d))) {
770 const char *name = de->d_name;
771 /* always skip "." and ".." */
772 if (name[0] == '.') {
773 if (name[1] == 0) continue;
774 if ((name[1] == '.') && (name[2] == 0)) continue;
775 }
776
777 if ((srcend+strlen(name)) >= (PKG_PATH_MAX-2)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000778 ALOGW("Source path too long; skipping: %s/%s\n", srcpath, name);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800779 continue;
780 }
781
782 if ((dstend+strlen(name)) >= (PKG_PATH_MAX-2)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000783 ALOGW("Destination path too long; skipping: %s/%s\n", dstpath, name);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800784 continue;
785 }
786
787 srcpath[srcend] = dstpath[dstend] = '/';
788 strcpy(srcpath+srcend+1, name);
789 strcpy(dstpath+dstend+1, name);
790
Dianne Hackbornc1552392010-03-03 16:19:01 -0800791 if (movefileordir(srcpath, dstpath, dstbasepos, dstuid, dstgid, statbuf) != 0) {
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800792 res = 1;
793 }
794
795 // Note: we will be leaving empty directories behind in srcpath,
796 // but that is okay, the package manager will be erasing all of the
797 // data associated with .apks that disappear.
798
799 srcpath[srcend] = dstpath[dstend] = 0;
800 }
801
802 closedir(d);
803 return res;
804}
805
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800806int movefiles()
807{
808 DIR *d;
809 int dfd, subfd;
810 struct dirent *de;
811 struct stat s;
812 char buf[PKG_PATH_MAX+1];
813 int bufp, bufe, bufi, readlen;
814
815 char srcpkg[PKG_NAME_MAX];
816 char dstpkg[PKG_NAME_MAX];
817 char srcpath[PKG_PATH_MAX];
818 char dstpath[PKG_PATH_MAX];
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800819 int dstuid=-1, dstgid=-1;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800820 int hasspace;
821
822 d = opendir(UPDATE_COMMANDS_DIR_PREFIX);
823 if (d == NULL) {
824 goto done;
825 }
826 dfd = dirfd(d);
827
828 /* Iterate through all files in the directory, executing the
829 * file movements requested there-in.
830 */
831 while ((de = readdir(d))) {
832 const char *name = de->d_name;
833
834 if (de->d_type == DT_DIR) {
835 continue;
836 } else {
837 subfd = openat(dfd, name, O_RDONLY);
838 if (subfd < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000839 ALOGW("Unable to open update commands at %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800840 UPDATE_COMMANDS_DIR_PREFIX, name);
841 continue;
842 }
843
844 bufp = 0;
845 bufe = 0;
846 buf[PKG_PATH_MAX] = 0;
847 srcpkg[0] = dstpkg[0] = 0;
848 while (1) {
849 bufi = bufp;
850 while (bufi < bufe && buf[bufi] != '\n') {
851 bufi++;
852 }
853 if (bufi < bufe) {
854 buf[bufi] = 0;
Steve Block71f2cf12011-10-20 11:56:00 +0100855 ALOGV("Processing line: %s\n", buf+bufp);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800856 hasspace = 0;
857 while (bufp < bufi && isspace(buf[bufp])) {
858 hasspace = 1;
859 bufp++;
860 }
861 if (buf[bufp] == '#' || bufp == bufi) {
862 // skip comments and empty lines.
863 } else if (hasspace) {
864 if (dstpkg[0] == 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000865 ALOGW("Path before package line in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800866 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
867 } else if (srcpkg[0] == 0) {
868 // Skip -- source package no longer exists.
869 } else {
Steve Block71f2cf12011-10-20 11:56:00 +0100870 ALOGV("Move file: %s (from %s to %s)\n", buf+bufp, srcpkg, dstpkg);
Kenny Root86c95842011-03-31 13:16:12 -0700871 if (!create_move_path(srcpath, srcpkg, buf+bufp, 0) &&
872 !create_move_path(dstpath, dstpkg, buf+bufp, 0)) {
Dianne Hackbornc1552392010-03-03 16:19:01 -0800873 movefileordir(srcpath, dstpath,
874 strlen(dstpath)-strlen(buf+bufp),
875 dstuid, dstgid, &s);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800876 }
877 }
878 } else {
879 char* div = strchr(buf+bufp, ':');
880 if (div == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000881 ALOGW("Bad package spec in %s%s; no ':' sep: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800882 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
883 } else {
884 *div = 0;
885 div++;
886 if (strlen(buf+bufp) < PKG_NAME_MAX) {
887 strcpy(dstpkg, buf+bufp);
888 } else {
889 srcpkg[0] = dstpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000890 ALOGW("Package name too long in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800891 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
892 }
893 if (strlen(div) < PKG_NAME_MAX) {
894 strcpy(srcpkg, div);
895 } else {
896 srcpkg[0] = dstpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000897 ALOGW("Package name too long in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800898 UPDATE_COMMANDS_DIR_PREFIX, name, div);
899 }
900 if (srcpkg[0] != 0) {
Kenny Root86c95842011-03-31 13:16:12 -0700901 if (!create_pkg_path(srcpath, srcpkg, PKG_DIR_POSTFIX, 0)) {
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800902 if (lstat(srcpath, &s) < 0) {
903 // Package no longer exists -- skip.
904 srcpkg[0] = 0;
905 }
906 } else {
907 srcpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000908 ALOGW("Can't create path %s in %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800909 div, UPDATE_COMMANDS_DIR_PREFIX, name);
910 }
911 if (srcpkg[0] != 0) {
Kenny Root86c95842011-03-31 13:16:12 -0700912 if (!create_pkg_path(dstpath, dstpkg, PKG_DIR_POSTFIX, 0)) {
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800913 if (lstat(dstpath, &s) == 0) {
914 dstuid = s.st_uid;
915 dstgid = s.st_gid;
916 } else {
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800917 // Destination package doesn't
918 // exist... due to original-package,
919 // this is normal, so don't be
920 // noisy about it.
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800921 srcpkg[0] = 0;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800922 }
923 } else {
924 srcpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000925 ALOGW("Can't create path %s in %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800926 div, UPDATE_COMMANDS_DIR_PREFIX, name);
927 }
928 }
Steve Block71f2cf12011-10-20 11:56:00 +0100929 ALOGV("Transfering from %s to %s: uid=%d\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800930 srcpkg, dstpkg, dstuid);
931 }
932 }
933 }
934 bufp = bufi+1;
935 } else {
936 if (bufp == 0) {
937 if (bufp < bufe) {
Steve Block8564c8d2012-01-05 23:22:43 +0000938 ALOGW("Line too long in %s%s, skipping: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800939 UPDATE_COMMANDS_DIR_PREFIX, name, buf);
940 }
941 } else if (bufp < bufe) {
942 memcpy(buf, buf+bufp, bufe-bufp);
943 bufe -= bufp;
944 bufp = 0;
945 }
946 readlen = read(subfd, buf+bufe, PKG_PATH_MAX-bufe);
947 if (readlen < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000948 ALOGW("Failure reading update commands in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800949 UPDATE_COMMANDS_DIR_PREFIX, name, strerror(errno));
950 break;
951 } else if (readlen == 0) {
952 break;
953 }
954 bufe += readlen;
955 buf[bufe] = 0;
Steve Block71f2cf12011-10-20 11:56:00 +0100956 ALOGV("Read buf: %s\n", buf);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800957 }
958 }
959 close(subfd);
960 }
961 }
962 closedir(d);
963done:
964 return 0;
965}
Kenny Root6a6b0072010-10-07 16:46:10 -0700966
967int linklib(const char* dataDir, const char* asecLibDir)
968{
969 char libdir[PKG_PATH_MAX];
970 struct stat s, libStat;
971 int rc = 0;
972
973 const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
974 if (libdirLen >= PKG_PATH_MAX) {
Steve Block3762c312012-01-06 19:20:56 +0000975 ALOGE("library dir len too large");
Kenny Root0332d1c2010-10-21 16:14:06 -0700976 return -1;
Kenny Root6a6b0072010-10-07 16:46:10 -0700977 }
978
979 if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
Steve Block3762c312012-01-06 19:20:56 +0000980 ALOGE("library dir not written successfully: %s\n", strerror(errno));
Kenny Root0332d1c2010-10-21 16:14:06 -0700981 return -1;
Kenny Root6a6b0072010-10-07 16:46:10 -0700982 }
983
984 if (stat(dataDir, &s) < 0) return -1;
985
986 if (chown(dataDir, 0, 0) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000987 ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700988 return -1;
989 }
990
991 if (chmod(dataDir, 0700) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000992 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700993 rc = -1;
994 goto out;
995 }
996
997 if (lstat(libdir, &libStat) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000998 ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700999 rc = -1;
1000 goto out;
1001 }
1002
1003 if (S_ISDIR(libStat.st_mode)) {
1004 if (delete_dir_contents(libdir, 1, 0) < 0) {
1005 rc = -1;
1006 goto out;
1007 }
1008 } else if (S_ISLNK(libStat.st_mode)) {
1009 if (unlink(libdir) < 0) {
1010 rc = -1;
1011 goto out;
1012 }
1013 }
1014
1015 if (symlink(asecLibDir, libdir) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001016 ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libdir, asecLibDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001017 rc = -errno;
1018 goto out;
1019 }
1020
1021 if (lchown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001022 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001023 unlink(libdir);
1024 rc = -errno;
1025 goto out;
1026 }
1027
1028out:
1029 if (chmod(dataDir, s.st_mode) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001030 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Dianne Hackbornd0c5f512012-06-07 16:53:59 -07001031 rc = -errno;
Kenny Root6a6b0072010-10-07 16:46:10 -07001032 }
1033
1034 if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001035 ALOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001036 return -errno;
1037 }
1038
1039 return rc;
1040}
1041
1042int unlinklib(const char* dataDir)
1043{
1044 char libdir[PKG_PATH_MAX];
1045 struct stat s, libStat;
1046 int rc = 0;
1047
1048 const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
1049 if (libdirLen >= PKG_PATH_MAX) {
1050 return -1;
1051 }
1052
1053 if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
Steve Block3762c312012-01-06 19:20:56 +00001054 ALOGE("library dir not written successfully: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001055 return -1;
1056 }
1057
1058 if (stat(dataDir, &s) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001059 ALOGE("couldn't state data dir");
Kenny Root6a6b0072010-10-07 16:46:10 -07001060 return -1;
1061 }
1062
1063 if (chown(dataDir, 0, 0) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001064 ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001065 return -1;
1066 }
1067
1068 if (chmod(dataDir, 0700) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001069 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001070 rc = -1;
1071 goto out;
1072 }
1073
1074 if (lstat(libdir, &libStat) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001075 ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001076 rc = -1;
1077 goto out;
1078 }
1079
1080 if (S_ISDIR(libStat.st_mode)) {
1081 if (delete_dir_contents(libdir, 1, 0) < 0) {
1082 rc = -1;
1083 goto out;
1084 }
1085 } else if (S_ISLNK(libStat.st_mode)) {
1086 if (unlink(libdir) < 0) {
1087 rc = -1;
1088 goto out;
1089 }
1090 }
1091
1092 if (mkdir(libdir, 0755) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001093 ALOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001094 rc = -errno;
1095 goto out;
1096 }
1097
1098 if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001099 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001100 unlink(libdir);
1101 rc = -errno;
1102 goto out;
1103 }
1104
1105out:
1106 if (chmod(dataDir, s.st_mode) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001107 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Dianne Hackbornd0c5f512012-06-07 16:53:59 -07001108 rc = -1;
Kenny Root6a6b0072010-10-07 16:46:10 -07001109 }
1110
1111 if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001112 ALOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001113 return -1;
1114 }
1115
1116 return rc;
1117}