blob: 203d180a64398e97f2232750d4a5a9b37f84b9c6 [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 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056 if (chown(pkgdir, uid, gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000057 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058 unlink(pkgdir);
59 return -errno;
60 }
61 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 }
78 return 0;
79}
80
Amith Yamasani0b285492011-04-14 17:35:23 -070081int uninstall(const char *pkgname, uid_t persona)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082{
83 char pkgdir[PKG_PATH_MAX];
84
Amith Yamasani0b285492011-04-14 17:35:23 -070085 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
Kenny Root35ab3ad2011-02-02 16:42:14 -080086 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087
Amith Yamasani0b285492011-04-14 17:35:23 -070088 /* delete contents AND directory, no exceptions */
89 return delete_dir_contents(pkgdir, 1, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090}
91
Kenny Root35ab3ad2011-02-02 16:42:14 -080092int renamepkg(const char *oldpkgname, const char *newpkgname)
Dianne Hackbornb858dfd2010-02-02 10:49:14 -080093{
94 char oldpkgdir[PKG_PATH_MAX];
95 char newpkgdir[PKG_PATH_MAX];
96
Kenny Root86c95842011-03-31 13:16:12 -070097 if (create_pkg_path(oldpkgdir, oldpkgname, PKG_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -080098 return -1;
Kenny Root86c95842011-03-31 13:16:12 -070099 if (create_pkg_path(newpkgdir, newpkgname, PKG_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800100 return -1;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800101
102 if (rename(oldpkgdir, newpkgdir) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000103 ALOGE("cannot rename dir '%s' to '%s': %s\n", oldpkgdir, newpkgdir, strerror(errno));
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800104 return -errno;
105 }
106 return 0;
107}
108
Amith Yamasani0b285492011-04-14 17:35:23 -0700109int delete_user_data(const char *pkgname, uid_t persona)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110{
111 char pkgdir[PKG_PATH_MAX];
112
Amith Yamasani0b285492011-04-14 17:35:23 -0700113 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800114 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115
Amith Yamasani0b285492011-04-14 17:35:23 -0700116 /* delete contents, excluding "lib", but not the directory itself */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117 return delete_dir_contents(pkgdir, 0, "lib");
118}
119
Amith Yamasani0b285492011-04-14 17:35:23 -0700120int make_user_data(const char *pkgname, uid_t uid, uid_t persona)
121{
122 char pkgdir[PKG_PATH_MAX];
123 char real_libdir[PKG_PATH_MAX];
124
125 // Create the data dir for the package
126 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona)) {
127 return -1;
128 }
129 if (mkdir(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000130 ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
Amith Yamasani0b285492011-04-14 17:35:23 -0700131 return -errno;
132 }
133 if (chown(pkgdir, uid, uid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000134 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
Amith Yamasani0b285492011-04-14 17:35:23 -0700135 unlink(pkgdir);
136 return -errno;
137 }
138 return 0;
139}
140
141int delete_persona(uid_t persona)
142{
143 char pkgdir[PKG_PATH_MAX];
144
145 if (create_persona_path(pkgdir, persona))
146 return -1;
147
148 return delete_dir_contents(pkgdir, 1, NULL);
149}
150
Amith Yamasani742a6712011-05-04 14:49:28 -0700151int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy)
152{
153 char src_data_dir[PKG_PATH_MAX];
154 char pkg_path[PKG_PATH_MAX];
155 DIR *d;
156 struct dirent *de;
157 struct stat s;
158 uid_t uid;
159
160 if (create_persona_path(src_data_dir, src_persona)) {
161 return -1;
162 }
163
164 d = opendir(src_data_dir);
165 if (d != NULL) {
166 while ((de = readdir(d))) {
167 const char *name = de->d_name;
168
169 if (de->d_type == DT_DIR) {
170 int subfd;
171 /* always skip "." and ".." */
172 if (name[0] == '.') {
173 if (name[1] == 0) continue;
174 if ((name[1] == '.') && (name[2] == 0)) continue;
175 }
176 /* Create the full path to the package's data dir */
177 create_pkg_path(pkg_path, name, PKG_DIR_POSTFIX, src_persona);
178 /* Get the file stat */
179 if (stat(pkg_path, &s) < 0) continue;
180 /* Get the uid of the package */
181 ALOGI("Adding datadir for uid = %d\n", s.st_uid);
182 uid = (uid_t) s.st_uid % PER_USER_RANGE;
183 /* Create the directory for the target */
184 make_user_data(name, uid + target_persona * PER_USER_RANGE,
185 target_persona);
186 }
187 }
188 closedir(d);
189 }
190 return 0;
191}
192
Kenny Root35ab3ad2011-02-02 16:42:14 -0800193int delete_cache(const char *pkgname)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194{
195 char cachedir[PKG_PATH_MAX];
196
Kenny Root86c95842011-03-31 13:16:12 -0700197 if (create_pkg_path(cachedir, pkgname, CACHE_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800198 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199
200 /* delete contents, not the directory, no exceptions */
201 return delete_dir_contents(cachedir, 0, 0);
202}
203
Kenny Root3e319a92010-09-07 13:58:28 -0700204static int64_t disk_free()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205{
206 struct statfs sfs;
Kenny Root86c95842011-03-31 13:16:12 -0700207 if (statfs(android_data_dir.path, &sfs) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208 return sfs.f_bavail * sfs.f_bsize;
209 } else {
Steve Block3762c312012-01-06 19:20:56 +0000210 ALOGE("Couldn't statfs %s: %s\n", android_data_dir.path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 return -1;
212 }
213}
214
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215/* Try to ensure free_size bytes of storage are available.
216 * Returns 0 on success.
217 * This is rather simple-minded because doing a full LRU would
218 * be potentially memory-intensive, and without atime it would
219 * also require that apps constantly modify file metadata even
220 * when just reading from the cache, which is pretty awful.
221 */
Kenny Root3e319a92010-09-07 13:58:28 -0700222int free_cache(int64_t free_size)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223{
224 const char *name;
225 int dfd, subfd;
226 DIR *d;
227 struct dirent *de;
Kenny Root3e319a92010-09-07 13:58:28 -0700228 int64_t avail;
Kenny Rootad757e92011-11-29 15:54:55 -0800229 char datadir[PKG_PATH_MAX];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230
231 avail = disk_free();
232 if (avail < 0) return -1;
233
Steve Block6215d3f2012-01-04 20:05:49 +0000234 ALOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235 if (avail >= free_size) return 0;
236
Kenny Rootad757e92011-11-29 15:54:55 -0800237 if (create_persona_path(datadir, 0)) {
Steve Block3762c312012-01-06 19:20:56 +0000238 ALOGE("couldn't get directory for persona 0");
Kenny Rootad757e92011-11-29 15:54:55 -0800239 return -1;
240 }
241
242 d = opendir(datadir);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 if (d == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000244 ALOGE("cannot open %s: %s\n", datadir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245 return -1;
246 }
247 dfd = dirfd(d);
248
249 while ((de = readdir(d))) {
250 if (de->d_type != DT_DIR) continue;
251 name = de->d_name;
252
Oscar Montemayora8529f62009-11-18 10:14:20 -0800253 /* always skip "." and ".." */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254 if (name[0] == '.') {
255 if (name[1] == 0) continue;
256 if ((name[1] == '.') && (name[2] == 0)) continue;
257 }
258
259 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
260 if (subfd < 0) continue;
261
262 delete_dir_contents_fd(subfd, "cache");
263 close(subfd);
264
265 avail = disk_free();
266 if (avail >= free_size) {
267 closedir(d);
268 return 0;
269 }
270 }
271 closedir(d);
Oscar Montemayora8529f62009-11-18 10:14:20 -0800272
273 /* Fail case - not possible to free space */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274 return -1;
275}
276
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277int move_dex(const char *src, const char *dst)
278{
279 char src_dex[PKG_PATH_MAX];
280 char dst_dex[PKG_PATH_MAX];
281
Kenny Root86c95842011-03-31 13:16:12 -0700282 if (validate_apk_path(src)) return -1;
283 if (validate_apk_path(dst)) return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284
285 if (create_cache_path(src_dex, src)) return -1;
286 if (create_cache_path(dst_dex, dst)) return -1;
287
Steve Block71f2cf12011-10-20 11:56:00 +0100288 ALOGV("move %s -> %s\n", src_dex, dst_dex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289 if (rename(src_dex, dst_dex) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000290 ALOGE("Couldn't move %s: %s\n", src_dex, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291 return -1;
292 } else {
293 return 0;
294 }
295}
296
297int rm_dex(const char *path)
298{
299 char dex_path[PKG_PATH_MAX];
300
Kenny Root86c95842011-03-31 13:16:12 -0700301 if (validate_apk_path(path)) return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302 if (create_cache_path(dex_path, path)) return -1;
303
Steve Block71f2cf12011-10-20 11:56:00 +0100304 ALOGV("unlink %s\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305 if (unlink(dex_path) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000306 ALOGE("Couldn't unlink %s: %s\n", dex_path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800307 return -1;
308 } else {
309 return 0;
310 }
311}
312
313int protect(char *pkgname, gid_t gid)
314{
315 struct stat s;
316 char pkgpath[PKG_PATH_MAX];
317
318 if (gid < AID_SYSTEM) return -1;
319
Kenny Root86c95842011-03-31 13:16:12 -0700320 if (create_pkg_path_in_dir(pkgpath, &android_app_private_dir, pkgname, ".apk"))
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321 return -1;
322
323 if (stat(pkgpath, &s) < 0) return -1;
324
325 if (chown(pkgpath, s.st_uid, gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000326 ALOGE("failed to chgrp '%s': %s\n", pkgpath, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800327 return -1;
328 }
329
330 if (chmod(pkgpath, S_IRUSR|S_IWUSR|S_IRGRP) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000331 ALOGE("failed to chmod '%s': %s\n", pkgpath, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 return -1;
333 }
334
335 return 0;
336}
337
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800338int get_size(const char *pkgname, const char *apkpath,
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700339 const char *fwdlock_apkpath, const char *asecpath,
340 int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize,
341 int64_t* _asecsize)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342{
343 DIR *d;
344 int dfd;
345 struct dirent *de;
346 struct stat s;
347 char path[PKG_PATH_MAX];
348
Kenny Root3e319a92010-09-07 13:58:28 -0700349 int64_t codesize = 0;
350 int64_t datasize = 0;
351 int64_t cachesize = 0;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700352 int64_t asecsize = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353
354 /* count the source apk as code -- but only if it's not
Suchi Amalapurapu8a9ab242010-03-11 16:49:16 -0800355 * on the /system partition and its not on the sdcard.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356 */
Kenny Root86c95842011-03-31 13:16:12 -0700357 if (validate_system_app_path(apkpath) &&
358 strncmp(apkpath, android_asec_dir.path, android_asec_dir.len) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 if (stat(apkpath, &s) == 0) {
360 codesize += stat_size(&s);
361 }
362 }
363 /* count the forward locked apk as code if it is given
364 */
365 if (fwdlock_apkpath != NULL && fwdlock_apkpath[0] != '!') {
366 if (stat(fwdlock_apkpath, &s) == 0) {
367 codesize += stat_size(&s);
368 }
369 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 /* count the cached dexfile as code */
371 if (!create_cache_path(path, apkpath)) {
372 if (stat(path, &s) == 0) {
373 codesize += stat_size(&s);
374 }
375 }
376
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700377 /* compute asec size if it is given
378 */
379 if (asecpath != NULL && asecpath[0] != '!') {
380 if (stat(asecpath, &s) == 0) {
381 asecsize += stat_size(&s);
382 }
383 }
384
Kenny Root86c95842011-03-31 13:16:12 -0700385 if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, 0)) {
Kenny Root35ab3ad2011-02-02 16:42:14 -0800386 goto done;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 }
388
389 d = opendir(path);
390 if (d == NULL) {
391 goto done;
392 }
393 dfd = dirfd(d);
394
Kenny Root86c95842011-03-31 13:16:12 -0700395 /* most stuff in the pkgdir is data, except for the "cache"
396 * directory and below, which is cache, and the "lib" directory
397 * and below, which is code...
398 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 while ((de = readdir(d))) {
400 const char *name = de->d_name;
401
402 if (de->d_type == DT_DIR) {
403 int subfd;
404 /* always skip "." and ".." */
405 if (name[0] == '.') {
406 if (name[1] == 0) continue;
407 if ((name[1] == '.') && (name[2] == 0)) continue;
408 }
409 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
410 if (subfd >= 0) {
Kenny Root3e319a92010-09-07 13:58:28 -0700411 int64_t size = calculate_dir_size(subfd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 if (!strcmp(name,"lib")) {
413 codesize += size;
414 } else if(!strcmp(name,"cache")) {
415 cachesize += size;
416 } else {
417 datasize += size;
418 }
419 }
420 } else {
421 if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
422 datasize += stat_size(&s);
423 }
424 }
425 }
426 closedir(d);
427done:
428 *_codesize = codesize;
429 *_datasize = datasize;
430 *_cachesize = cachesize;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700431 *_asecsize = asecsize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432 return 0;
433}
434
435
436/* a simpler version of dexOptGenerateCacheFileName() */
437int create_cache_path(char path[PKG_PATH_MAX], const char *src)
438{
439 char *tmp;
440 int srclen;
441 int dstlen;
442
443 srclen = strlen(src);
444
445 /* demand that we are an absolute path */
446 if ((src == 0) || (src[0] != '/') || strstr(src,"..")) {
447 return -1;
448 }
449
450 if (srclen > PKG_PATH_MAX) { // XXX: PKG_NAME_MAX?
451 return -1;
452 }
453
454 dstlen = srclen + strlen(DALVIK_CACHE_PREFIX) +
455 strlen(DALVIK_CACHE_POSTFIX) + 1;
456
457 if (dstlen > PKG_PATH_MAX) {
458 return -1;
459 }
460
461 sprintf(path,"%s%s%s",
462 DALVIK_CACHE_PREFIX,
463 src + 1, /* skip the leading / */
464 DALVIK_CACHE_POSTFIX);
465
466 for(tmp = path + strlen(DALVIK_CACHE_PREFIX); *tmp; tmp++) {
467 if (*tmp == '/') {
468 *tmp = '@';
469 }
470 }
471
472 return 0;
473}
474
475static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name,
476 const char* dexopt_flags)
477{
478 static const char* DEX_OPT_BIN = "/system/bin/dexopt";
479 static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
480 char zip_num[MAX_INT_LEN];
481 char odex_num[MAX_INT_LEN];
482
483 sprintf(zip_num, "%d", zip_fd);
484 sprintf(odex_num, "%d", odex_fd);
485
486 execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name,
487 dexopt_flags, (char*) NULL);
Steve Block3762c312012-01-06 19:20:56 +0000488 ALOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489}
490
491static int wait_dexopt(pid_t pid, const char* apk_path)
492{
493 int status;
494 pid_t got_pid;
495
496 /*
497 * Wait for the optimization process to finish.
498 */
499 while (1) {
500 got_pid = waitpid(pid, &status, 0);
501 if (got_pid == -1 && errno == EINTR) {
502 printf("waitpid interrupted, retrying\n");
503 } else {
504 break;
505 }
506 }
507 if (got_pid != pid) {
Steve Block8564c8d2012-01-05 23:22:43 +0000508 ALOGW("waitpid failed: wanted %d, got %d: %s\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509 (int) pid, (int) got_pid, strerror(errno));
510 return 1;
511 }
512
513 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100514 ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800515 return 0;
516 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000517 ALOGW("DexInv: --- END '%s' --- status=0x%04x, process failed\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800518 apk_path, status);
519 return status; /* always nonzero */
520 }
521}
522
523int dexopt(const char *apk_path, uid_t uid, int is_public)
524{
525 struct utimbuf ut;
526 struct stat apk_stat, dex_stat;
527 char dex_path[PKG_PATH_MAX];
528 char dexopt_flags[PROPERTY_VALUE_MAX];
529 char *end;
530 int res, zip_fd=-1, odex_fd=-1;
531
532 /* Before anything else: is there a .odex file? If so, we have
533 * pre-optimized the apk and there is nothing to do here.
534 */
535 if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
536 return -1;
537 }
538
539 /* platform-specific flags affecting optimization and verification */
540 property_get("dalvik.vm.dexopt-flags", dexopt_flags, "");
541
542 strcpy(dex_path, apk_path);
543 end = strrchr(dex_path, '.');
544 if (end != NULL) {
545 strcpy(end, ".odex");
546 if (stat(dex_path, &dex_stat) == 0) {
547 return 0;
548 }
549 }
550
551 if (create_cache_path(dex_path, apk_path)) {
552 return -1;
553 }
554
555 memset(&apk_stat, 0, sizeof(apk_stat));
556 stat(apk_path, &apk_stat);
557
558 zip_fd = open(apk_path, O_RDONLY, 0);
559 if (zip_fd < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000560 ALOGE("dexopt cannot open '%s' for input\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561 return -1;
562 }
563
564 unlink(dex_path);
565 odex_fd = open(dex_path, O_RDWR | O_CREAT | O_EXCL, 0644);
566 if (odex_fd < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000567 ALOGE("dexopt cannot open '%s' for output\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 goto fail;
569 }
570 if (fchown(odex_fd, AID_SYSTEM, uid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000571 ALOGE("dexopt cannot chown '%s'\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 goto fail;
573 }
574 if (fchmod(odex_fd,
575 S_IRUSR|S_IWUSR|S_IRGRP |
576 (is_public ? S_IROTH : 0)) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000577 ALOGE("dexopt cannot chmod '%s'\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 goto fail;
579 }
580
Steve Block71f2cf12011-10-20 11:56:00 +0100581 ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582
583 pid_t pid;
584 pid = fork();
585 if (pid == 0) {
586 /* child -- drop privileges before continuing */
587 if (setgid(uid) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000588 ALOGE("setgid(%d) failed during dexopt\n", uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800589 exit(64);
590 }
591 if (setuid(uid) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000592 ALOGE("setuid(%d) during dexopt\n", uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 exit(65);
594 }
595 if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000596 ALOGE("flock(%s) failed: %s\n", dex_path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800597 exit(66);
598 }
599
600 run_dexopt(zip_fd, odex_fd, apk_path, dexopt_flags);
601 exit(67); /* only get here on exec failure */
602 } else {
603 res = wait_dexopt(pid, apk_path);
604 if (res != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000605 ALOGE("dexopt failed on '%s' res = %d\n", dex_path, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800606 goto fail;
607 }
608 }
609
610 ut.actime = apk_stat.st_atime;
611 ut.modtime = apk_stat.st_mtime;
612 utime(dex_path, &ut);
613
614 close(odex_fd);
615 close(zip_fd);
616 return 0;
617
618fail:
619 if (odex_fd >= 0) {
620 close(odex_fd);
621 unlink(dex_path);
622 }
623 if (zip_fd >= 0) {
624 close(zip_fd);
625 }
626 return -1;
627}
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800628
Dianne Hackbornc1552392010-03-03 16:19:01 -0800629void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid,
630 struct stat* statbuf)
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800631{
632 while (path[basepos] != 0) {
633 if (path[basepos] == '/') {
634 path[basepos] = 0;
Dianne Hackbornc1552392010-03-03 16:19:01 -0800635 if (lstat(path, statbuf) < 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100636 ALOGV("Making directory: %s\n", path);
Dianne Hackbornc1552392010-03-03 16:19:01 -0800637 if (mkdir(path, mode) == 0) {
638 chown(path, uid, gid);
639 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000640 ALOGW("Unable to make directory %s: %s\n", path, strerror(errno));
Dianne Hackbornc1552392010-03-03 16:19:01 -0800641 }
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800642 }
643 path[basepos] = '/';
644 basepos++;
645 }
646 basepos++;
647 }
648}
649
Dianne Hackbornc1552392010-03-03 16:19:01 -0800650int movefileordir(char* srcpath, char* dstpath, int dstbasepos,
651 int dstuid, int dstgid, struct stat* statbuf)
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800652{
653 DIR *d;
654 struct dirent *de;
655 int res;
656
657 int srcend = strlen(srcpath);
658 int dstend = strlen(dstpath);
659
660 if (lstat(srcpath, statbuf) < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000661 ALOGW("Unable to stat %s: %s\n", srcpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800662 return 1;
663 }
664
665 if ((statbuf->st_mode&S_IFDIR) == 0) {
Dianne Hackbornc1552392010-03-03 16:19:01 -0800666 mkinnerdirs(dstpath, dstbasepos, S_IRWXU|S_IRWXG|S_IXOTH,
667 dstuid, dstgid, statbuf);
Steve Block71f2cf12011-10-20 11:56:00 +0100668 ALOGV("Renaming %s to %s (uid %d)\n", srcpath, dstpath, dstuid);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800669 if (rename(srcpath, dstpath) >= 0) {
670 if (chown(dstpath, dstuid, dstgid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000671 ALOGE("cannot chown %s: %s\n", dstpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800672 unlink(dstpath);
673 return 1;
674 }
675 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000676 ALOGW("Unable to rename %s to %s: %s\n",
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800677 srcpath, dstpath, strerror(errno));
678 return 1;
679 }
680 return 0;
681 }
682
683 d = opendir(srcpath);
684 if (d == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000685 ALOGW("Unable to opendir %s: %s\n", srcpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800686 return 1;
687 }
688
689 res = 0;
690
691 while ((de = readdir(d))) {
692 const char *name = de->d_name;
693 /* always skip "." and ".." */
694 if (name[0] == '.') {
695 if (name[1] == 0) continue;
696 if ((name[1] == '.') && (name[2] == 0)) continue;
697 }
698
699 if ((srcend+strlen(name)) >= (PKG_PATH_MAX-2)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000700 ALOGW("Source path too long; skipping: %s/%s\n", srcpath, name);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800701 continue;
702 }
703
704 if ((dstend+strlen(name)) >= (PKG_PATH_MAX-2)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000705 ALOGW("Destination path too long; skipping: %s/%s\n", dstpath, name);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800706 continue;
707 }
708
709 srcpath[srcend] = dstpath[dstend] = '/';
710 strcpy(srcpath+srcend+1, name);
711 strcpy(dstpath+dstend+1, name);
712
Dianne Hackbornc1552392010-03-03 16:19:01 -0800713 if (movefileordir(srcpath, dstpath, dstbasepos, dstuid, dstgid, statbuf) != 0) {
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800714 res = 1;
715 }
716
717 // Note: we will be leaving empty directories behind in srcpath,
718 // but that is okay, the package manager will be erasing all of the
719 // data associated with .apks that disappear.
720
721 srcpath[srcend] = dstpath[dstend] = 0;
722 }
723
724 closedir(d);
725 return res;
726}
727
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800728int movefiles()
729{
730 DIR *d;
731 int dfd, subfd;
732 struct dirent *de;
733 struct stat s;
734 char buf[PKG_PATH_MAX+1];
735 int bufp, bufe, bufi, readlen;
736
737 char srcpkg[PKG_NAME_MAX];
738 char dstpkg[PKG_NAME_MAX];
739 char srcpath[PKG_PATH_MAX];
740 char dstpath[PKG_PATH_MAX];
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800741 int dstuid=-1, dstgid=-1;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800742 int hasspace;
743
744 d = opendir(UPDATE_COMMANDS_DIR_PREFIX);
745 if (d == NULL) {
746 goto done;
747 }
748 dfd = dirfd(d);
749
750 /* Iterate through all files in the directory, executing the
751 * file movements requested there-in.
752 */
753 while ((de = readdir(d))) {
754 const char *name = de->d_name;
755
756 if (de->d_type == DT_DIR) {
757 continue;
758 } else {
759 subfd = openat(dfd, name, O_RDONLY);
760 if (subfd < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000761 ALOGW("Unable to open update commands at %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800762 UPDATE_COMMANDS_DIR_PREFIX, name);
763 continue;
764 }
765
766 bufp = 0;
767 bufe = 0;
768 buf[PKG_PATH_MAX] = 0;
769 srcpkg[0] = dstpkg[0] = 0;
770 while (1) {
771 bufi = bufp;
772 while (bufi < bufe && buf[bufi] != '\n') {
773 bufi++;
774 }
775 if (bufi < bufe) {
776 buf[bufi] = 0;
Steve Block71f2cf12011-10-20 11:56:00 +0100777 ALOGV("Processing line: %s\n", buf+bufp);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800778 hasspace = 0;
779 while (bufp < bufi && isspace(buf[bufp])) {
780 hasspace = 1;
781 bufp++;
782 }
783 if (buf[bufp] == '#' || bufp == bufi) {
784 // skip comments and empty lines.
785 } else if (hasspace) {
786 if (dstpkg[0] == 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000787 ALOGW("Path before package line in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800788 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
789 } else if (srcpkg[0] == 0) {
790 // Skip -- source package no longer exists.
791 } else {
Steve Block71f2cf12011-10-20 11:56:00 +0100792 ALOGV("Move file: %s (from %s to %s)\n", buf+bufp, srcpkg, dstpkg);
Kenny Root86c95842011-03-31 13:16:12 -0700793 if (!create_move_path(srcpath, srcpkg, buf+bufp, 0) &&
794 !create_move_path(dstpath, dstpkg, buf+bufp, 0)) {
Dianne Hackbornc1552392010-03-03 16:19:01 -0800795 movefileordir(srcpath, dstpath,
796 strlen(dstpath)-strlen(buf+bufp),
797 dstuid, dstgid, &s);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800798 }
799 }
800 } else {
801 char* div = strchr(buf+bufp, ':');
802 if (div == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000803 ALOGW("Bad package spec in %s%s; no ':' sep: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800804 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
805 } else {
806 *div = 0;
807 div++;
808 if (strlen(buf+bufp) < PKG_NAME_MAX) {
809 strcpy(dstpkg, buf+bufp);
810 } else {
811 srcpkg[0] = dstpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000812 ALOGW("Package name too long in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800813 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
814 }
815 if (strlen(div) < PKG_NAME_MAX) {
816 strcpy(srcpkg, div);
817 } else {
818 srcpkg[0] = dstpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000819 ALOGW("Package name too long in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800820 UPDATE_COMMANDS_DIR_PREFIX, name, div);
821 }
822 if (srcpkg[0] != 0) {
Kenny Root86c95842011-03-31 13:16:12 -0700823 if (!create_pkg_path(srcpath, srcpkg, PKG_DIR_POSTFIX, 0)) {
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800824 if (lstat(srcpath, &s) < 0) {
825 // Package no longer exists -- skip.
826 srcpkg[0] = 0;
827 }
828 } else {
829 srcpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000830 ALOGW("Can't create path %s in %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800831 div, UPDATE_COMMANDS_DIR_PREFIX, name);
832 }
833 if (srcpkg[0] != 0) {
Kenny Root86c95842011-03-31 13:16:12 -0700834 if (!create_pkg_path(dstpath, dstpkg, PKG_DIR_POSTFIX, 0)) {
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800835 if (lstat(dstpath, &s) == 0) {
836 dstuid = s.st_uid;
837 dstgid = s.st_gid;
838 } else {
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800839 // Destination package doesn't
840 // exist... due to original-package,
841 // this is normal, so don't be
842 // noisy about it.
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800843 srcpkg[0] = 0;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800844 }
845 } else {
846 srcpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000847 ALOGW("Can't create path %s in %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800848 div, UPDATE_COMMANDS_DIR_PREFIX, name);
849 }
850 }
Steve Block71f2cf12011-10-20 11:56:00 +0100851 ALOGV("Transfering from %s to %s: uid=%d\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800852 srcpkg, dstpkg, dstuid);
853 }
854 }
855 }
856 bufp = bufi+1;
857 } else {
858 if (bufp == 0) {
859 if (bufp < bufe) {
Steve Block8564c8d2012-01-05 23:22:43 +0000860 ALOGW("Line too long in %s%s, skipping: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800861 UPDATE_COMMANDS_DIR_PREFIX, name, buf);
862 }
863 } else if (bufp < bufe) {
864 memcpy(buf, buf+bufp, bufe-bufp);
865 bufe -= bufp;
866 bufp = 0;
867 }
868 readlen = read(subfd, buf+bufe, PKG_PATH_MAX-bufe);
869 if (readlen < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000870 ALOGW("Failure reading update commands in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800871 UPDATE_COMMANDS_DIR_PREFIX, name, strerror(errno));
872 break;
873 } else if (readlen == 0) {
874 break;
875 }
876 bufe += readlen;
877 buf[bufe] = 0;
Steve Block71f2cf12011-10-20 11:56:00 +0100878 ALOGV("Read buf: %s\n", buf);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800879 }
880 }
881 close(subfd);
882 }
883 }
884 closedir(d);
885done:
886 return 0;
887}
Kenny Root6a6b0072010-10-07 16:46:10 -0700888
889int linklib(const char* dataDir, const char* asecLibDir)
890{
891 char libdir[PKG_PATH_MAX];
892 struct stat s, libStat;
893 int rc = 0;
894
895 const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
896 if (libdirLen >= PKG_PATH_MAX) {
Steve Block3762c312012-01-06 19:20:56 +0000897 ALOGE("library dir len too large");
Kenny Root0332d1c2010-10-21 16:14:06 -0700898 return -1;
Kenny Root6a6b0072010-10-07 16:46:10 -0700899 }
900
901 if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
Steve Block3762c312012-01-06 19:20:56 +0000902 ALOGE("library dir not written successfully: %s\n", strerror(errno));
Kenny Root0332d1c2010-10-21 16:14:06 -0700903 return -1;
Kenny Root6a6b0072010-10-07 16:46:10 -0700904 }
905
906 if (stat(dataDir, &s) < 0) return -1;
907
908 if (chown(dataDir, 0, 0) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000909 ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700910 return -1;
911 }
912
913 if (chmod(dataDir, 0700) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000914 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700915 rc = -1;
916 goto out;
917 }
918
919 if (lstat(libdir, &libStat) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000920 ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700921 rc = -1;
922 goto out;
923 }
924
925 if (S_ISDIR(libStat.st_mode)) {
926 if (delete_dir_contents(libdir, 1, 0) < 0) {
927 rc = -1;
928 goto out;
929 }
930 } else if (S_ISLNK(libStat.st_mode)) {
931 if (unlink(libdir) < 0) {
932 rc = -1;
933 goto out;
934 }
935 }
936
937 if (symlink(asecLibDir, libdir) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000938 ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libdir, asecLibDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700939 rc = -errno;
940 goto out;
941 }
942
943 if (lchown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000944 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700945 unlink(libdir);
946 rc = -errno;
947 goto out;
948 }
949
950out:
951 if (chmod(dataDir, s.st_mode) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000952 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700953 return -errno;
954 }
955
956 if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000957 ALOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700958 return -errno;
959 }
960
961 return rc;
962}
963
964int unlinklib(const char* dataDir)
965{
966 char libdir[PKG_PATH_MAX];
967 struct stat s, libStat;
968 int rc = 0;
969
970 const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
971 if (libdirLen >= PKG_PATH_MAX) {
972 return -1;
973 }
974
975 if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
Steve Block3762c312012-01-06 19:20:56 +0000976 ALOGE("library dir not written successfully: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700977 return -1;
978 }
979
980 if (stat(dataDir, &s) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000981 ALOGE("couldn't state data dir");
Kenny Root6a6b0072010-10-07 16:46:10 -0700982 return -1;
983 }
984
985 if (chown(dataDir, 0, 0) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000986 ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700987 return -1;
988 }
989
990 if (chmod(dataDir, 0700) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000991 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700992 rc = -1;
993 goto out;
994 }
995
996 if (lstat(libdir, &libStat) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000997 ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700998 rc = -1;
999 goto out;
1000 }
1001
1002 if (S_ISDIR(libStat.st_mode)) {
1003 if (delete_dir_contents(libdir, 1, 0) < 0) {
1004 rc = -1;
1005 goto out;
1006 }
1007 } else if (S_ISLNK(libStat.st_mode)) {
1008 if (unlink(libdir) < 0) {
1009 rc = -1;
1010 goto out;
1011 }
1012 }
1013
1014 if (mkdir(libdir, 0755) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001015 ALOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001016 rc = -errno;
1017 goto out;
1018 }
1019
1020 if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001021 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001022 unlink(libdir);
1023 rc = -errno;
1024 goto out;
1025 }
1026
1027out:
1028 if (chmod(dataDir, s.st_mode) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001029 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001030 return -1;
1031 }
1032
1033 if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001034 ALOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001035 return -1;
1036 }
1037
1038 return rc;
1039}