blob: f5f6f3b087f2d561dbf27b850650a2cda538ab76 [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;
Dianne Hackborn197a0c82012-07-12 14:46:04 -070029dir_rec_t android_media_dir;
Kenny Root86c95842011-03-31 13:16:12 -070030dir_rec_array_t android_system_dirs;
31
Kenny Root35ab3ad2011-02-02 16:42:14 -080032int install(const char *pkgname, uid_t uid, gid_t gid)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033{
34 char pkgdir[PKG_PATH_MAX];
35 char libdir[PKG_PATH_MAX];
36
37 if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
Steve Block3762c312012-01-06 19:20:56 +000038 ALOGE("invalid uid/gid: %d %d\n", uid, gid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040 }
Oscar Montemayora8529f62009-11-18 10:14:20 -080041
Kenny Root86c95842011-03-31 13:16:12 -070042 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
Steve Block3762c312012-01-06 19:20:56 +000043 ALOGE("cannot create package path\n");
Kenny Root35ab3ad2011-02-02 16:42:14 -080044 return -1;
Kenny Root86c95842011-03-31 13:16:12 -070045 }
46
47 if (create_pkg_path(libdir, pkgname, PKG_LIB_POSTFIX, 0)) {
Steve Block3762c312012-01-06 19:20:56 +000048 ALOGE("cannot create package lib path\n");
Kenny Root35ab3ad2011-02-02 16:42:14 -080049 return -1;
Kenny Root86c95842011-03-31 13:16:12 -070050 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051
David 'Digit' Turner0dd50e62010-02-09 19:02:38 -080052 if (mkdir(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000053 ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054 return -errno;
55 }
Nick Kralevichf68327e2011-04-14 16:20:03 -070056 if (chmod(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000057 ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
Nick Kralevichf68327e2011-04-14 16:20:03 -070058 unlink(pkgdir);
59 return -errno;
60 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -050061
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062 if (mkdir(libdir, 0755) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000063 ALOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064 unlink(pkgdir);
65 return -errno;
66 }
Nick Kralevichf68327e2011-04-14 16:20:03 -070067 if (chmod(libdir, 0755) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000068 ALOGE("cannot chmod dir '%s': %s\n", libdir, strerror(errno));
Nick Kralevichf68327e2011-04-14 16:20:03 -070069 unlink(libdir);
70 unlink(pkgdir);
71 return -errno;
72 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073 if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000074 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075 unlink(libdir);
76 unlink(pkgdir);
77 return -errno;
78 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -050079
80#ifdef HAVE_SELINUX
81 if (selinux_android_setfilecon(libdir, pkgname, AID_SYSTEM) < 0) {
82 LOGE("cannot setfilecon dir '%s': %s\n", libdir, strerror(errno));
83 unlink(libdir);
84 unlink(pkgdir);
85 return -errno;
86 }
87#endif
88
Kenny Root4503cf62012-06-14 13:05:18 -070089 if (chown(pkgdir, uid, gid) < 0) {
90 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
91 unlink(libdir);
92 unlink(pkgdir);
93 return -errno;
94 }
Kenny Root33ef4ee2012-06-18 10:26:36 -070095
96#ifdef HAVE_SELINUX
97 if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
98 LOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
99 unlink(libdir);
100 unlink(pkgdir);
101 return -errno;
102 }
103#endif
104
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 return 0;
106}
107
Amith Yamasani0b285492011-04-14 17:35:23 -0700108int uninstall(const char *pkgname, uid_t persona)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109{
110 char pkgdir[PKG_PATH_MAX];
111
Amith Yamasani0b285492011-04-14 17:35:23 -0700112 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800113 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114
Amith Yamasani0b285492011-04-14 17:35:23 -0700115 /* delete contents AND directory, no exceptions */
116 return delete_dir_contents(pkgdir, 1, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117}
118
Kenny Root35ab3ad2011-02-02 16:42:14 -0800119int renamepkg(const char *oldpkgname, const char *newpkgname)
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800120{
121 char oldpkgdir[PKG_PATH_MAX];
122 char newpkgdir[PKG_PATH_MAX];
123
Kenny Root86c95842011-03-31 13:16:12 -0700124 if (create_pkg_path(oldpkgdir, oldpkgname, PKG_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800125 return -1;
Kenny Root86c95842011-03-31 13:16:12 -0700126 if (create_pkg_path(newpkgdir, newpkgname, PKG_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800127 return -1;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800128
129 if (rename(oldpkgdir, newpkgdir) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000130 ALOGE("cannot rename dir '%s' to '%s': %s\n", oldpkgdir, newpkgdir, strerror(errno));
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800131 return -errno;
132 }
133 return 0;
134}
135
Dianne Hackbornd0c5f512012-06-07 16:53:59 -0700136int fix_uid(const char *pkgname, uid_t uid, gid_t gid)
137{
138 char pkgdir[PKG_PATH_MAX];
139 struct stat s;
140 int rc = 0;
141
142 if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
143 ALOGE("invalid uid/gid: %d %d\n", uid, gid);
144 return -1;
145 }
146
147 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
148 ALOGE("cannot create package path\n");
149 return -1;
150 }
151
152 if (stat(pkgdir, &s) < 0) return -1;
153
154 if (s.st_uid != 0 || s.st_gid != 0) {
155 ALOGE("fixing uid of non-root pkg: %s %d %d\n", pkgdir, s.st_uid, s.st_gid);
156 return -1;
157 }
158
159 if (chmod(pkgdir, 0751) < 0) {
160 ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
161 unlink(pkgdir);
162 return -errno;
163 }
164 if (chown(pkgdir, uid, gid) < 0) {
165 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
166 unlink(pkgdir);
167 return -errno;
168 }
169
170 return 0;
171}
172
Amith Yamasani0b285492011-04-14 17:35:23 -0700173int delete_user_data(const char *pkgname, uid_t persona)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174{
175 char pkgdir[PKG_PATH_MAX];
176
Amith Yamasani0b285492011-04-14 17:35:23 -0700177 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800178 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179
Amith Yamasani0b285492011-04-14 17:35:23 -0700180 /* delete contents, excluding "lib", but not the directory itself */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 return delete_dir_contents(pkgdir, 0, "lib");
182}
183
Amith Yamasani0b285492011-04-14 17:35:23 -0700184int make_user_data(const char *pkgname, uid_t uid, uid_t persona)
185{
186 char pkgdir[PKG_PATH_MAX];
187 char real_libdir[PKG_PATH_MAX];
188
189 // Create the data dir for the package
190 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona)) {
191 return -1;
192 }
193 if (mkdir(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000194 ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
Amith Yamasani0b285492011-04-14 17:35:23 -0700195 return -errno;
196 }
197 if (chown(pkgdir, uid, uid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000198 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
Amith Yamasani0b285492011-04-14 17:35:23 -0700199 unlink(pkgdir);
200 return -errno;
201 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500202
203#ifdef HAVE_SELINUX
204 if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
205 LOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
206 unlink(pkgdir);
207 return -errno;
208 }
209#endif
210
Amith Yamasani0b285492011-04-14 17:35:23 -0700211 return 0;
212}
213
214int delete_persona(uid_t persona)
215{
216 char pkgdir[PKG_PATH_MAX];
217
218 if (create_persona_path(pkgdir, persona))
219 return -1;
220
221 return delete_dir_contents(pkgdir, 1, NULL);
222}
223
Amith Yamasani742a6712011-05-04 14:49:28 -0700224int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy)
225{
226 char src_data_dir[PKG_PATH_MAX];
227 char pkg_path[PKG_PATH_MAX];
228 DIR *d;
229 struct dirent *de;
230 struct stat s;
231 uid_t uid;
232
233 if (create_persona_path(src_data_dir, src_persona)) {
234 return -1;
235 }
236
237 d = opendir(src_data_dir);
238 if (d != NULL) {
239 while ((de = readdir(d))) {
240 const char *name = de->d_name;
241
242 if (de->d_type == DT_DIR) {
243 int subfd;
244 /* always skip "." and ".." */
245 if (name[0] == '.') {
246 if (name[1] == 0) continue;
247 if ((name[1] == '.') && (name[2] == 0)) continue;
248 }
249 /* Create the full path to the package's data dir */
250 create_pkg_path(pkg_path, name, PKG_DIR_POSTFIX, src_persona);
251 /* Get the file stat */
252 if (stat(pkg_path, &s) < 0) continue;
253 /* Get the uid of the package */
254 ALOGI("Adding datadir for uid = %d\n", s.st_uid);
255 uid = (uid_t) s.st_uid % PER_USER_RANGE;
256 /* Create the directory for the target */
257 make_user_data(name, uid + target_persona * PER_USER_RANGE,
258 target_persona);
259 }
260 }
261 closedir(d);
262 }
263 return 0;
264}
265
Kenny Root35ab3ad2011-02-02 16:42:14 -0800266int delete_cache(const char *pkgname)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267{
268 char cachedir[PKG_PATH_MAX];
269
Kenny Root86c95842011-03-31 13:16:12 -0700270 if (create_pkg_path(cachedir, pkgname, CACHE_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800271 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272
273 /* delete contents, not the directory, no exceptions */
274 return delete_dir_contents(cachedir, 0, 0);
275}
276
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277/* Try to ensure free_size bytes of storage are available.
278 * Returns 0 on success.
279 * This is rather simple-minded because doing a full LRU would
280 * be potentially memory-intensive, and without atime it would
281 * also require that apps constantly modify file metadata even
282 * when just reading from the cache, which is pretty awful.
283 */
Kenny Root3e319a92010-09-07 13:58:28 -0700284int free_cache(int64_t free_size)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285{
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700286 cache_t* cache;
287 int64_t avail;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288 DIR *d;
289 struct dirent *de;
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700290 char tmpdir[PATH_MAX];
291 char *dirpos;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800292
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700293 avail = data_disk_free();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294 if (avail < 0) return -1;
295
Steve Block6215d3f2012-01-04 20:05:49 +0000296 ALOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297 if (avail >= free_size) return 0;
298
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700299 cache = start_cache_collection();
300
301 // Collect cache files for primary user.
302 if (create_persona_path(tmpdir, 0) == 0) {
303 //ALOGI("adding cache files from %s\n", tmpdir);
304 add_cache_files(cache, tmpdir, "cache");
Kenny Rootad757e92011-11-29 15:54:55 -0800305 }
306
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700307 // Search for other users and add any cache files from them.
308 snprintf(tmpdir, sizeof(tmpdir), "%s%s", android_data_dir.path,
309 SECONDARY_USER_PREFIX);
310 dirpos = tmpdir + strlen(tmpdir);
311 d = opendir(tmpdir);
312 if (d != NULL) {
313 while ((de = readdir(d))) {
314 if (de->d_type == DT_DIR) {
315 const char *name = de->d_name;
316 /* always skip "." and ".." */
317 if (name[0] == '.') {
318 if (name[1] == 0) continue;
319 if ((name[1] == '.') && (name[2] == 0)) continue;
320 }
321 if ((strlen(name)+(dirpos-tmpdir)) < (sizeof(tmpdir)-1)) {
322 strcpy(dirpos, name);
323 //ALOGI("adding cache files from %s\n", tmpdir);
324 add_cache_files(cache, tmpdir, "cache");
325 } else {
326 ALOGW("Path exceeds limit: %s%s", tmpdir, name);
327 }
328 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 }
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700330 closedir(d);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331 }
Oscar Montemayora8529f62009-11-18 10:14:20 -0800332
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700333 // Collect cache files on external storage (if it is mounted as part
334 // of the internal storage).
335 strcpy(tmpdir, android_media_dir.path);
336 if (lookup_media_dir(tmpdir, "Android") == 0
337 && lookup_media_dir(tmpdir, "data") == 0) {
338 //ALOGI("adding cache files from %s\n", tmpdir);
339 add_cache_files(cache, tmpdir, "cache");
340 }
341
342 clear_cache_files(cache, free_size);
343 finish_cache_collection(cache);
344
345 return data_disk_free() >= free_size ? 0 : -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346}
347
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348int move_dex(const char *src, const char *dst)
349{
350 char src_dex[PKG_PATH_MAX];
351 char dst_dex[PKG_PATH_MAX];
352
Kenny Root86c95842011-03-31 13:16:12 -0700353 if (validate_apk_path(src)) return -1;
354 if (validate_apk_path(dst)) return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355
356 if (create_cache_path(src_dex, src)) return -1;
357 if (create_cache_path(dst_dex, dst)) return -1;
358
Steve Block71f2cf12011-10-20 11:56:00 +0100359 ALOGV("move %s -> %s\n", src_dex, dst_dex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800360 if (rename(src_dex, dst_dex) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000361 ALOGE("Couldn't move %s: %s\n", src_dex, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362 return -1;
363 } else {
364 return 0;
365 }
366}
367
368int rm_dex(const char *path)
369{
370 char dex_path[PKG_PATH_MAX];
371
Kenny Root86c95842011-03-31 13:16:12 -0700372 if (validate_apk_path(path)) return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 if (create_cache_path(dex_path, path)) return -1;
374
Steve Block71f2cf12011-10-20 11:56:00 +0100375 ALOGV("unlink %s\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376 if (unlink(dex_path) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000377 ALOGE("Couldn't unlink %s: %s\n", dex_path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378 return -1;
379 } else {
380 return 0;
381 }
382}
383
384int protect(char *pkgname, gid_t gid)
385{
386 struct stat s;
387 char pkgpath[PKG_PATH_MAX];
388
389 if (gid < AID_SYSTEM) return -1;
390
Kenny Root86c95842011-03-31 13:16:12 -0700391 if (create_pkg_path_in_dir(pkgpath, &android_app_private_dir, pkgname, ".apk"))
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392 return -1;
393
394 if (stat(pkgpath, &s) < 0) return -1;
395
396 if (chown(pkgpath, s.st_uid, gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000397 ALOGE("failed to chgrp '%s': %s\n", pkgpath, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 return -1;
399 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 if (chmod(pkgpath, S_IRUSR|S_IWUSR|S_IRGRP) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000401 ALOGE("failed to chmod '%s': %s\n", pkgpath, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 return -1;
403 }
404
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500405#ifdef HAVE_SELINUX
406 if (selinux_android_setfilecon(pkgpath, pkgname, s.st_uid) < 0) {
407 LOGE("cannot setfilecon dir '%s': %s\n", pkgpath, strerror(errno));
408 return -1;
409 }
410#endif
411
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800412 return 0;
413}
414
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415int get_size(const char *pkgname, const char *apkpath,
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700416 const char *fwdlock_apkpath, const char *asecpath,
417 int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize,
418 int64_t* _asecsize)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419{
420 DIR *d;
421 int dfd;
422 struct dirent *de;
423 struct stat s;
424 char path[PKG_PATH_MAX];
425
Kenny Root3e319a92010-09-07 13:58:28 -0700426 int64_t codesize = 0;
427 int64_t datasize = 0;
428 int64_t cachesize = 0;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700429 int64_t asecsize = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430
431 /* count the source apk as code -- but only if it's not
Suchi Amalapurapu8a9ab242010-03-11 16:49:16 -0800432 * on the /system partition and its not on the sdcard.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433 */
Kenny Root86c95842011-03-31 13:16:12 -0700434 if (validate_system_app_path(apkpath) &&
435 strncmp(apkpath, android_asec_dir.path, android_asec_dir.len) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 if (stat(apkpath, &s) == 0) {
437 codesize += stat_size(&s);
438 }
439 }
440 /* count the forward locked apk as code if it is given
441 */
442 if (fwdlock_apkpath != NULL && fwdlock_apkpath[0] != '!') {
443 if (stat(fwdlock_apkpath, &s) == 0) {
444 codesize += stat_size(&s);
445 }
446 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447 /* count the cached dexfile as code */
448 if (!create_cache_path(path, apkpath)) {
449 if (stat(path, &s) == 0) {
450 codesize += stat_size(&s);
451 }
452 }
453
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700454 /* compute asec size if it is given
455 */
456 if (asecpath != NULL && asecpath[0] != '!') {
457 if (stat(asecpath, &s) == 0) {
458 asecsize += stat_size(&s);
459 }
460 }
461
Kenny Root86c95842011-03-31 13:16:12 -0700462 if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, 0)) {
Kenny Root35ab3ad2011-02-02 16:42:14 -0800463 goto done;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464 }
465
466 d = opendir(path);
467 if (d == NULL) {
468 goto done;
469 }
470 dfd = dirfd(d);
471
Kenny Root86c95842011-03-31 13:16:12 -0700472 /* most stuff in the pkgdir is data, except for the "cache"
473 * directory and below, which is cache, and the "lib" directory
474 * and below, which is code...
475 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 while ((de = readdir(d))) {
477 const char *name = de->d_name;
478
479 if (de->d_type == DT_DIR) {
480 int subfd;
481 /* always skip "." and ".." */
482 if (name[0] == '.') {
483 if (name[1] == 0) continue;
484 if ((name[1] == '.') && (name[2] == 0)) continue;
485 }
486 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
487 if (subfd >= 0) {
Kenny Root3e319a92010-09-07 13:58:28 -0700488 int64_t size = calculate_dir_size(subfd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 if (!strcmp(name,"lib")) {
490 codesize += size;
491 } else if(!strcmp(name,"cache")) {
492 cachesize += size;
493 } else {
494 datasize += size;
495 }
496 }
497 } else {
498 if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
499 datasize += stat_size(&s);
500 }
501 }
502 }
503 closedir(d);
504done:
505 *_codesize = codesize;
506 *_datasize = datasize;
507 *_cachesize = cachesize;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700508 *_asecsize = asecsize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509 return 0;
510}
511
512
513/* a simpler version of dexOptGenerateCacheFileName() */
514int create_cache_path(char path[PKG_PATH_MAX], const char *src)
515{
516 char *tmp;
517 int srclen;
518 int dstlen;
519
520 srclen = strlen(src);
521
522 /* demand that we are an absolute path */
523 if ((src == 0) || (src[0] != '/') || strstr(src,"..")) {
524 return -1;
525 }
526
527 if (srclen > PKG_PATH_MAX) { // XXX: PKG_NAME_MAX?
528 return -1;
529 }
530
531 dstlen = srclen + strlen(DALVIK_CACHE_PREFIX) +
532 strlen(DALVIK_CACHE_POSTFIX) + 1;
533
534 if (dstlen > PKG_PATH_MAX) {
535 return -1;
536 }
537
538 sprintf(path,"%s%s%s",
539 DALVIK_CACHE_PREFIX,
540 src + 1, /* skip the leading / */
541 DALVIK_CACHE_POSTFIX);
542
543 for(tmp = path + strlen(DALVIK_CACHE_PREFIX); *tmp; tmp++) {
544 if (*tmp == '/') {
545 *tmp = '@';
546 }
547 }
548
549 return 0;
550}
551
552static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name,
553 const char* dexopt_flags)
554{
555 static const char* DEX_OPT_BIN = "/system/bin/dexopt";
556 static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
557 char zip_num[MAX_INT_LEN];
558 char odex_num[MAX_INT_LEN];
559
560 sprintf(zip_num, "%d", zip_fd);
561 sprintf(odex_num, "%d", odex_fd);
562
563 execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name,
564 dexopt_flags, (char*) NULL);
Steve Block3762c312012-01-06 19:20:56 +0000565 ALOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566}
567
568static int wait_dexopt(pid_t pid, const char* apk_path)
569{
570 int status;
571 pid_t got_pid;
572
573 /*
574 * Wait for the optimization process to finish.
575 */
576 while (1) {
577 got_pid = waitpid(pid, &status, 0);
578 if (got_pid == -1 && errno == EINTR) {
579 printf("waitpid interrupted, retrying\n");
580 } else {
581 break;
582 }
583 }
584 if (got_pid != pid) {
Steve Block8564c8d2012-01-05 23:22:43 +0000585 ALOGW("waitpid failed: wanted %d, got %d: %s\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 (int) pid, (int) got_pid, strerror(errno));
587 return 1;
588 }
589
590 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100591 ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800592 return 0;
593 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000594 ALOGW("DexInv: --- END '%s' --- status=0x%04x, process failed\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595 apk_path, status);
596 return status; /* always nonzero */
597 }
598}
599
600int dexopt(const char *apk_path, uid_t uid, int is_public)
601{
602 struct utimbuf ut;
603 struct stat apk_stat, dex_stat;
604 char dex_path[PKG_PATH_MAX];
605 char dexopt_flags[PROPERTY_VALUE_MAX];
606 char *end;
607 int res, zip_fd=-1, odex_fd=-1;
608
609 /* Before anything else: is there a .odex file? If so, we have
610 * pre-optimized the apk and there is nothing to do here.
611 */
612 if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
613 return -1;
614 }
615
616 /* platform-specific flags affecting optimization and verification */
617 property_get("dalvik.vm.dexopt-flags", dexopt_flags, "");
618
619 strcpy(dex_path, apk_path);
620 end = strrchr(dex_path, '.');
621 if (end != NULL) {
622 strcpy(end, ".odex");
623 if (stat(dex_path, &dex_stat) == 0) {
624 return 0;
625 }
626 }
627
628 if (create_cache_path(dex_path, apk_path)) {
629 return -1;
630 }
631
632 memset(&apk_stat, 0, sizeof(apk_stat));
633 stat(apk_path, &apk_stat);
634
635 zip_fd = open(apk_path, O_RDONLY, 0);
636 if (zip_fd < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000637 ALOGE("dexopt cannot open '%s' for input\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800638 return -1;
639 }
640
641 unlink(dex_path);
642 odex_fd = open(dex_path, O_RDWR | O_CREAT | O_EXCL, 0644);
643 if (odex_fd < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000644 ALOGE("dexopt cannot open '%s' for output\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800645 goto fail;
646 }
647 if (fchown(odex_fd, AID_SYSTEM, uid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000648 ALOGE("dexopt cannot chown '%s'\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800649 goto fail;
650 }
651 if (fchmod(odex_fd,
652 S_IRUSR|S_IWUSR|S_IRGRP |
653 (is_public ? S_IROTH : 0)) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000654 ALOGE("dexopt cannot chmod '%s'\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800655 goto fail;
656 }
657
Steve Block71f2cf12011-10-20 11:56:00 +0100658 ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659
660 pid_t pid;
661 pid = fork();
662 if (pid == 0) {
663 /* child -- drop privileges before continuing */
664 if (setgid(uid) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000665 ALOGE("setgid(%d) failed during dexopt\n", uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800666 exit(64);
667 }
668 if (setuid(uid) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000669 ALOGE("setuid(%d) during dexopt\n", uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800670 exit(65);
671 }
672 if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000673 ALOGE("flock(%s) failed: %s\n", dex_path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800674 exit(66);
675 }
676
677 run_dexopt(zip_fd, odex_fd, apk_path, dexopt_flags);
678 exit(67); /* only get here on exec failure */
679 } else {
680 res = wait_dexopt(pid, apk_path);
681 if (res != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000682 ALOGE("dexopt failed on '%s' res = %d\n", dex_path, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683 goto fail;
684 }
685 }
686
687 ut.actime = apk_stat.st_atime;
688 ut.modtime = apk_stat.st_mtime;
689 utime(dex_path, &ut);
690
691 close(odex_fd);
692 close(zip_fd);
693 return 0;
694
695fail:
696 if (odex_fd >= 0) {
697 close(odex_fd);
698 unlink(dex_path);
699 }
700 if (zip_fd >= 0) {
701 close(zip_fd);
702 }
703 return -1;
704}
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800705
Dianne Hackbornc1552392010-03-03 16:19:01 -0800706void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid,
707 struct stat* statbuf)
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800708{
709 while (path[basepos] != 0) {
710 if (path[basepos] == '/') {
711 path[basepos] = 0;
Dianne Hackbornc1552392010-03-03 16:19:01 -0800712 if (lstat(path, statbuf) < 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100713 ALOGV("Making directory: %s\n", path);
Dianne Hackbornc1552392010-03-03 16:19:01 -0800714 if (mkdir(path, mode) == 0) {
715 chown(path, uid, gid);
716 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000717 ALOGW("Unable to make directory %s: %s\n", path, strerror(errno));
Dianne Hackbornc1552392010-03-03 16:19:01 -0800718 }
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800719 }
720 path[basepos] = '/';
721 basepos++;
722 }
723 basepos++;
724 }
725}
726
Dianne Hackbornc1552392010-03-03 16:19:01 -0800727int movefileordir(char* srcpath, char* dstpath, int dstbasepos,
728 int dstuid, int dstgid, struct stat* statbuf)
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800729{
730 DIR *d;
731 struct dirent *de;
732 int res;
733
734 int srcend = strlen(srcpath);
735 int dstend = strlen(dstpath);
736
737 if (lstat(srcpath, statbuf) < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000738 ALOGW("Unable to stat %s: %s\n", srcpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800739 return 1;
740 }
741
742 if ((statbuf->st_mode&S_IFDIR) == 0) {
Dianne Hackbornc1552392010-03-03 16:19:01 -0800743 mkinnerdirs(dstpath, dstbasepos, S_IRWXU|S_IRWXG|S_IXOTH,
744 dstuid, dstgid, statbuf);
Steve Block71f2cf12011-10-20 11:56:00 +0100745 ALOGV("Renaming %s to %s (uid %d)\n", srcpath, dstpath, dstuid);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800746 if (rename(srcpath, dstpath) >= 0) {
747 if (chown(dstpath, dstuid, dstgid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000748 ALOGE("cannot chown %s: %s\n", dstpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800749 unlink(dstpath);
750 return 1;
751 }
752 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000753 ALOGW("Unable to rename %s to %s: %s\n",
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800754 srcpath, dstpath, strerror(errno));
755 return 1;
756 }
757 return 0;
758 }
759
760 d = opendir(srcpath);
761 if (d == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000762 ALOGW("Unable to opendir %s: %s\n", srcpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800763 return 1;
764 }
765
766 res = 0;
767
768 while ((de = readdir(d))) {
769 const char *name = de->d_name;
770 /* always skip "." and ".." */
771 if (name[0] == '.') {
772 if (name[1] == 0) continue;
773 if ((name[1] == '.') && (name[2] == 0)) continue;
774 }
775
776 if ((srcend+strlen(name)) >= (PKG_PATH_MAX-2)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000777 ALOGW("Source path too long; skipping: %s/%s\n", srcpath, name);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800778 continue;
779 }
780
781 if ((dstend+strlen(name)) >= (PKG_PATH_MAX-2)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000782 ALOGW("Destination path too long; skipping: %s/%s\n", dstpath, name);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800783 continue;
784 }
785
786 srcpath[srcend] = dstpath[dstend] = '/';
787 strcpy(srcpath+srcend+1, name);
788 strcpy(dstpath+dstend+1, name);
789
Dianne Hackbornc1552392010-03-03 16:19:01 -0800790 if (movefileordir(srcpath, dstpath, dstbasepos, dstuid, dstgid, statbuf) != 0) {
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800791 res = 1;
792 }
793
794 // Note: we will be leaving empty directories behind in srcpath,
795 // but that is okay, the package manager will be erasing all of the
796 // data associated with .apks that disappear.
797
798 srcpath[srcend] = dstpath[dstend] = 0;
799 }
800
801 closedir(d);
802 return res;
803}
804
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800805int movefiles()
806{
807 DIR *d;
808 int dfd, subfd;
809 struct dirent *de;
810 struct stat s;
811 char buf[PKG_PATH_MAX+1];
812 int bufp, bufe, bufi, readlen;
813
814 char srcpkg[PKG_NAME_MAX];
815 char dstpkg[PKG_NAME_MAX];
816 char srcpath[PKG_PATH_MAX];
817 char dstpath[PKG_PATH_MAX];
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800818 int dstuid=-1, dstgid=-1;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800819 int hasspace;
820
821 d = opendir(UPDATE_COMMANDS_DIR_PREFIX);
822 if (d == NULL) {
823 goto done;
824 }
825 dfd = dirfd(d);
826
827 /* Iterate through all files in the directory, executing the
828 * file movements requested there-in.
829 */
830 while ((de = readdir(d))) {
831 const char *name = de->d_name;
832
833 if (de->d_type == DT_DIR) {
834 continue;
835 } else {
836 subfd = openat(dfd, name, O_RDONLY);
837 if (subfd < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000838 ALOGW("Unable to open update commands at %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800839 UPDATE_COMMANDS_DIR_PREFIX, name);
840 continue;
841 }
842
843 bufp = 0;
844 bufe = 0;
845 buf[PKG_PATH_MAX] = 0;
846 srcpkg[0] = dstpkg[0] = 0;
847 while (1) {
848 bufi = bufp;
849 while (bufi < bufe && buf[bufi] != '\n') {
850 bufi++;
851 }
852 if (bufi < bufe) {
853 buf[bufi] = 0;
Steve Block71f2cf12011-10-20 11:56:00 +0100854 ALOGV("Processing line: %s\n", buf+bufp);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800855 hasspace = 0;
856 while (bufp < bufi && isspace(buf[bufp])) {
857 hasspace = 1;
858 bufp++;
859 }
860 if (buf[bufp] == '#' || bufp == bufi) {
861 // skip comments and empty lines.
862 } else if (hasspace) {
863 if (dstpkg[0] == 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000864 ALOGW("Path before package line in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800865 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
866 } else if (srcpkg[0] == 0) {
867 // Skip -- source package no longer exists.
868 } else {
Steve Block71f2cf12011-10-20 11:56:00 +0100869 ALOGV("Move file: %s (from %s to %s)\n", buf+bufp, srcpkg, dstpkg);
Kenny Root86c95842011-03-31 13:16:12 -0700870 if (!create_move_path(srcpath, srcpkg, buf+bufp, 0) &&
871 !create_move_path(dstpath, dstpkg, buf+bufp, 0)) {
Dianne Hackbornc1552392010-03-03 16:19:01 -0800872 movefileordir(srcpath, dstpath,
873 strlen(dstpath)-strlen(buf+bufp),
874 dstuid, dstgid, &s);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800875 }
876 }
877 } else {
878 char* div = strchr(buf+bufp, ':');
879 if (div == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000880 ALOGW("Bad package spec in %s%s; no ':' sep: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800881 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
882 } else {
883 *div = 0;
884 div++;
885 if (strlen(buf+bufp) < PKG_NAME_MAX) {
886 strcpy(dstpkg, buf+bufp);
887 } else {
888 srcpkg[0] = dstpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000889 ALOGW("Package name too long in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800890 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
891 }
892 if (strlen(div) < PKG_NAME_MAX) {
893 strcpy(srcpkg, div);
894 } else {
895 srcpkg[0] = dstpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000896 ALOGW("Package name too long in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800897 UPDATE_COMMANDS_DIR_PREFIX, name, div);
898 }
899 if (srcpkg[0] != 0) {
Kenny Root86c95842011-03-31 13:16:12 -0700900 if (!create_pkg_path(srcpath, srcpkg, PKG_DIR_POSTFIX, 0)) {
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800901 if (lstat(srcpath, &s) < 0) {
902 // Package no longer exists -- skip.
903 srcpkg[0] = 0;
904 }
905 } else {
906 srcpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000907 ALOGW("Can't create path %s in %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800908 div, UPDATE_COMMANDS_DIR_PREFIX, name);
909 }
910 if (srcpkg[0] != 0) {
Kenny Root86c95842011-03-31 13:16:12 -0700911 if (!create_pkg_path(dstpath, dstpkg, PKG_DIR_POSTFIX, 0)) {
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800912 if (lstat(dstpath, &s) == 0) {
913 dstuid = s.st_uid;
914 dstgid = s.st_gid;
915 } else {
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800916 // Destination package doesn't
917 // exist... due to original-package,
918 // this is normal, so don't be
919 // noisy about it.
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800920 srcpkg[0] = 0;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800921 }
922 } else {
923 srcpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000924 ALOGW("Can't create path %s in %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800925 div, UPDATE_COMMANDS_DIR_PREFIX, name);
926 }
927 }
Steve Block71f2cf12011-10-20 11:56:00 +0100928 ALOGV("Transfering from %s to %s: uid=%d\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800929 srcpkg, dstpkg, dstuid);
930 }
931 }
932 }
933 bufp = bufi+1;
934 } else {
935 if (bufp == 0) {
936 if (bufp < bufe) {
Steve Block8564c8d2012-01-05 23:22:43 +0000937 ALOGW("Line too long in %s%s, skipping: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800938 UPDATE_COMMANDS_DIR_PREFIX, name, buf);
939 }
940 } else if (bufp < bufe) {
941 memcpy(buf, buf+bufp, bufe-bufp);
942 bufe -= bufp;
943 bufp = 0;
944 }
945 readlen = read(subfd, buf+bufe, PKG_PATH_MAX-bufe);
946 if (readlen < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000947 ALOGW("Failure reading update commands in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800948 UPDATE_COMMANDS_DIR_PREFIX, name, strerror(errno));
949 break;
950 } else if (readlen == 0) {
951 break;
952 }
953 bufe += readlen;
954 buf[bufe] = 0;
Steve Block71f2cf12011-10-20 11:56:00 +0100955 ALOGV("Read buf: %s\n", buf);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800956 }
957 }
958 close(subfd);
959 }
960 }
961 closedir(d);
962done:
963 return 0;
964}
Kenny Root6a6b0072010-10-07 16:46:10 -0700965
966int linklib(const char* dataDir, const char* asecLibDir)
967{
968 char libdir[PKG_PATH_MAX];
969 struct stat s, libStat;
970 int rc = 0;
971
972 const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
973 if (libdirLen >= PKG_PATH_MAX) {
Steve Block3762c312012-01-06 19:20:56 +0000974 ALOGE("library dir len too large");
Kenny Root0332d1c2010-10-21 16:14:06 -0700975 return -1;
Kenny Root6a6b0072010-10-07 16:46:10 -0700976 }
977
978 if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
Steve Block3762c312012-01-06 19:20:56 +0000979 ALOGE("library dir not written successfully: %s\n", strerror(errno));
Kenny Root0332d1c2010-10-21 16:14:06 -0700980 return -1;
Kenny Root6a6b0072010-10-07 16:46:10 -0700981 }
982
983 if (stat(dataDir, &s) < 0) return -1;
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 (symlink(asecLibDir, libdir) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001015 ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libdir, asecLibDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001016 rc = -errno;
1017 goto out;
1018 }
1019
1020 if (lchown(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));
Dianne Hackbornd0c5f512012-06-07 16:53:59 -07001030 rc = -errno;
Kenny Root6a6b0072010-10-07 16:46:10 -07001031 }
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 -errno;
1036 }
1037
1038 return rc;
1039}
1040
1041int unlinklib(const char* dataDir)
1042{
1043 char libdir[PKG_PATH_MAX];
1044 struct stat s, libStat;
1045 int rc = 0;
1046
1047 const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
1048 if (libdirLen >= PKG_PATH_MAX) {
1049 return -1;
1050 }
1051
1052 if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
Steve Block3762c312012-01-06 19:20:56 +00001053 ALOGE("library dir not written successfully: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001054 return -1;
1055 }
1056
1057 if (stat(dataDir, &s) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001058 ALOGE("couldn't state data dir");
Kenny Root6a6b0072010-10-07 16:46:10 -07001059 return -1;
1060 }
1061
1062 if (chown(dataDir, 0, 0) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001063 ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001064 return -1;
1065 }
1066
1067 if (chmod(dataDir, 0700) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001068 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001069 rc = -1;
1070 goto out;
1071 }
1072
1073 if (lstat(libdir, &libStat) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001074 ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001075 rc = -1;
1076 goto out;
1077 }
1078
1079 if (S_ISDIR(libStat.st_mode)) {
1080 if (delete_dir_contents(libdir, 1, 0) < 0) {
1081 rc = -1;
1082 goto out;
1083 }
1084 } else if (S_ISLNK(libStat.st_mode)) {
1085 if (unlink(libdir) < 0) {
1086 rc = -1;
1087 goto out;
1088 }
1089 }
1090
1091 if (mkdir(libdir, 0755) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001092 ALOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001093 rc = -errno;
1094 goto out;
1095 }
1096
1097 if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001098 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001099 unlink(libdir);
1100 rc = -errno;
1101 goto out;
1102 }
1103
1104out:
1105 if (chmod(dataDir, s.st_mode) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001106 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Dianne Hackbornd0c5f512012-06-07 16:53:59 -07001107 rc = -1;
Kenny Root6a6b0072010-10-07 16:46:10 -07001108 }
1109
1110 if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001111 ALOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001112 return -1;
1113 }
1114
1115 return rc;
1116}