blob: a50915630517535c9ece33d201702e3abb94c676 [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
Kenny Root86c95842011-03-31 13:16:12 -070020/* Directory records that are used in execution of commands. */
21dir_rec_t android_data_dir;
22dir_rec_t android_asec_dir;
23dir_rec_t android_app_dir;
24dir_rec_t android_app_private_dir;
25dir_rec_array_t android_system_dirs;
26
Kenny Root35ab3ad2011-02-02 16:42:14 -080027int install(const char *pkgname, uid_t uid, gid_t gid)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028{
29 char pkgdir[PKG_PATH_MAX];
30 char libdir[PKG_PATH_MAX];
31
32 if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
Steve Block3762c312012-01-06 19:20:56 +000033 ALOGE("invalid uid/gid: %d %d\n", uid, gid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035 }
Oscar Montemayora8529f62009-11-18 10:14:20 -080036
Kenny Root86c95842011-03-31 13:16:12 -070037 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
Steve Block3762c312012-01-06 19:20:56 +000038 ALOGE("cannot create package path\n");
Kenny Root35ab3ad2011-02-02 16:42:14 -080039 return -1;
Kenny Root86c95842011-03-31 13:16:12 -070040 }
41
42 if (create_pkg_path(libdir, pkgname, PKG_LIB_POSTFIX, 0)) {
Steve Block3762c312012-01-06 19:20:56 +000043 ALOGE("cannot create package lib path\n");
Kenny Root35ab3ad2011-02-02 16:42:14 -080044 return -1;
Kenny Root86c95842011-03-31 13:16:12 -070045 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046
David 'Digit' Turner0dd50e62010-02-09 19:02:38 -080047 if (mkdir(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000048 ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049 return -errno;
50 }
Nick Kralevichf68327e2011-04-14 16:20:03 -070051 if (chmod(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000052 ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
Nick Kralevichf68327e2011-04-14 16:20:03 -070053 unlink(pkgdir);
54 return -errno;
55 }
Kenny Root4503cf62012-06-14 13:05:18 -070056
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057 if (mkdir(libdir, 0755) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000058 ALOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059 unlink(pkgdir);
60 return -errno;
61 }
Nick Kralevichf68327e2011-04-14 16:20:03 -070062 if (chmod(libdir, 0755) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000063 ALOGE("cannot chmod dir '%s': %s\n", libdir, strerror(errno));
Nick Kralevichf68327e2011-04-14 16:20:03 -070064 unlink(libdir);
65 unlink(pkgdir);
66 return -errno;
67 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068 if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000069 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070 unlink(libdir);
71 unlink(pkgdir);
72 return -errno;
73 }
Kenny Root4503cf62012-06-14 13:05:18 -070074
75 if (chown(pkgdir, uid, gid) < 0) {
76 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
77 unlink(libdir);
78 unlink(pkgdir);
79 return -errno;
80 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081 return 0;
82}
83
Amith Yamasani0b285492011-04-14 17:35:23 -070084int uninstall(const char *pkgname, uid_t persona)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085{
86 char pkgdir[PKG_PATH_MAX];
87
Amith Yamasani0b285492011-04-14 17:35:23 -070088 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
Kenny Root35ab3ad2011-02-02 16:42:14 -080089 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090
Amith Yamasani0b285492011-04-14 17:35:23 -070091 /* delete contents AND directory, no exceptions */
92 return delete_dir_contents(pkgdir, 1, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093}
94
Kenny Root35ab3ad2011-02-02 16:42:14 -080095int renamepkg(const char *oldpkgname, const char *newpkgname)
Dianne Hackbornb858dfd2010-02-02 10:49:14 -080096{
97 char oldpkgdir[PKG_PATH_MAX];
98 char newpkgdir[PKG_PATH_MAX];
99
Kenny Root86c95842011-03-31 13:16:12 -0700100 if (create_pkg_path(oldpkgdir, oldpkgname, PKG_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800101 return -1;
Kenny Root86c95842011-03-31 13:16:12 -0700102 if (create_pkg_path(newpkgdir, newpkgname, PKG_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800103 return -1;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800104
105 if (rename(oldpkgdir, newpkgdir) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000106 ALOGE("cannot rename dir '%s' to '%s': %s\n", oldpkgdir, newpkgdir, strerror(errno));
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800107 return -errno;
108 }
109 return 0;
110}
111
Dianne Hackbornd0c5f512012-06-07 16:53:59 -0700112int fix_uid(const char *pkgname, uid_t uid, gid_t gid)
113{
114 char pkgdir[PKG_PATH_MAX];
115 struct stat s;
116 int rc = 0;
117
118 if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
119 ALOGE("invalid uid/gid: %d %d\n", uid, gid);
120 return -1;
121 }
122
123 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
124 ALOGE("cannot create package path\n");
125 return -1;
126 }
127
128 if (stat(pkgdir, &s) < 0) return -1;
129
130 if (s.st_uid != 0 || s.st_gid != 0) {
131 ALOGE("fixing uid of non-root pkg: %s %d %d\n", pkgdir, s.st_uid, s.st_gid);
132 return -1;
133 }
134
135 if (chmod(pkgdir, 0751) < 0) {
136 ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
137 unlink(pkgdir);
138 return -errno;
139 }
140 if (chown(pkgdir, uid, gid) < 0) {
141 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
142 unlink(pkgdir);
143 return -errno;
144 }
145
146 return 0;
147}
148
Amith Yamasani0b285492011-04-14 17:35:23 -0700149int delete_user_data(const char *pkgname, uid_t persona)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150{
151 char pkgdir[PKG_PATH_MAX];
152
Amith Yamasani0b285492011-04-14 17:35:23 -0700153 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800154 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155
Amith Yamasani0b285492011-04-14 17:35:23 -0700156 /* delete contents, excluding "lib", but not the directory itself */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 return delete_dir_contents(pkgdir, 0, "lib");
158}
159
Amith Yamasani0b285492011-04-14 17:35:23 -0700160int make_user_data(const char *pkgname, uid_t uid, uid_t persona)
161{
162 char pkgdir[PKG_PATH_MAX];
163 char real_libdir[PKG_PATH_MAX];
164
165 // Create the data dir for the package
166 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona)) {
167 return -1;
168 }
169 if (mkdir(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000170 ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
Amith Yamasani0b285492011-04-14 17:35:23 -0700171 return -errno;
172 }
173 if (chown(pkgdir, uid, uid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000174 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
Amith Yamasani0b285492011-04-14 17:35:23 -0700175 unlink(pkgdir);
176 return -errno;
177 }
178 return 0;
179}
180
181int delete_persona(uid_t persona)
182{
183 char pkgdir[PKG_PATH_MAX];
184
185 if (create_persona_path(pkgdir, persona))
186 return -1;
187
188 return delete_dir_contents(pkgdir, 1, NULL);
189}
190
Amith Yamasani742a6712011-05-04 14:49:28 -0700191int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy)
192{
193 char src_data_dir[PKG_PATH_MAX];
194 char pkg_path[PKG_PATH_MAX];
195 DIR *d;
196 struct dirent *de;
197 struct stat s;
198 uid_t uid;
199
200 if (create_persona_path(src_data_dir, src_persona)) {
201 return -1;
202 }
203
204 d = opendir(src_data_dir);
205 if (d != NULL) {
206 while ((de = readdir(d))) {
207 const char *name = de->d_name;
208
209 if (de->d_type == DT_DIR) {
210 int subfd;
211 /* always skip "." and ".." */
212 if (name[0] == '.') {
213 if (name[1] == 0) continue;
214 if ((name[1] == '.') && (name[2] == 0)) continue;
215 }
216 /* Create the full path to the package's data dir */
217 create_pkg_path(pkg_path, name, PKG_DIR_POSTFIX, src_persona);
218 /* Get the file stat */
219 if (stat(pkg_path, &s) < 0) continue;
220 /* Get the uid of the package */
221 ALOGI("Adding datadir for uid = %d\n", s.st_uid);
222 uid = (uid_t) s.st_uid % PER_USER_RANGE;
223 /* Create the directory for the target */
224 make_user_data(name, uid + target_persona * PER_USER_RANGE,
225 target_persona);
226 }
227 }
228 closedir(d);
229 }
230 return 0;
231}
232
Kenny Root35ab3ad2011-02-02 16:42:14 -0800233int delete_cache(const char *pkgname)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234{
235 char cachedir[PKG_PATH_MAX];
236
Kenny Root86c95842011-03-31 13:16:12 -0700237 if (create_pkg_path(cachedir, pkgname, CACHE_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800238 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239
240 /* delete contents, not the directory, no exceptions */
241 return delete_dir_contents(cachedir, 0, 0);
242}
243
Kenny Root3e319a92010-09-07 13:58:28 -0700244static int64_t disk_free()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245{
246 struct statfs sfs;
Kenny Root86c95842011-03-31 13:16:12 -0700247 if (statfs(android_data_dir.path, &sfs) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 return sfs.f_bavail * sfs.f_bsize;
249 } else {
Steve Block3762c312012-01-06 19:20:56 +0000250 ALOGE("Couldn't statfs %s: %s\n", android_data_dir.path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251 return -1;
252 }
253}
254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255/* Try to ensure free_size bytes of storage are available.
256 * Returns 0 on success.
257 * This is rather simple-minded because doing a full LRU would
258 * be potentially memory-intensive, and without atime it would
259 * also require that apps constantly modify file metadata even
260 * when just reading from the cache, which is pretty awful.
261 */
Kenny Root3e319a92010-09-07 13:58:28 -0700262int free_cache(int64_t free_size)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263{
264 const char *name;
265 int dfd, subfd;
266 DIR *d;
267 struct dirent *de;
Kenny Root3e319a92010-09-07 13:58:28 -0700268 int64_t avail;
Kenny Rootad757e92011-11-29 15:54:55 -0800269 char datadir[PKG_PATH_MAX];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270
271 avail = disk_free();
272 if (avail < 0) return -1;
273
Steve Block6215d3f2012-01-04 20:05:49 +0000274 ALOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 if (avail >= free_size) return 0;
276
Kenny Rootad757e92011-11-29 15:54:55 -0800277 if (create_persona_path(datadir, 0)) {
Steve Block3762c312012-01-06 19:20:56 +0000278 ALOGE("couldn't get directory for persona 0");
Kenny Rootad757e92011-11-29 15:54:55 -0800279 return -1;
280 }
281
282 d = opendir(datadir);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283 if (d == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000284 ALOGE("cannot open %s: %s\n", datadir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285 return -1;
286 }
287 dfd = dirfd(d);
288
289 while ((de = readdir(d))) {
290 if (de->d_type != DT_DIR) continue;
291 name = de->d_name;
292
Oscar Montemayora8529f62009-11-18 10:14:20 -0800293 /* always skip "." and ".." */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294 if (name[0] == '.') {
295 if (name[1] == 0) continue;
296 if ((name[1] == '.') && (name[2] == 0)) continue;
297 }
298
299 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
300 if (subfd < 0) continue;
301
302 delete_dir_contents_fd(subfd, "cache");
303 close(subfd);
304
305 avail = disk_free();
306 if (avail >= free_size) {
307 closedir(d);
308 return 0;
309 }
310 }
311 closedir(d);
Oscar Montemayora8529f62009-11-18 10:14:20 -0800312
313 /* Fail case - not possible to free space */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800314 return -1;
315}
316
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317int move_dex(const char *src, const char *dst)
318{
319 char src_dex[PKG_PATH_MAX];
320 char dst_dex[PKG_PATH_MAX];
321
Kenny Root86c95842011-03-31 13:16:12 -0700322 if (validate_apk_path(src)) return -1;
323 if (validate_apk_path(dst)) return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324
325 if (create_cache_path(src_dex, src)) return -1;
326 if (create_cache_path(dst_dex, dst)) return -1;
327
Steve Block71f2cf12011-10-20 11:56:00 +0100328 ALOGV("move %s -> %s\n", src_dex, dst_dex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 if (rename(src_dex, dst_dex) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000330 ALOGE("Couldn't move %s: %s\n", src_dex, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331 return -1;
332 } else {
333 return 0;
334 }
335}
336
337int rm_dex(const char *path)
338{
339 char dex_path[PKG_PATH_MAX];
340
Kenny Root86c95842011-03-31 13:16:12 -0700341 if (validate_apk_path(path)) return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 if (create_cache_path(dex_path, path)) return -1;
343
Steve Block71f2cf12011-10-20 11:56:00 +0100344 ALOGV("unlink %s\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800345 if (unlink(dex_path) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000346 ALOGE("Couldn't unlink %s: %s\n", dex_path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800347 return -1;
348 } else {
349 return 0;
350 }
351}
352
353int protect(char *pkgname, gid_t gid)
354{
355 struct stat s;
356 char pkgpath[PKG_PATH_MAX];
357
358 if (gid < AID_SYSTEM) return -1;
359
Kenny Root86c95842011-03-31 13:16:12 -0700360 if (create_pkg_path_in_dir(pkgpath, &android_app_private_dir, pkgname, ".apk"))
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361 return -1;
362
363 if (stat(pkgpath, &s) < 0) return -1;
364
365 if (chown(pkgpath, s.st_uid, gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000366 ALOGE("failed to chgrp '%s': %s\n", pkgpath, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 return -1;
368 }
369
370 if (chmod(pkgpath, S_IRUSR|S_IWUSR|S_IRGRP) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000371 ALOGE("failed to chmod '%s': %s\n", pkgpath, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800372 return -1;
373 }
374
375 return 0;
376}
377
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378int get_size(const char *pkgname, const char *apkpath,
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700379 const char *fwdlock_apkpath, const char *asecpath,
380 int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize,
381 int64_t* _asecsize)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382{
383 DIR *d;
384 int dfd;
385 struct dirent *de;
386 struct stat s;
387 char path[PKG_PATH_MAX];
388
Kenny Root3e319a92010-09-07 13:58:28 -0700389 int64_t codesize = 0;
390 int64_t datasize = 0;
391 int64_t cachesize = 0;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700392 int64_t asecsize = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393
394 /* count the source apk as code -- but only if it's not
Suchi Amalapurapu8a9ab242010-03-11 16:49:16 -0800395 * on the /system partition and its not on the sdcard.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 */
Kenny Root86c95842011-03-31 13:16:12 -0700397 if (validate_system_app_path(apkpath) &&
398 strncmp(apkpath, android_asec_dir.path, android_asec_dir.len) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 if (stat(apkpath, &s) == 0) {
400 codesize += stat_size(&s);
401 }
402 }
403 /* count the forward locked apk as code if it is given
404 */
405 if (fwdlock_apkpath != NULL && fwdlock_apkpath[0] != '!') {
406 if (stat(fwdlock_apkpath, &s) == 0) {
407 codesize += stat_size(&s);
408 }
409 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410 /* count the cached dexfile as code */
411 if (!create_cache_path(path, apkpath)) {
412 if (stat(path, &s) == 0) {
413 codesize += stat_size(&s);
414 }
415 }
416
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700417 /* compute asec size if it is given
418 */
419 if (asecpath != NULL && asecpath[0] != '!') {
420 if (stat(asecpath, &s) == 0) {
421 asecsize += stat_size(&s);
422 }
423 }
424
Kenny Root86c95842011-03-31 13:16:12 -0700425 if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, 0)) {
Kenny Root35ab3ad2011-02-02 16:42:14 -0800426 goto done;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427 }
428
429 d = opendir(path);
430 if (d == NULL) {
431 goto done;
432 }
433 dfd = dirfd(d);
434
Kenny Root86c95842011-03-31 13:16:12 -0700435 /* most stuff in the pkgdir is data, except for the "cache"
436 * directory and below, which is cache, and the "lib" directory
437 * and below, which is code...
438 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439 while ((de = readdir(d))) {
440 const char *name = de->d_name;
441
442 if (de->d_type == DT_DIR) {
443 int subfd;
444 /* always skip "." and ".." */
445 if (name[0] == '.') {
446 if (name[1] == 0) continue;
447 if ((name[1] == '.') && (name[2] == 0)) continue;
448 }
449 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
450 if (subfd >= 0) {
Kenny Root3e319a92010-09-07 13:58:28 -0700451 int64_t size = calculate_dir_size(subfd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 if (!strcmp(name,"lib")) {
453 codesize += size;
454 } else if(!strcmp(name,"cache")) {
455 cachesize += size;
456 } else {
457 datasize += size;
458 }
459 }
460 } else {
461 if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
462 datasize += stat_size(&s);
463 }
464 }
465 }
466 closedir(d);
467done:
468 *_codesize = codesize;
469 *_datasize = datasize;
470 *_cachesize = cachesize;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700471 *_asecsize = asecsize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 return 0;
473}
474
475
476/* a simpler version of dexOptGenerateCacheFileName() */
477int create_cache_path(char path[PKG_PATH_MAX], const char *src)
478{
479 char *tmp;
480 int srclen;
481 int dstlen;
482
483 srclen = strlen(src);
484
485 /* demand that we are an absolute path */
486 if ((src == 0) || (src[0] != '/') || strstr(src,"..")) {
487 return -1;
488 }
489
490 if (srclen > PKG_PATH_MAX) { // XXX: PKG_NAME_MAX?
491 return -1;
492 }
493
494 dstlen = srclen + strlen(DALVIK_CACHE_PREFIX) +
495 strlen(DALVIK_CACHE_POSTFIX) + 1;
496
497 if (dstlen > PKG_PATH_MAX) {
498 return -1;
499 }
500
501 sprintf(path,"%s%s%s",
502 DALVIK_CACHE_PREFIX,
503 src + 1, /* skip the leading / */
504 DALVIK_CACHE_POSTFIX);
505
506 for(tmp = path + strlen(DALVIK_CACHE_PREFIX); *tmp; tmp++) {
507 if (*tmp == '/') {
508 *tmp = '@';
509 }
510 }
511
512 return 0;
513}
514
515static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name,
516 const char* dexopt_flags)
517{
518 static const char* DEX_OPT_BIN = "/system/bin/dexopt";
519 static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
520 char zip_num[MAX_INT_LEN];
521 char odex_num[MAX_INT_LEN];
522
523 sprintf(zip_num, "%d", zip_fd);
524 sprintf(odex_num, "%d", odex_fd);
525
526 execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name,
527 dexopt_flags, (char*) NULL);
Steve Block3762c312012-01-06 19:20:56 +0000528 ALOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800529}
530
531static int wait_dexopt(pid_t pid, const char* apk_path)
532{
533 int status;
534 pid_t got_pid;
535
536 /*
537 * Wait for the optimization process to finish.
538 */
539 while (1) {
540 got_pid = waitpid(pid, &status, 0);
541 if (got_pid == -1 && errno == EINTR) {
542 printf("waitpid interrupted, retrying\n");
543 } else {
544 break;
545 }
546 }
547 if (got_pid != pid) {
Steve Block8564c8d2012-01-05 23:22:43 +0000548 ALOGW("waitpid failed: wanted %d, got %d: %s\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 (int) pid, (int) got_pid, strerror(errno));
550 return 1;
551 }
552
553 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100554 ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555 return 0;
556 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000557 ALOGW("DexInv: --- END '%s' --- status=0x%04x, process failed\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558 apk_path, status);
559 return status; /* always nonzero */
560 }
561}
562
563int dexopt(const char *apk_path, uid_t uid, int is_public)
564{
565 struct utimbuf ut;
566 struct stat apk_stat, dex_stat;
567 char dex_path[PKG_PATH_MAX];
568 char dexopt_flags[PROPERTY_VALUE_MAX];
569 char *end;
570 int res, zip_fd=-1, odex_fd=-1;
571
572 /* Before anything else: is there a .odex file? If so, we have
573 * pre-optimized the apk and there is nothing to do here.
574 */
575 if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
576 return -1;
577 }
578
579 /* platform-specific flags affecting optimization and verification */
580 property_get("dalvik.vm.dexopt-flags", dexopt_flags, "");
581
582 strcpy(dex_path, apk_path);
583 end = strrchr(dex_path, '.');
584 if (end != NULL) {
585 strcpy(end, ".odex");
586 if (stat(dex_path, &dex_stat) == 0) {
587 return 0;
588 }
589 }
590
591 if (create_cache_path(dex_path, apk_path)) {
592 return -1;
593 }
594
595 memset(&apk_stat, 0, sizeof(apk_stat));
596 stat(apk_path, &apk_stat);
597
598 zip_fd = open(apk_path, O_RDONLY, 0);
599 if (zip_fd < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000600 ALOGE("dexopt cannot open '%s' for input\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800601 return -1;
602 }
603
604 unlink(dex_path);
605 odex_fd = open(dex_path, O_RDWR | O_CREAT | O_EXCL, 0644);
606 if (odex_fd < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000607 ALOGE("dexopt cannot open '%s' for output\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608 goto fail;
609 }
610 if (fchown(odex_fd, AID_SYSTEM, uid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000611 ALOGE("dexopt cannot chown '%s'\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612 goto fail;
613 }
614 if (fchmod(odex_fd,
615 S_IRUSR|S_IWUSR|S_IRGRP |
616 (is_public ? S_IROTH : 0)) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000617 ALOGE("dexopt cannot chmod '%s'\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800618 goto fail;
619 }
620
Steve Block71f2cf12011-10-20 11:56:00 +0100621 ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800622
623 pid_t pid;
624 pid = fork();
625 if (pid == 0) {
626 /* child -- drop privileges before continuing */
627 if (setgid(uid) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000628 ALOGE("setgid(%d) failed during dexopt\n", uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800629 exit(64);
630 }
631 if (setuid(uid) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000632 ALOGE("setuid(%d) during dexopt\n", uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 exit(65);
634 }
635 if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000636 ALOGE("flock(%s) failed: %s\n", dex_path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 exit(66);
638 }
639
640 run_dexopt(zip_fd, odex_fd, apk_path, dexopt_flags);
641 exit(67); /* only get here on exec failure */
642 } else {
643 res = wait_dexopt(pid, apk_path);
644 if (res != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000645 ALOGE("dexopt failed on '%s' res = %d\n", dex_path, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800646 goto fail;
647 }
648 }
649
650 ut.actime = apk_stat.st_atime;
651 ut.modtime = apk_stat.st_mtime;
652 utime(dex_path, &ut);
653
654 close(odex_fd);
655 close(zip_fd);
656 return 0;
657
658fail:
659 if (odex_fd >= 0) {
660 close(odex_fd);
661 unlink(dex_path);
662 }
663 if (zip_fd >= 0) {
664 close(zip_fd);
665 }
666 return -1;
667}
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800668
Dianne Hackbornc1552392010-03-03 16:19:01 -0800669void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid,
670 struct stat* statbuf)
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800671{
672 while (path[basepos] != 0) {
673 if (path[basepos] == '/') {
674 path[basepos] = 0;
Dianne Hackbornc1552392010-03-03 16:19:01 -0800675 if (lstat(path, statbuf) < 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100676 ALOGV("Making directory: %s\n", path);
Dianne Hackbornc1552392010-03-03 16:19:01 -0800677 if (mkdir(path, mode) == 0) {
678 chown(path, uid, gid);
679 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000680 ALOGW("Unable to make directory %s: %s\n", path, strerror(errno));
Dianne Hackbornc1552392010-03-03 16:19:01 -0800681 }
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800682 }
683 path[basepos] = '/';
684 basepos++;
685 }
686 basepos++;
687 }
688}
689
Dianne Hackbornc1552392010-03-03 16:19:01 -0800690int movefileordir(char* srcpath, char* dstpath, int dstbasepos,
691 int dstuid, int dstgid, struct stat* statbuf)
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800692{
693 DIR *d;
694 struct dirent *de;
695 int res;
696
697 int srcend = strlen(srcpath);
698 int dstend = strlen(dstpath);
699
700 if (lstat(srcpath, statbuf) < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000701 ALOGW("Unable to stat %s: %s\n", srcpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800702 return 1;
703 }
704
705 if ((statbuf->st_mode&S_IFDIR) == 0) {
Dianne Hackbornc1552392010-03-03 16:19:01 -0800706 mkinnerdirs(dstpath, dstbasepos, S_IRWXU|S_IRWXG|S_IXOTH,
707 dstuid, dstgid, statbuf);
Steve Block71f2cf12011-10-20 11:56:00 +0100708 ALOGV("Renaming %s to %s (uid %d)\n", srcpath, dstpath, dstuid);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800709 if (rename(srcpath, dstpath) >= 0) {
710 if (chown(dstpath, dstuid, dstgid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000711 ALOGE("cannot chown %s: %s\n", dstpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800712 unlink(dstpath);
713 return 1;
714 }
715 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000716 ALOGW("Unable to rename %s to %s: %s\n",
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800717 srcpath, dstpath, strerror(errno));
718 return 1;
719 }
720 return 0;
721 }
722
723 d = opendir(srcpath);
724 if (d == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000725 ALOGW("Unable to opendir %s: %s\n", srcpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800726 return 1;
727 }
728
729 res = 0;
730
731 while ((de = readdir(d))) {
732 const char *name = de->d_name;
733 /* always skip "." and ".." */
734 if (name[0] == '.') {
735 if (name[1] == 0) continue;
736 if ((name[1] == '.') && (name[2] == 0)) continue;
737 }
738
739 if ((srcend+strlen(name)) >= (PKG_PATH_MAX-2)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000740 ALOGW("Source path too long; skipping: %s/%s\n", srcpath, name);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800741 continue;
742 }
743
744 if ((dstend+strlen(name)) >= (PKG_PATH_MAX-2)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000745 ALOGW("Destination path too long; skipping: %s/%s\n", dstpath, name);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800746 continue;
747 }
748
749 srcpath[srcend] = dstpath[dstend] = '/';
750 strcpy(srcpath+srcend+1, name);
751 strcpy(dstpath+dstend+1, name);
752
Dianne Hackbornc1552392010-03-03 16:19:01 -0800753 if (movefileordir(srcpath, dstpath, dstbasepos, dstuid, dstgid, statbuf) != 0) {
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800754 res = 1;
755 }
756
757 // Note: we will be leaving empty directories behind in srcpath,
758 // but that is okay, the package manager will be erasing all of the
759 // data associated with .apks that disappear.
760
761 srcpath[srcend] = dstpath[dstend] = 0;
762 }
763
764 closedir(d);
765 return res;
766}
767
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800768int movefiles()
769{
770 DIR *d;
771 int dfd, subfd;
772 struct dirent *de;
773 struct stat s;
774 char buf[PKG_PATH_MAX+1];
775 int bufp, bufe, bufi, readlen;
776
777 char srcpkg[PKG_NAME_MAX];
778 char dstpkg[PKG_NAME_MAX];
779 char srcpath[PKG_PATH_MAX];
780 char dstpath[PKG_PATH_MAX];
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800781 int dstuid=-1, dstgid=-1;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800782 int hasspace;
783
784 d = opendir(UPDATE_COMMANDS_DIR_PREFIX);
785 if (d == NULL) {
786 goto done;
787 }
788 dfd = dirfd(d);
789
790 /* Iterate through all files in the directory, executing the
791 * file movements requested there-in.
792 */
793 while ((de = readdir(d))) {
794 const char *name = de->d_name;
795
796 if (de->d_type == DT_DIR) {
797 continue;
798 } else {
799 subfd = openat(dfd, name, O_RDONLY);
800 if (subfd < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000801 ALOGW("Unable to open update commands at %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800802 UPDATE_COMMANDS_DIR_PREFIX, name);
803 continue;
804 }
805
806 bufp = 0;
807 bufe = 0;
808 buf[PKG_PATH_MAX] = 0;
809 srcpkg[0] = dstpkg[0] = 0;
810 while (1) {
811 bufi = bufp;
812 while (bufi < bufe && buf[bufi] != '\n') {
813 bufi++;
814 }
815 if (bufi < bufe) {
816 buf[bufi] = 0;
Steve Block71f2cf12011-10-20 11:56:00 +0100817 ALOGV("Processing line: %s\n", buf+bufp);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800818 hasspace = 0;
819 while (bufp < bufi && isspace(buf[bufp])) {
820 hasspace = 1;
821 bufp++;
822 }
823 if (buf[bufp] == '#' || bufp == bufi) {
824 // skip comments and empty lines.
825 } else if (hasspace) {
826 if (dstpkg[0] == 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000827 ALOGW("Path before package line in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800828 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
829 } else if (srcpkg[0] == 0) {
830 // Skip -- source package no longer exists.
831 } else {
Steve Block71f2cf12011-10-20 11:56:00 +0100832 ALOGV("Move file: %s (from %s to %s)\n", buf+bufp, srcpkg, dstpkg);
Kenny Root86c95842011-03-31 13:16:12 -0700833 if (!create_move_path(srcpath, srcpkg, buf+bufp, 0) &&
834 !create_move_path(dstpath, dstpkg, buf+bufp, 0)) {
Dianne Hackbornc1552392010-03-03 16:19:01 -0800835 movefileordir(srcpath, dstpath,
836 strlen(dstpath)-strlen(buf+bufp),
837 dstuid, dstgid, &s);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800838 }
839 }
840 } else {
841 char* div = strchr(buf+bufp, ':');
842 if (div == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000843 ALOGW("Bad package spec in %s%s; no ':' sep: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800844 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
845 } else {
846 *div = 0;
847 div++;
848 if (strlen(buf+bufp) < PKG_NAME_MAX) {
849 strcpy(dstpkg, buf+bufp);
850 } else {
851 srcpkg[0] = dstpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000852 ALOGW("Package name too long in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800853 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
854 }
855 if (strlen(div) < PKG_NAME_MAX) {
856 strcpy(srcpkg, div);
857 } else {
858 srcpkg[0] = dstpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000859 ALOGW("Package name too long in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800860 UPDATE_COMMANDS_DIR_PREFIX, name, div);
861 }
862 if (srcpkg[0] != 0) {
Kenny Root86c95842011-03-31 13:16:12 -0700863 if (!create_pkg_path(srcpath, srcpkg, PKG_DIR_POSTFIX, 0)) {
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800864 if (lstat(srcpath, &s) < 0) {
865 // Package no longer exists -- skip.
866 srcpkg[0] = 0;
867 }
868 } else {
869 srcpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000870 ALOGW("Can't create path %s in %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800871 div, UPDATE_COMMANDS_DIR_PREFIX, name);
872 }
873 if (srcpkg[0] != 0) {
Kenny Root86c95842011-03-31 13:16:12 -0700874 if (!create_pkg_path(dstpath, dstpkg, PKG_DIR_POSTFIX, 0)) {
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800875 if (lstat(dstpath, &s) == 0) {
876 dstuid = s.st_uid;
877 dstgid = s.st_gid;
878 } else {
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800879 // Destination package doesn't
880 // exist... due to original-package,
881 // this is normal, so don't be
882 // noisy about it.
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800883 srcpkg[0] = 0;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800884 }
885 } else {
886 srcpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000887 ALOGW("Can't create path %s in %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800888 div, UPDATE_COMMANDS_DIR_PREFIX, name);
889 }
890 }
Steve Block71f2cf12011-10-20 11:56:00 +0100891 ALOGV("Transfering from %s to %s: uid=%d\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800892 srcpkg, dstpkg, dstuid);
893 }
894 }
895 }
896 bufp = bufi+1;
897 } else {
898 if (bufp == 0) {
899 if (bufp < bufe) {
Steve Block8564c8d2012-01-05 23:22:43 +0000900 ALOGW("Line too long in %s%s, skipping: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800901 UPDATE_COMMANDS_DIR_PREFIX, name, buf);
902 }
903 } else if (bufp < bufe) {
904 memcpy(buf, buf+bufp, bufe-bufp);
905 bufe -= bufp;
906 bufp = 0;
907 }
908 readlen = read(subfd, buf+bufe, PKG_PATH_MAX-bufe);
909 if (readlen < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000910 ALOGW("Failure reading update commands in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800911 UPDATE_COMMANDS_DIR_PREFIX, name, strerror(errno));
912 break;
913 } else if (readlen == 0) {
914 break;
915 }
916 bufe += readlen;
917 buf[bufe] = 0;
Steve Block71f2cf12011-10-20 11:56:00 +0100918 ALOGV("Read buf: %s\n", buf);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800919 }
920 }
921 close(subfd);
922 }
923 }
924 closedir(d);
925done:
926 return 0;
927}
Kenny Root6a6b0072010-10-07 16:46:10 -0700928
929int linklib(const char* dataDir, const char* asecLibDir)
930{
931 char libdir[PKG_PATH_MAX];
932 struct stat s, libStat;
933 int rc = 0;
934
935 const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
936 if (libdirLen >= PKG_PATH_MAX) {
Steve Block3762c312012-01-06 19:20:56 +0000937 ALOGE("library dir len too large");
Kenny Root0332d1c2010-10-21 16:14:06 -0700938 return -1;
Kenny Root6a6b0072010-10-07 16:46:10 -0700939 }
940
941 if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
Steve Block3762c312012-01-06 19:20:56 +0000942 ALOGE("library dir not written successfully: %s\n", strerror(errno));
Kenny Root0332d1c2010-10-21 16:14:06 -0700943 return -1;
Kenny Root6a6b0072010-10-07 16:46:10 -0700944 }
945
946 if (stat(dataDir, &s) < 0) return -1;
947
948 if (chown(dataDir, 0, 0) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000949 ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700950 return -1;
951 }
952
953 if (chmod(dataDir, 0700) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000954 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700955 rc = -1;
956 goto out;
957 }
958
959 if (lstat(libdir, &libStat) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000960 ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700961 rc = -1;
962 goto out;
963 }
964
965 if (S_ISDIR(libStat.st_mode)) {
966 if (delete_dir_contents(libdir, 1, 0) < 0) {
967 rc = -1;
968 goto out;
969 }
970 } else if (S_ISLNK(libStat.st_mode)) {
971 if (unlink(libdir) < 0) {
972 rc = -1;
973 goto out;
974 }
975 }
976
977 if (symlink(asecLibDir, libdir) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000978 ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libdir, asecLibDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700979 rc = -errno;
980 goto out;
981 }
982
983 if (lchown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000984 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700985 unlink(libdir);
986 rc = -errno;
987 goto out;
988 }
989
990out:
991 if (chmod(dataDir, s.st_mode) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000992 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Dianne Hackbornd0c5f512012-06-07 16:53:59 -0700993 rc = -errno;
Kenny Root6a6b0072010-10-07 16:46:10 -0700994 }
995
996 if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000997 ALOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700998 return -errno;
999 }
1000
1001 return rc;
1002}
1003
1004int unlinklib(const char* dataDir)
1005{
1006 char libdir[PKG_PATH_MAX];
1007 struct stat s, libStat;
1008 int rc = 0;
1009
1010 const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
1011 if (libdirLen >= PKG_PATH_MAX) {
1012 return -1;
1013 }
1014
1015 if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
Steve Block3762c312012-01-06 19:20:56 +00001016 ALOGE("library dir not written successfully: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001017 return -1;
1018 }
1019
1020 if (stat(dataDir, &s) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001021 ALOGE("couldn't state data dir");
Kenny Root6a6b0072010-10-07 16:46:10 -07001022 return -1;
1023 }
1024
1025 if (chown(dataDir, 0, 0) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001026 ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001027 return -1;
1028 }
1029
1030 if (chmod(dataDir, 0700) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001031 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001032 rc = -1;
1033 goto out;
1034 }
1035
1036 if (lstat(libdir, &libStat) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001037 ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001038 rc = -1;
1039 goto out;
1040 }
1041
1042 if (S_ISDIR(libStat.st_mode)) {
1043 if (delete_dir_contents(libdir, 1, 0) < 0) {
1044 rc = -1;
1045 goto out;
1046 }
1047 } else if (S_ISLNK(libStat.st_mode)) {
1048 if (unlink(libdir) < 0) {
1049 rc = -1;
1050 goto out;
1051 }
1052 }
1053
1054 if (mkdir(libdir, 0755) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001055 ALOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001056 rc = -errno;
1057 goto out;
1058 }
Kenny Root515087d2012-07-30 15:00:16 -07001059 if (chmod(libdir, 0755) < 0) {
1060 ALOGE("cannot chmod dir '%s': %s\n", libdir, strerror(errno));
1061 unlink(libdir);
1062 rc = -errno;
1063 goto out;
1064 }
Kenny Root6a6b0072010-10-07 16:46:10 -07001065 if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001066 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001067 unlink(libdir);
1068 rc = -errno;
1069 goto out;
1070 }
1071
1072out:
1073 if (chmod(dataDir, s.st_mode) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001074 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Dianne Hackbornd0c5f512012-06-07 16:53:59 -07001075 rc = -1;
Kenny Root6a6b0072010-10-07 16:46:10 -07001076 }
1077
1078 if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001079 ALOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001080 return -1;
1081 }
1082
1083 return rc;
1084}