blob: 2934261148709e820eab9013466792c21e9aecff [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
Nick Kralevich812b19a2012-08-31 16:08:06 -070017#include <linux/capability.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018#include "installd.h"
Kenny Root33b22642010-11-30 13:49:32 -080019#include <diskusage/dirsize.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020
Stephen Smalley0b58e6a2012-01-13 08:27:42 -050021#ifdef HAVE_SELINUX
22#include <selinux/android.h>
23#endif
24
Kenny Root86c95842011-03-31 13:16:12 -070025/* Directory records that are used in execution of commands. */
26dir_rec_t android_data_dir;
27dir_rec_t android_asec_dir;
28dir_rec_t android_app_dir;
29dir_rec_t android_app_private_dir;
Kenny Root9bbd70a2012-09-10 11:13:36 -070030dir_rec_t android_app_lib_dir;
Dianne Hackborn197a0c82012-07-12 14:46:04 -070031dir_rec_t android_media_dir;
Kenny Root86c95842011-03-31 13:16:12 -070032dir_rec_array_t android_system_dirs;
33
Kenny Root35ab3ad2011-02-02 16:42:14 -080034int install(const char *pkgname, uid_t uid, gid_t gid)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035{
36 char pkgdir[PKG_PATH_MAX];
Kenny Root9bbd70a2012-09-10 11:13:36 -070037 char libsymlink[PKG_PATH_MAX];
38 char applibdir[PKG_PATH_MAX];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039
40 if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
Steve Block3762c312012-01-06 19:20:56 +000041 ALOGE("invalid uid/gid: %d %d\n", uid, gid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043 }
Oscar Montemayora8529f62009-11-18 10:14:20 -080044
Kenny Root86c95842011-03-31 13:16:12 -070045 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
Steve Block3762c312012-01-06 19:20:56 +000046 ALOGE("cannot create package path\n");
Kenny Root35ab3ad2011-02-02 16:42:14 -080047 return -1;
Kenny Root86c95842011-03-31 13:16:12 -070048 }
49
Kenny Root9bbd70a2012-09-10 11:13:36 -070050 if (create_pkg_path(libsymlink, pkgname, PKG_LIB_POSTFIX, 0)) {
51 ALOGE("cannot create package lib symlink origin path\n");
52 return -1;
53 }
54
55 if (create_pkg_path_in_dir(applibdir, &android_app_lib_dir, pkgname, PKG_DIR_POSTFIX)) {
56 ALOGE("cannot create package lib symlink dest path\n");
Kenny Root35ab3ad2011-02-02 16:42:14 -080057 return -1;
Kenny Root86c95842011-03-31 13:16:12 -070058 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059
David 'Digit' Turner0dd50e62010-02-09 19:02:38 -080060 if (mkdir(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000061 ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
Kenny Root9bbd70a2012-09-10 11:13:36 -070062 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063 }
Nick Kralevichf68327e2011-04-14 16:20:03 -070064 if (chmod(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000065 ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
Nick Kralevichf68327e2011-04-14 16:20:03 -070066 unlink(pkgdir);
Kenny Root9bbd70a2012-09-10 11:13:36 -070067 return -1;
Nick Kralevichf68327e2011-04-14 16:20:03 -070068 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -050069
Kenny Root9bbd70a2012-09-10 11:13:36 -070070 if (symlink(applibdir, libsymlink) < 0) {
71 ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libsymlink, applibdir,
72 strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073 unlink(pkgdir);
Kenny Root9bbd70a2012-09-10 11:13:36 -070074 return -1;
Kenny Root4503cf62012-06-14 13:05:18 -070075 }
Kenny Root33ef4ee2012-06-18 10:26:36 -070076
77#ifdef HAVE_SELINUX
78 if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
Joshua Brindle365861e2012-07-10 10:22:36 -040079 ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
Kenny Root9bbd70a2012-09-10 11:13:36 -070080 unlink(libsymlink);
Kenny Root33ef4ee2012-06-18 10:26:36 -070081 unlink(pkgdir);
Kenny Root9bbd70a2012-09-10 11:13:36 -070082 return -1;
Kenny Root33ef4ee2012-06-18 10:26:36 -070083 }
84#endif
85
Kenny Root9bbd70a2012-09-10 11:13:36 -070086 if (chown(pkgdir, uid, gid) < 0) {
87 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
88 unlink(libsymlink);
89 unlink(pkgdir);
90 return -1;
91 }
92
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 return 0;
94}
95
Amith Yamasani0b285492011-04-14 17:35:23 -070096int uninstall(const char *pkgname, uid_t persona)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097{
98 char pkgdir[PKG_PATH_MAX];
99
Amith Yamasani0b285492011-04-14 17:35:23 -0700100 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800101 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102
Amith Yamasani0b285492011-04-14 17:35:23 -0700103 /* delete contents AND directory, no exceptions */
104 return delete_dir_contents(pkgdir, 1, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105}
106
Kenny Root35ab3ad2011-02-02 16:42:14 -0800107int renamepkg(const char *oldpkgname, const char *newpkgname)
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800108{
109 char oldpkgdir[PKG_PATH_MAX];
110 char newpkgdir[PKG_PATH_MAX];
111
Kenny Root86c95842011-03-31 13:16:12 -0700112 if (create_pkg_path(oldpkgdir, oldpkgname, PKG_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800113 return -1;
Kenny Root86c95842011-03-31 13:16:12 -0700114 if (create_pkg_path(newpkgdir, newpkgname, PKG_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800115 return -1;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800116
117 if (rename(oldpkgdir, newpkgdir) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000118 ALOGE("cannot rename dir '%s' to '%s': %s\n", oldpkgdir, newpkgdir, strerror(errno));
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800119 return -errno;
120 }
121 return 0;
122}
123
Dianne Hackbornd0c5f512012-06-07 16:53:59 -0700124int fix_uid(const char *pkgname, uid_t uid, gid_t gid)
125{
126 char pkgdir[PKG_PATH_MAX];
127 struct stat s;
128 int rc = 0;
129
130 if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
131 ALOGE("invalid uid/gid: %d %d\n", uid, gid);
132 return -1;
133 }
134
135 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
136 ALOGE("cannot create package path\n");
137 return -1;
138 }
139
140 if (stat(pkgdir, &s) < 0) return -1;
141
142 if (s.st_uid != 0 || s.st_gid != 0) {
143 ALOGE("fixing uid of non-root pkg: %s %d %d\n", pkgdir, s.st_uid, s.st_gid);
144 return -1;
145 }
146
147 if (chmod(pkgdir, 0751) < 0) {
148 ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
149 unlink(pkgdir);
150 return -errno;
151 }
152 if (chown(pkgdir, uid, gid) < 0) {
153 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
154 unlink(pkgdir);
155 return -errno;
156 }
157
158 return 0;
159}
160
Amith Yamasani0b285492011-04-14 17:35:23 -0700161int delete_user_data(const char *pkgname, uid_t persona)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162{
163 char pkgdir[PKG_PATH_MAX];
164
Amith Yamasani0b285492011-04-14 17:35:23 -0700165 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800166 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167
Amith Yamasani0b285492011-04-14 17:35:23 -0700168 /* delete contents, excluding "lib", but not the directory itself */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169 return delete_dir_contents(pkgdir, 0, "lib");
170}
171
Amith Yamasani0b285492011-04-14 17:35:23 -0700172int make_user_data(const char *pkgname, uid_t uid, uid_t persona)
173{
174 char pkgdir[PKG_PATH_MAX];
Amith Yamasani0b285492011-04-14 17:35:23 -0700175
176 // Create the data dir for the package
177 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona)) {
178 return -1;
179 }
180 if (mkdir(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000181 ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
Amith Yamasani0b285492011-04-14 17:35:23 -0700182 return -errno;
183 }
Amith Yamasani794d62f2012-08-24 12:58:27 -0700184 if (chmod(pkgdir, 0751) < 0) {
185 ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
186 unlink(pkgdir);
187 return -errno;
188 }
Amith Yamasani0b285492011-04-14 17:35:23 -0700189 if (chown(pkgdir, uid, uid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000190 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
Amith Yamasani0b285492011-04-14 17:35:23 -0700191 unlink(pkgdir);
192 return -errno;
193 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500194
195#ifdef HAVE_SELINUX
196 if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
Joshua Brindle365861e2012-07-10 10:22:36 -0400197 ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500198 unlink(pkgdir);
199 return -errno;
200 }
201#endif
202
Amith Yamasani0b285492011-04-14 17:35:23 -0700203 return 0;
204}
205
206int delete_persona(uid_t persona)
207{
Jeff Sharkey5b1ada22012-08-14 18:47:09 -0700208 char data_path[PKG_PATH_MAX];
209 if (create_persona_path(data_path, persona)) {
Amith Yamasani0b285492011-04-14 17:35:23 -0700210 return -1;
Jeff Sharkey5b1ada22012-08-14 18:47:09 -0700211 }
212 if (delete_dir_contents(data_path, 1, NULL)) {
213 return -1;
214 }
Amith Yamasani0b285492011-04-14 17:35:23 -0700215
Jeff Sharkey5b1ada22012-08-14 18:47:09 -0700216 char media_path[PATH_MAX];
217 if (create_persona_media_path(media_path, (userid_t) persona) == -1) {
218 return -1;
219 }
220 if (delete_dir_contents(media_path, 1, NULL) == -1) {
221 return -1;
222 }
223
224 return 0;
Amith Yamasani0b285492011-04-14 17:35:23 -0700225}
226
Amith Yamasani742a6712011-05-04 14:49:28 -0700227int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy)
228{
229 char src_data_dir[PKG_PATH_MAX];
230 char pkg_path[PKG_PATH_MAX];
231 DIR *d;
232 struct dirent *de;
233 struct stat s;
234 uid_t uid;
235
236 if (create_persona_path(src_data_dir, src_persona)) {
237 return -1;
238 }
239
240 d = opendir(src_data_dir);
241 if (d != NULL) {
242 while ((de = readdir(d))) {
243 const char *name = de->d_name;
244
245 if (de->d_type == DT_DIR) {
246 int subfd;
247 /* always skip "." and ".." */
248 if (name[0] == '.') {
249 if (name[1] == 0) continue;
250 if ((name[1] == '.') && (name[2] == 0)) continue;
251 }
252 /* Create the full path to the package's data dir */
253 create_pkg_path(pkg_path, name, PKG_DIR_POSTFIX, src_persona);
254 /* Get the file stat */
255 if (stat(pkg_path, &s) < 0) continue;
256 /* Get the uid of the package */
257 ALOGI("Adding datadir for uid = %d\n", s.st_uid);
258 uid = (uid_t) s.st_uid % PER_USER_RANGE;
259 /* Create the directory for the target */
260 make_user_data(name, uid + target_persona * PER_USER_RANGE,
261 target_persona);
262 }
263 }
264 closedir(d);
265 }
Jeff Sharkey5b1ada22012-08-14 18:47:09 -0700266
Jeff Sharkey8ea0dc62012-08-27 15:46:54 -0700267 if (ensure_media_user_dirs((userid_t) target_persona) == -1) {
Jeff Sharkey5b1ada22012-08-14 18:47:09 -0700268 return -1;
269 }
Jeff Sharkey8ea0dc62012-08-27 15:46:54 -0700270
Amith Yamasani742a6712011-05-04 14:49:28 -0700271 return 0;
272}
273
Kenny Root35ab3ad2011-02-02 16:42:14 -0800274int delete_cache(const char *pkgname)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275{
276 char cachedir[PKG_PATH_MAX];
277
Kenny Root86c95842011-03-31 13:16:12 -0700278 if (create_pkg_path(cachedir, pkgname, CACHE_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800279 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280
281 /* delete contents, not the directory, no exceptions */
282 return delete_dir_contents(cachedir, 0, 0);
283}
284
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285/* Try to ensure free_size bytes of storage are available.
286 * Returns 0 on success.
287 * This is rather simple-minded because doing a full LRU would
288 * be potentially memory-intensive, and without atime it would
289 * also require that apps constantly modify file metadata even
290 * when just reading from the cache, which is pretty awful.
291 */
Kenny Root3e319a92010-09-07 13:58:28 -0700292int free_cache(int64_t free_size)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800293{
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700294 cache_t* cache;
295 int64_t avail;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296 DIR *d;
297 struct dirent *de;
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700298 char tmpdir[PATH_MAX];
299 char *dirpos;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700301 avail = data_disk_free();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302 if (avail < 0) return -1;
303
Steve Block6215d3f2012-01-04 20:05:49 +0000304 ALOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305 if (avail >= free_size) return 0;
306
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700307 cache = start_cache_collection();
308
309 // Collect cache files for primary user.
310 if (create_persona_path(tmpdir, 0) == 0) {
311 //ALOGI("adding cache files from %s\n", tmpdir);
312 add_cache_files(cache, tmpdir, "cache");
Kenny Rootad757e92011-11-29 15:54:55 -0800313 }
314
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700315 // Search for other users and add any cache files from them.
316 snprintf(tmpdir, sizeof(tmpdir), "%s%s", android_data_dir.path,
317 SECONDARY_USER_PREFIX);
318 dirpos = tmpdir + strlen(tmpdir);
319 d = opendir(tmpdir);
320 if (d != NULL) {
321 while ((de = readdir(d))) {
322 if (de->d_type == DT_DIR) {
323 const char *name = de->d_name;
324 /* always skip "." and ".." */
325 if (name[0] == '.') {
326 if (name[1] == 0) continue;
327 if ((name[1] == '.') && (name[2] == 0)) continue;
328 }
329 if ((strlen(name)+(dirpos-tmpdir)) < (sizeof(tmpdir)-1)) {
330 strcpy(dirpos, name);
331 //ALOGI("adding cache files from %s\n", tmpdir);
332 add_cache_files(cache, tmpdir, "cache");
333 } else {
334 ALOGW("Path exceeds limit: %s%s", tmpdir, name);
335 }
336 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 }
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700338 closedir(d);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 }
Oscar Montemayora8529f62009-11-18 10:14:20 -0800340
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700341 // Collect cache files on external storage (if it is mounted as part
342 // of the internal storage).
343 strcpy(tmpdir, android_media_dir.path);
344 if (lookup_media_dir(tmpdir, "Android") == 0
345 && lookup_media_dir(tmpdir, "data") == 0) {
346 //ALOGI("adding cache files from %s\n", tmpdir);
347 add_cache_files(cache, tmpdir, "cache");
348 }
349
350 clear_cache_files(cache, free_size);
351 finish_cache_collection(cache);
352
353 return data_disk_free() >= free_size ? 0 : -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354}
355
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356int move_dex(const char *src, const char *dst)
357{
358 char src_dex[PKG_PATH_MAX];
359 char dst_dex[PKG_PATH_MAX];
360
Kenny Root86c95842011-03-31 13:16:12 -0700361 if (validate_apk_path(src)) return -1;
362 if (validate_apk_path(dst)) return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363
364 if (create_cache_path(src_dex, src)) return -1;
365 if (create_cache_path(dst_dex, dst)) return -1;
366
Steve Block71f2cf12011-10-20 11:56:00 +0100367 ALOGV("move %s -> %s\n", src_dex, dst_dex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368 if (rename(src_dex, dst_dex) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000369 ALOGE("Couldn't move %s: %s\n", src_dex, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 return -1;
371 } else {
372 return 0;
373 }
374}
375
376int rm_dex(const char *path)
377{
378 char dex_path[PKG_PATH_MAX];
379
Kenny Root86c95842011-03-31 13:16:12 -0700380 if (validate_apk_path(path)) return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381 if (create_cache_path(dex_path, path)) return -1;
382
Steve Block71f2cf12011-10-20 11:56:00 +0100383 ALOGV("unlink %s\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 if (unlink(dex_path) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000385 ALOGE("Couldn't unlink %s: %s\n", dex_path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 return -1;
387 } else {
388 return 0;
389 }
390}
391
Dianne Hackborn0c380492012-08-20 17:23:30 -0700392int get_size(const char *pkgname, int persona, const char *apkpath,
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700393 const char *fwdlock_apkpath, const char *asecpath,
394 int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize,
395 int64_t* _asecsize)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396{
397 DIR *d;
398 int dfd;
399 struct dirent *de;
400 struct stat s;
401 char path[PKG_PATH_MAX];
402
Kenny Root3e319a92010-09-07 13:58:28 -0700403 int64_t codesize = 0;
404 int64_t datasize = 0;
405 int64_t cachesize = 0;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700406 int64_t asecsize = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407
408 /* count the source apk as code -- but only if it's not
Suchi Amalapurapu8a9ab242010-03-11 16:49:16 -0800409 * on the /system partition and its not on the sdcard.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410 */
Kenny Root86c95842011-03-31 13:16:12 -0700411 if (validate_system_app_path(apkpath) &&
412 strncmp(apkpath, android_asec_dir.path, android_asec_dir.len) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 if (stat(apkpath, &s) == 0) {
414 codesize += stat_size(&s);
415 }
416 }
417 /* count the forward locked apk as code if it is given
418 */
419 if (fwdlock_apkpath != NULL && fwdlock_apkpath[0] != '!') {
420 if (stat(fwdlock_apkpath, &s) == 0) {
421 codesize += stat_size(&s);
422 }
423 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 /* count the cached dexfile as code */
425 if (!create_cache_path(path, apkpath)) {
426 if (stat(path, &s) == 0) {
427 codesize += stat_size(&s);
428 }
429 }
430
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700431 /* compute asec size if it is given
432 */
433 if (asecpath != NULL && asecpath[0] != '!') {
434 if (stat(asecpath, &s) == 0) {
435 asecsize += stat_size(&s);
436 }
437 }
438
Dianne Hackborn0c380492012-08-20 17:23:30 -0700439 if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, persona)) {
Kenny Root35ab3ad2011-02-02 16:42:14 -0800440 goto done;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800441 }
442
443 d = opendir(path);
444 if (d == NULL) {
445 goto done;
446 }
447 dfd = dirfd(d);
448
Kenny Root86c95842011-03-31 13:16:12 -0700449 /* most stuff in the pkgdir is data, except for the "cache"
450 * directory and below, which is cache, and the "lib" directory
451 * and below, which is code...
452 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 while ((de = readdir(d))) {
454 const char *name = de->d_name;
455
456 if (de->d_type == DT_DIR) {
457 int subfd;
458 /* always skip "." and ".." */
459 if (name[0] == '.') {
460 if (name[1] == 0) continue;
461 if ((name[1] == '.') && (name[2] == 0)) continue;
462 }
463 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
464 if (subfd >= 0) {
Kenny Root3e319a92010-09-07 13:58:28 -0700465 int64_t size = calculate_dir_size(subfd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 if (!strcmp(name,"lib")) {
467 codesize += size;
468 } else if(!strcmp(name,"cache")) {
469 cachesize += size;
470 } else {
471 datasize += size;
472 }
473 }
474 } else {
475 if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
476 datasize += stat_size(&s);
477 }
478 }
479 }
480 closedir(d);
481done:
482 *_codesize = codesize;
483 *_datasize = datasize;
484 *_cachesize = cachesize;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700485 *_asecsize = asecsize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486 return 0;
487}
488
489
490/* a simpler version of dexOptGenerateCacheFileName() */
491int create_cache_path(char path[PKG_PATH_MAX], const char *src)
492{
493 char *tmp;
494 int srclen;
495 int dstlen;
496
497 srclen = strlen(src);
498
499 /* demand that we are an absolute path */
500 if ((src == 0) || (src[0] != '/') || strstr(src,"..")) {
501 return -1;
502 }
503
504 if (srclen > PKG_PATH_MAX) { // XXX: PKG_NAME_MAX?
505 return -1;
506 }
507
508 dstlen = srclen + strlen(DALVIK_CACHE_PREFIX) +
509 strlen(DALVIK_CACHE_POSTFIX) + 1;
510
511 if (dstlen > PKG_PATH_MAX) {
512 return -1;
513 }
514
515 sprintf(path,"%s%s%s",
516 DALVIK_CACHE_PREFIX,
517 src + 1, /* skip the leading / */
518 DALVIK_CACHE_POSTFIX);
519
520 for(tmp = path + strlen(DALVIK_CACHE_PREFIX); *tmp; tmp++) {
521 if (*tmp == '/') {
522 *tmp = '@';
523 }
524 }
525
526 return 0;
527}
528
529static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name,
530 const char* dexopt_flags)
531{
532 static const char* DEX_OPT_BIN = "/system/bin/dexopt";
533 static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
534 char zip_num[MAX_INT_LEN];
535 char odex_num[MAX_INT_LEN];
536
537 sprintf(zip_num, "%d", zip_fd);
538 sprintf(odex_num, "%d", odex_fd);
539
540 execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name,
541 dexopt_flags, (char*) NULL);
Steve Block3762c312012-01-06 19:20:56 +0000542 ALOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543}
544
545static int wait_dexopt(pid_t pid, const char* apk_path)
546{
547 int status;
548 pid_t got_pid;
549
550 /*
551 * Wait for the optimization process to finish.
552 */
553 while (1) {
554 got_pid = waitpid(pid, &status, 0);
555 if (got_pid == -1 && errno == EINTR) {
556 printf("waitpid interrupted, retrying\n");
557 } else {
558 break;
559 }
560 }
561 if (got_pid != pid) {
Steve Block8564c8d2012-01-05 23:22:43 +0000562 ALOGW("waitpid failed: wanted %d, got %d: %s\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800563 (int) pid, (int) got_pid, strerror(errno));
564 return 1;
565 }
566
567 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100568 ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569 return 0;
570 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000571 ALOGW("DexInv: --- END '%s' --- status=0x%04x, process failed\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 apk_path, status);
573 return status; /* always nonzero */
574 }
575}
576
577int dexopt(const char *apk_path, uid_t uid, int is_public)
578{
579 struct utimbuf ut;
580 struct stat apk_stat, dex_stat;
581 char dex_path[PKG_PATH_MAX];
582 char dexopt_flags[PROPERTY_VALUE_MAX];
583 char *end;
584 int res, zip_fd=-1, odex_fd=-1;
585
586 /* Before anything else: is there a .odex file? If so, we have
587 * pre-optimized the apk and there is nothing to do here.
588 */
589 if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
590 return -1;
591 }
592
593 /* platform-specific flags affecting optimization and verification */
594 property_get("dalvik.vm.dexopt-flags", dexopt_flags, "");
595
596 strcpy(dex_path, apk_path);
597 end = strrchr(dex_path, '.');
598 if (end != NULL) {
599 strcpy(end, ".odex");
600 if (stat(dex_path, &dex_stat) == 0) {
601 return 0;
602 }
603 }
604
605 if (create_cache_path(dex_path, apk_path)) {
606 return -1;
607 }
608
609 memset(&apk_stat, 0, sizeof(apk_stat));
610 stat(apk_path, &apk_stat);
611
612 zip_fd = open(apk_path, O_RDONLY, 0);
613 if (zip_fd < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000614 ALOGE("dexopt cannot open '%s' for input\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800615 return -1;
616 }
617
618 unlink(dex_path);
619 odex_fd = open(dex_path, O_RDWR | O_CREAT | O_EXCL, 0644);
620 if (odex_fd < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000621 ALOGE("dexopt cannot open '%s' for output\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800622 goto fail;
623 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800624 if (fchmod(odex_fd,
625 S_IRUSR|S_IWUSR|S_IRGRP |
626 (is_public ? S_IROTH : 0)) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000627 ALOGE("dexopt cannot chmod '%s'\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800628 goto fail;
629 }
Nick Kralevich812b19a2012-08-31 16:08:06 -0700630 if (fchown(odex_fd, AID_SYSTEM, uid) < 0) {
631 ALOGE("dexopt cannot chown '%s'\n", dex_path);
632 goto fail;
633 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800634
Steve Block71f2cf12011-10-20 11:56:00 +0100635 ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636
637 pid_t pid;
638 pid = fork();
639 if (pid == 0) {
640 /* child -- drop privileges before continuing */
641 if (setgid(uid) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000642 ALOGE("setgid(%d) failed during dexopt\n", uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800643 exit(64);
644 }
645 if (setuid(uid) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000646 ALOGE("setuid(%d) during dexopt\n", uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647 exit(65);
648 }
Nick Kralevich812b19a2012-08-31 16:08:06 -0700649 // drop capabilities
650 struct __user_cap_header_struct capheader;
651 struct __user_cap_data_struct capdata[2];
652 memset(&capheader, 0, sizeof(capheader));
653 memset(&capdata, 0, sizeof(capdata));
654 capheader.version = _LINUX_CAPABILITY_VERSION_3;
655 if (capset(&capheader, &capdata[0]) < 0) {
656 ALOGE("capset failed: %s\n", strerror(errno));
657 exit(66);
658 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000660 ALOGE("flock(%s) failed: %s\n", dex_path, strerror(errno));
Nick Kralevich812b19a2012-08-31 16:08:06 -0700661 exit(67);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800662 }
663
664 run_dexopt(zip_fd, odex_fd, apk_path, dexopt_flags);
Nick Kralevich812b19a2012-08-31 16:08:06 -0700665 exit(68); /* only get here on exec failure */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800666 } else {
667 res = wait_dexopt(pid, apk_path);
668 if (res != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000669 ALOGE("dexopt failed on '%s' res = %d\n", dex_path, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800670 goto fail;
671 }
672 }
673
674 ut.actime = apk_stat.st_atime;
675 ut.modtime = apk_stat.st_mtime;
676 utime(dex_path, &ut);
677
678 close(odex_fd);
679 close(zip_fd);
680 return 0;
681
682fail:
683 if (odex_fd >= 0) {
684 close(odex_fd);
685 unlink(dex_path);
686 }
687 if (zip_fd >= 0) {
688 close(zip_fd);
689 }
690 return -1;
691}
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800692
Dianne Hackbornc1552392010-03-03 16:19:01 -0800693void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid,
694 struct stat* statbuf)
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800695{
696 while (path[basepos] != 0) {
697 if (path[basepos] == '/') {
698 path[basepos] = 0;
Dianne Hackbornc1552392010-03-03 16:19:01 -0800699 if (lstat(path, statbuf) < 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100700 ALOGV("Making directory: %s\n", path);
Dianne Hackbornc1552392010-03-03 16:19:01 -0800701 if (mkdir(path, mode) == 0) {
702 chown(path, uid, gid);
703 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000704 ALOGW("Unable to make directory %s: %s\n", path, strerror(errno));
Dianne Hackbornc1552392010-03-03 16:19:01 -0800705 }
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800706 }
707 path[basepos] = '/';
708 basepos++;
709 }
710 basepos++;
711 }
712}
713
Dianne Hackbornc1552392010-03-03 16:19:01 -0800714int movefileordir(char* srcpath, char* dstpath, int dstbasepos,
715 int dstuid, int dstgid, struct stat* statbuf)
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800716{
717 DIR *d;
718 struct dirent *de;
719 int res;
720
721 int srcend = strlen(srcpath);
722 int dstend = strlen(dstpath);
723
724 if (lstat(srcpath, statbuf) < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000725 ALOGW("Unable to stat %s: %s\n", srcpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800726 return 1;
727 }
728
729 if ((statbuf->st_mode&S_IFDIR) == 0) {
Dianne Hackbornc1552392010-03-03 16:19:01 -0800730 mkinnerdirs(dstpath, dstbasepos, S_IRWXU|S_IRWXG|S_IXOTH,
731 dstuid, dstgid, statbuf);
Steve Block71f2cf12011-10-20 11:56:00 +0100732 ALOGV("Renaming %s to %s (uid %d)\n", srcpath, dstpath, dstuid);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800733 if (rename(srcpath, dstpath) >= 0) {
734 if (chown(dstpath, dstuid, dstgid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000735 ALOGE("cannot chown %s: %s\n", dstpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800736 unlink(dstpath);
737 return 1;
738 }
739 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000740 ALOGW("Unable to rename %s to %s: %s\n",
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800741 srcpath, dstpath, strerror(errno));
742 return 1;
743 }
744 return 0;
745 }
746
747 d = opendir(srcpath);
748 if (d == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000749 ALOGW("Unable to opendir %s: %s\n", srcpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800750 return 1;
751 }
752
753 res = 0;
754
755 while ((de = readdir(d))) {
756 const char *name = de->d_name;
757 /* always skip "." and ".." */
758 if (name[0] == '.') {
759 if (name[1] == 0) continue;
760 if ((name[1] == '.') && (name[2] == 0)) continue;
761 }
762
763 if ((srcend+strlen(name)) >= (PKG_PATH_MAX-2)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000764 ALOGW("Source path too long; skipping: %s/%s\n", srcpath, name);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800765 continue;
766 }
767
768 if ((dstend+strlen(name)) >= (PKG_PATH_MAX-2)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000769 ALOGW("Destination path too long; skipping: %s/%s\n", dstpath, name);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800770 continue;
771 }
772
773 srcpath[srcend] = dstpath[dstend] = '/';
774 strcpy(srcpath+srcend+1, name);
775 strcpy(dstpath+dstend+1, name);
776
Dianne Hackbornc1552392010-03-03 16:19:01 -0800777 if (movefileordir(srcpath, dstpath, dstbasepos, dstuid, dstgid, statbuf) != 0) {
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800778 res = 1;
779 }
780
781 // Note: we will be leaving empty directories behind in srcpath,
782 // but that is okay, the package manager will be erasing all of the
783 // data associated with .apks that disappear.
784
785 srcpath[srcend] = dstpath[dstend] = 0;
786 }
787
788 closedir(d);
789 return res;
790}
791
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800792int movefiles()
793{
794 DIR *d;
795 int dfd, subfd;
796 struct dirent *de;
797 struct stat s;
798 char buf[PKG_PATH_MAX+1];
799 int bufp, bufe, bufi, readlen;
800
801 char srcpkg[PKG_NAME_MAX];
802 char dstpkg[PKG_NAME_MAX];
803 char srcpath[PKG_PATH_MAX];
804 char dstpath[PKG_PATH_MAX];
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800805 int dstuid=-1, dstgid=-1;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800806 int hasspace;
807
808 d = opendir(UPDATE_COMMANDS_DIR_PREFIX);
809 if (d == NULL) {
810 goto done;
811 }
812 dfd = dirfd(d);
813
814 /* Iterate through all files in the directory, executing the
815 * file movements requested there-in.
816 */
817 while ((de = readdir(d))) {
818 const char *name = de->d_name;
819
820 if (de->d_type == DT_DIR) {
821 continue;
822 } else {
823 subfd = openat(dfd, name, O_RDONLY);
824 if (subfd < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000825 ALOGW("Unable to open update commands at %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800826 UPDATE_COMMANDS_DIR_PREFIX, name);
827 continue;
828 }
829
830 bufp = 0;
831 bufe = 0;
832 buf[PKG_PATH_MAX] = 0;
833 srcpkg[0] = dstpkg[0] = 0;
834 while (1) {
835 bufi = bufp;
836 while (bufi < bufe && buf[bufi] != '\n') {
837 bufi++;
838 }
839 if (bufi < bufe) {
840 buf[bufi] = 0;
Steve Block71f2cf12011-10-20 11:56:00 +0100841 ALOGV("Processing line: %s\n", buf+bufp);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800842 hasspace = 0;
843 while (bufp < bufi && isspace(buf[bufp])) {
844 hasspace = 1;
845 bufp++;
846 }
847 if (buf[bufp] == '#' || bufp == bufi) {
848 // skip comments and empty lines.
849 } else if (hasspace) {
850 if (dstpkg[0] == 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000851 ALOGW("Path before package line in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800852 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
853 } else if (srcpkg[0] == 0) {
854 // Skip -- source package no longer exists.
855 } else {
Steve Block71f2cf12011-10-20 11:56:00 +0100856 ALOGV("Move file: %s (from %s to %s)\n", buf+bufp, srcpkg, dstpkg);
Kenny Root86c95842011-03-31 13:16:12 -0700857 if (!create_move_path(srcpath, srcpkg, buf+bufp, 0) &&
858 !create_move_path(dstpath, dstpkg, buf+bufp, 0)) {
Dianne Hackbornc1552392010-03-03 16:19:01 -0800859 movefileordir(srcpath, dstpath,
860 strlen(dstpath)-strlen(buf+bufp),
861 dstuid, dstgid, &s);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800862 }
863 }
864 } else {
865 char* div = strchr(buf+bufp, ':');
866 if (div == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000867 ALOGW("Bad package spec in %s%s; no ':' sep: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800868 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
869 } else {
870 *div = 0;
871 div++;
872 if (strlen(buf+bufp) < PKG_NAME_MAX) {
873 strcpy(dstpkg, buf+bufp);
874 } else {
875 srcpkg[0] = dstpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000876 ALOGW("Package name too long in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800877 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
878 }
879 if (strlen(div) < PKG_NAME_MAX) {
880 strcpy(srcpkg, div);
881 } else {
882 srcpkg[0] = dstpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000883 ALOGW("Package name too long in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800884 UPDATE_COMMANDS_DIR_PREFIX, name, div);
885 }
886 if (srcpkg[0] != 0) {
Kenny Root86c95842011-03-31 13:16:12 -0700887 if (!create_pkg_path(srcpath, srcpkg, PKG_DIR_POSTFIX, 0)) {
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800888 if (lstat(srcpath, &s) < 0) {
889 // Package no longer exists -- skip.
890 srcpkg[0] = 0;
891 }
892 } else {
893 srcpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000894 ALOGW("Can't create path %s in %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800895 div, UPDATE_COMMANDS_DIR_PREFIX, name);
896 }
897 if (srcpkg[0] != 0) {
Kenny Root86c95842011-03-31 13:16:12 -0700898 if (!create_pkg_path(dstpath, dstpkg, PKG_DIR_POSTFIX, 0)) {
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800899 if (lstat(dstpath, &s) == 0) {
900 dstuid = s.st_uid;
901 dstgid = s.st_gid;
902 } else {
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800903 // Destination package doesn't
904 // exist... due to original-package,
905 // this is normal, so don't be
906 // noisy about it.
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800907 srcpkg[0] = 0;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800908 }
909 } else {
910 srcpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000911 ALOGW("Can't create path %s in %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800912 div, UPDATE_COMMANDS_DIR_PREFIX, name);
913 }
914 }
Steve Block71f2cf12011-10-20 11:56:00 +0100915 ALOGV("Transfering from %s to %s: uid=%d\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800916 srcpkg, dstpkg, dstuid);
917 }
918 }
919 }
920 bufp = bufi+1;
921 } else {
922 if (bufp == 0) {
923 if (bufp < bufe) {
Steve Block8564c8d2012-01-05 23:22:43 +0000924 ALOGW("Line too long in %s%s, skipping: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800925 UPDATE_COMMANDS_DIR_PREFIX, name, buf);
926 }
927 } else if (bufp < bufe) {
928 memcpy(buf, buf+bufp, bufe-bufp);
929 bufe -= bufp;
930 bufp = 0;
931 }
932 readlen = read(subfd, buf+bufe, PKG_PATH_MAX-bufe);
933 if (readlen < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000934 ALOGW("Failure reading update commands in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800935 UPDATE_COMMANDS_DIR_PREFIX, name, strerror(errno));
936 break;
937 } else if (readlen == 0) {
938 break;
939 }
940 bufe += readlen;
941 buf[bufe] = 0;
Steve Block71f2cf12011-10-20 11:56:00 +0100942 ALOGV("Read buf: %s\n", buf);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800943 }
944 }
945 close(subfd);
946 }
947 }
948 closedir(d);
949done:
950 return 0;
951}
Kenny Root6a6b0072010-10-07 16:46:10 -0700952
953int linklib(const char* dataDir, const char* asecLibDir)
954{
955 char libdir[PKG_PATH_MAX];
956 struct stat s, libStat;
957 int rc = 0;
958
959 const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
960 if (libdirLen >= PKG_PATH_MAX) {
Steve Block3762c312012-01-06 19:20:56 +0000961 ALOGE("library dir len too large");
Kenny Root0332d1c2010-10-21 16:14:06 -0700962 return -1;
Kenny Root6a6b0072010-10-07 16:46:10 -0700963 }
964
965 if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
Steve Block3762c312012-01-06 19:20:56 +0000966 ALOGE("library dir not written successfully: %s\n", strerror(errno));
Kenny Root0332d1c2010-10-21 16:14:06 -0700967 return -1;
Kenny Root6a6b0072010-10-07 16:46:10 -0700968 }
969
970 if (stat(dataDir, &s) < 0) return -1;
971
Nick Kralevich7de350a2012-09-07 15:48:11 -0700972 if (chown(dataDir, AID_INSTALL, AID_INSTALL) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000973 ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700974 return -1;
975 }
976
977 if (chmod(dataDir, 0700) < 0) {
Nick Kralevich7de350a2012-09-07 15:48:11 -0700978 ALOGE("linklib() 1: failed to chmod '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700979 rc = -1;
980 goto out;
981 }
982
983 if (lstat(libdir, &libStat) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000984 ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700985 rc = -1;
986 goto out;
987 }
988
989 if (S_ISDIR(libStat.st_mode)) {
990 if (delete_dir_contents(libdir, 1, 0) < 0) {
991 rc = -1;
992 goto out;
993 }
994 } else if (S_ISLNK(libStat.st_mode)) {
995 if (unlink(libdir) < 0) {
996 rc = -1;
997 goto out;
998 }
999 }
1000
1001 if (symlink(asecLibDir, libdir) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001002 ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libdir, asecLibDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001003 rc = -errno;
1004 goto out;
1005 }
1006
1007 if (lchown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001008 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001009 unlink(libdir);
1010 rc = -errno;
1011 goto out;
1012 }
1013
1014out:
1015 if (chmod(dataDir, s.st_mode) < 0) {
Nick Kralevich7de350a2012-09-07 15:48:11 -07001016 ALOGE("linklib() 2: failed to chmod '%s': %s\n", dataDir, strerror(errno));
Dianne Hackbornd0c5f512012-06-07 16:53:59 -07001017 rc = -errno;
Kenny Root6a6b0072010-10-07 16:46:10 -07001018 }
1019
1020 if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001021 ALOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001022 return -errno;
1023 }
1024
1025 return rc;
1026}