blob: 9e83a670b44d19e79ffd28c95d562e2c97173fca [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;
Dianne Hackborn197a0c82012-07-12 14:46:04 -070030dir_rec_t android_media_dir;
Kenny Root86c95842011-03-31 13:16:12 -070031dir_rec_array_t android_system_dirs;
32
Kenny Root35ab3ad2011-02-02 16:42:14 -080033int install(const char *pkgname, uid_t uid, gid_t gid)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034{
35 char pkgdir[PKG_PATH_MAX];
36 char libdir[PKG_PATH_MAX];
37
38 if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
Steve Block3762c312012-01-06 19:20:56 +000039 ALOGE("invalid uid/gid: %d %d\n", uid, gid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041 }
Oscar Montemayora8529f62009-11-18 10:14:20 -080042
Kenny Root86c95842011-03-31 13:16:12 -070043 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
Steve Block3762c312012-01-06 19:20:56 +000044 ALOGE("cannot create package path\n");
Kenny Root35ab3ad2011-02-02 16:42:14 -080045 return -1;
Kenny Root86c95842011-03-31 13:16:12 -070046 }
47
48 if (create_pkg_path(libdir, pkgname, PKG_LIB_POSTFIX, 0)) {
Steve Block3762c312012-01-06 19:20:56 +000049 ALOGE("cannot create package lib path\n");
Kenny Root35ab3ad2011-02-02 16:42:14 -080050 return -1;
Kenny Root86c95842011-03-31 13:16:12 -070051 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052
David 'Digit' Turner0dd50e62010-02-09 19:02:38 -080053 if (mkdir(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000054 ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055 return -errno;
56 }
Nick Kralevichf68327e2011-04-14 16:20:03 -070057 if (chmod(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000058 ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
Nick Kralevichf68327e2011-04-14 16:20:03 -070059 unlink(pkgdir);
60 return -errno;
61 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -050062
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063 if (mkdir(libdir, 0755) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000064 ALOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065 unlink(pkgdir);
66 return -errno;
67 }
Nick Kralevichf68327e2011-04-14 16:20:03 -070068 if (chmod(libdir, 0755) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000069 ALOGE("cannot chmod dir '%s': %s\n", libdir, strerror(errno));
Nick Kralevichf68327e2011-04-14 16:20:03 -070070 unlink(libdir);
71 unlink(pkgdir);
72 return -errno;
73 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074 if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000075 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076 unlink(libdir);
77 unlink(pkgdir);
78 return -errno;
79 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -050080
81#ifdef HAVE_SELINUX
82 if (selinux_android_setfilecon(libdir, pkgname, AID_SYSTEM) < 0) {
Joshua Brindle365861e2012-07-10 10:22:36 -040083 ALOGE("cannot setfilecon dir '%s': %s\n", libdir, strerror(errno));
Stephen Smalley0b58e6a2012-01-13 08:27:42 -050084 unlink(libdir);
85 unlink(pkgdir);
86 return -errno;
87 }
88#endif
89
Kenny Root4503cf62012-06-14 13:05:18 -070090 if (chown(pkgdir, uid, gid) < 0) {
91 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
92 unlink(libdir);
93 unlink(pkgdir);
94 return -errno;
95 }
Kenny Root33ef4ee2012-06-18 10:26:36 -070096
97#ifdef HAVE_SELINUX
98 if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
Joshua Brindle365861e2012-07-10 10:22:36 -040099 ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
Kenny Root33ef4ee2012-06-18 10:26:36 -0700100 unlink(libdir);
101 unlink(pkgdir);
102 return -errno;
103 }
104#endif
105
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 return 0;
107}
108
Amith Yamasani0b285492011-04-14 17:35:23 -0700109int uninstall(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 AND directory, no exceptions */
117 return delete_dir_contents(pkgdir, 1, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118}
119
Kenny Root35ab3ad2011-02-02 16:42:14 -0800120int renamepkg(const char *oldpkgname, const char *newpkgname)
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800121{
122 char oldpkgdir[PKG_PATH_MAX];
123 char newpkgdir[PKG_PATH_MAX];
124
Kenny Root86c95842011-03-31 13:16:12 -0700125 if (create_pkg_path(oldpkgdir, oldpkgname, PKG_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800126 return -1;
Kenny Root86c95842011-03-31 13:16:12 -0700127 if (create_pkg_path(newpkgdir, newpkgname, PKG_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800128 return -1;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800129
130 if (rename(oldpkgdir, newpkgdir) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000131 ALOGE("cannot rename dir '%s' to '%s': %s\n", oldpkgdir, newpkgdir, strerror(errno));
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800132 return -errno;
133 }
134 return 0;
135}
136
Dianne Hackbornd0c5f512012-06-07 16:53:59 -0700137int fix_uid(const char *pkgname, uid_t uid, gid_t gid)
138{
139 char pkgdir[PKG_PATH_MAX];
140 struct stat s;
141 int rc = 0;
142
143 if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
144 ALOGE("invalid uid/gid: %d %d\n", uid, gid);
145 return -1;
146 }
147
148 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
149 ALOGE("cannot create package path\n");
150 return -1;
151 }
152
153 if (stat(pkgdir, &s) < 0) return -1;
154
155 if (s.st_uid != 0 || s.st_gid != 0) {
156 ALOGE("fixing uid of non-root pkg: %s %d %d\n", pkgdir, s.st_uid, s.st_gid);
157 return -1;
158 }
159
160 if (chmod(pkgdir, 0751) < 0) {
161 ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
162 unlink(pkgdir);
163 return -errno;
164 }
165 if (chown(pkgdir, uid, gid) < 0) {
166 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
167 unlink(pkgdir);
168 return -errno;
169 }
170
171 return 0;
172}
173
Amith Yamasani0b285492011-04-14 17:35:23 -0700174int delete_user_data(const char *pkgname, uid_t persona)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175{
176 char pkgdir[PKG_PATH_MAX];
177
Amith Yamasani0b285492011-04-14 17:35:23 -0700178 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800179 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180
Amith Yamasani0b285492011-04-14 17:35:23 -0700181 /* delete contents, excluding "lib", but not the directory itself */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 return delete_dir_contents(pkgdir, 0, "lib");
183}
184
Amith Yamasani0b285492011-04-14 17:35:23 -0700185int make_user_data(const char *pkgname, uid_t uid, uid_t persona)
186{
187 char pkgdir[PKG_PATH_MAX];
188 char real_libdir[PKG_PATH_MAX];
189
190 // Create the data dir for the package
191 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona)) {
192 return -1;
193 }
194 if (mkdir(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000195 ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
Amith Yamasani0b285492011-04-14 17:35:23 -0700196 return -errno;
197 }
Amith Yamasani794d62f2012-08-24 12:58:27 -0700198 if (chmod(pkgdir, 0751) < 0) {
199 ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
200 unlink(pkgdir);
201 return -errno;
202 }
Amith Yamasani0b285492011-04-14 17:35:23 -0700203 if (chown(pkgdir, uid, uid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000204 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
Amith Yamasani0b285492011-04-14 17:35:23 -0700205 unlink(pkgdir);
206 return -errno;
207 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500208
209#ifdef HAVE_SELINUX
210 if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
Joshua Brindle365861e2012-07-10 10:22:36 -0400211 ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500212 unlink(pkgdir);
213 return -errno;
214 }
215#endif
216
Amith Yamasani0b285492011-04-14 17:35:23 -0700217 return 0;
218}
219
220int delete_persona(uid_t persona)
221{
Jeff Sharkey5b1ada22012-08-14 18:47:09 -0700222 char data_path[PKG_PATH_MAX];
223 if (create_persona_path(data_path, persona)) {
Amith Yamasani0b285492011-04-14 17:35:23 -0700224 return -1;
Jeff Sharkey5b1ada22012-08-14 18:47:09 -0700225 }
226 if (delete_dir_contents(data_path, 1, NULL)) {
227 return -1;
228 }
Amith Yamasani0b285492011-04-14 17:35:23 -0700229
Jeff Sharkey5b1ada22012-08-14 18:47:09 -0700230 char media_path[PATH_MAX];
231 if (create_persona_media_path(media_path, (userid_t) persona) == -1) {
232 return -1;
233 }
234 if (delete_dir_contents(media_path, 1, NULL) == -1) {
235 return -1;
236 }
237
238 return 0;
Amith Yamasani0b285492011-04-14 17:35:23 -0700239}
240
Amith Yamasani742a6712011-05-04 14:49:28 -0700241int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy)
242{
243 char src_data_dir[PKG_PATH_MAX];
244 char pkg_path[PKG_PATH_MAX];
245 DIR *d;
246 struct dirent *de;
247 struct stat s;
248 uid_t uid;
249
250 if (create_persona_path(src_data_dir, src_persona)) {
251 return -1;
252 }
253
254 d = opendir(src_data_dir);
255 if (d != NULL) {
256 while ((de = readdir(d))) {
257 const char *name = de->d_name;
258
259 if (de->d_type == DT_DIR) {
260 int subfd;
261 /* always skip "." and ".." */
262 if (name[0] == '.') {
263 if (name[1] == 0) continue;
264 if ((name[1] == '.') && (name[2] == 0)) continue;
265 }
266 /* Create the full path to the package's data dir */
267 create_pkg_path(pkg_path, name, PKG_DIR_POSTFIX, src_persona);
268 /* Get the file stat */
269 if (stat(pkg_path, &s) < 0) continue;
270 /* Get the uid of the package */
271 ALOGI("Adding datadir for uid = %d\n", s.st_uid);
272 uid = (uid_t) s.st_uid % PER_USER_RANGE;
273 /* Create the directory for the target */
274 make_user_data(name, uid + target_persona * PER_USER_RANGE,
275 target_persona);
276 }
277 }
278 closedir(d);
279 }
Jeff Sharkey5b1ada22012-08-14 18:47:09 -0700280
Jeff Sharkey8ea0dc62012-08-27 15:46:54 -0700281 if (ensure_media_user_dirs((userid_t) target_persona) == -1) {
Jeff Sharkey5b1ada22012-08-14 18:47:09 -0700282 return -1;
283 }
Jeff Sharkey8ea0dc62012-08-27 15:46:54 -0700284
Amith Yamasani742a6712011-05-04 14:49:28 -0700285 return 0;
286}
287
Kenny Root35ab3ad2011-02-02 16:42:14 -0800288int delete_cache(const char *pkgname)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289{
290 char cachedir[PKG_PATH_MAX];
291
Kenny Root86c95842011-03-31 13:16:12 -0700292 if (create_pkg_path(cachedir, pkgname, CACHE_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800293 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294
295 /* delete contents, not the directory, no exceptions */
296 return delete_dir_contents(cachedir, 0, 0);
297}
298
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299/* Try to ensure free_size bytes of storage are available.
300 * Returns 0 on success.
301 * This is rather simple-minded because doing a full LRU would
302 * be potentially memory-intensive, and without atime it would
303 * also require that apps constantly modify file metadata even
304 * when just reading from the cache, which is pretty awful.
305 */
Kenny Root3e319a92010-09-07 13:58:28 -0700306int free_cache(int64_t free_size)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800307{
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700308 cache_t* cache;
309 int64_t avail;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800310 DIR *d;
311 struct dirent *de;
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700312 char tmpdir[PATH_MAX];
313 char *dirpos;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800314
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700315 avail = data_disk_free();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 if (avail < 0) return -1;
317
Steve Block6215d3f2012-01-04 20:05:49 +0000318 ALOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 if (avail >= free_size) return 0;
320
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700321 cache = start_cache_collection();
322
323 // Collect cache files for primary user.
324 if (create_persona_path(tmpdir, 0) == 0) {
325 //ALOGI("adding cache files from %s\n", tmpdir);
326 add_cache_files(cache, tmpdir, "cache");
Kenny Rootad757e92011-11-29 15:54:55 -0800327 }
328
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700329 // Search for other users and add any cache files from them.
330 snprintf(tmpdir, sizeof(tmpdir), "%s%s", android_data_dir.path,
331 SECONDARY_USER_PREFIX);
332 dirpos = tmpdir + strlen(tmpdir);
333 d = opendir(tmpdir);
334 if (d != NULL) {
335 while ((de = readdir(d))) {
336 if (de->d_type == DT_DIR) {
337 const char *name = de->d_name;
338 /* always skip "." and ".." */
339 if (name[0] == '.') {
340 if (name[1] == 0) continue;
341 if ((name[1] == '.') && (name[2] == 0)) continue;
342 }
343 if ((strlen(name)+(dirpos-tmpdir)) < (sizeof(tmpdir)-1)) {
344 strcpy(dirpos, name);
345 //ALOGI("adding cache files from %s\n", tmpdir);
346 add_cache_files(cache, tmpdir, "cache");
347 } else {
348 ALOGW("Path exceeds limit: %s%s", tmpdir, name);
349 }
350 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 }
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700352 closedir(d);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 }
Oscar Montemayora8529f62009-11-18 10:14:20 -0800354
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700355 // Collect cache files on external storage (if it is mounted as part
356 // of the internal storage).
357 strcpy(tmpdir, android_media_dir.path);
358 if (lookup_media_dir(tmpdir, "Android") == 0
359 && lookup_media_dir(tmpdir, "data") == 0) {
360 //ALOGI("adding cache files from %s\n", tmpdir);
361 add_cache_files(cache, tmpdir, "cache");
362 }
363
364 clear_cache_files(cache, free_size);
365 finish_cache_collection(cache);
366
367 return data_disk_free() >= free_size ? 0 : -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368}
369
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370int move_dex(const char *src, const char *dst)
371{
372 char src_dex[PKG_PATH_MAX];
373 char dst_dex[PKG_PATH_MAX];
374
Kenny Root86c95842011-03-31 13:16:12 -0700375 if (validate_apk_path(src)) return -1;
376 if (validate_apk_path(dst)) return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800377
378 if (create_cache_path(src_dex, src)) return -1;
379 if (create_cache_path(dst_dex, dst)) return -1;
380
Steve Block71f2cf12011-10-20 11:56:00 +0100381 ALOGV("move %s -> %s\n", src_dex, dst_dex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 if (rename(src_dex, dst_dex) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000383 ALOGE("Couldn't move %s: %s\n", src_dex, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 return -1;
385 } else {
386 return 0;
387 }
388}
389
390int rm_dex(const char *path)
391{
392 char dex_path[PKG_PATH_MAX];
393
Kenny Root86c95842011-03-31 13:16:12 -0700394 if (validate_apk_path(path)) return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 if (create_cache_path(dex_path, path)) return -1;
396
Steve Block71f2cf12011-10-20 11:56:00 +0100397 ALOGV("unlink %s\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 if (unlink(dex_path) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000399 ALOGE("Couldn't unlink %s: %s\n", dex_path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 return -1;
401 } else {
402 return 0;
403 }
404}
405
406int protect(char *pkgname, gid_t gid)
407{
408 struct stat s;
409 char pkgpath[PKG_PATH_MAX];
410
411 if (gid < AID_SYSTEM) return -1;
412
Kenny Root86c95842011-03-31 13:16:12 -0700413 if (create_pkg_path_in_dir(pkgpath, &android_app_private_dir, pkgname, ".apk"))
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 return -1;
415
416 if (stat(pkgpath, &s) < 0) return -1;
417
418 if (chown(pkgpath, s.st_uid, gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000419 ALOGE("failed to chgrp '%s': %s\n", pkgpath, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 return -1;
421 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800422 if (chmod(pkgpath, S_IRUSR|S_IWUSR|S_IRGRP) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000423 ALOGE("failed to chmod '%s': %s\n", pkgpath, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 return -1;
425 }
426
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500427#ifdef HAVE_SELINUX
428 if (selinux_android_setfilecon(pkgpath, pkgname, s.st_uid) < 0) {
Joshua Brindle365861e2012-07-10 10:22:36 -0400429 ALOGE("cannot setfilecon dir '%s': %s\n", pkgpath, strerror(errno));
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500430 return -1;
431 }
432#endif
433
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434 return 0;
435}
436
Dianne Hackborn0c380492012-08-20 17:23:30 -0700437int get_size(const char *pkgname, int persona, const char *apkpath,
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700438 const char *fwdlock_apkpath, const char *asecpath,
439 int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize,
440 int64_t* _asecsize)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800441{
442 DIR *d;
443 int dfd;
444 struct dirent *de;
445 struct stat s;
446 char path[PKG_PATH_MAX];
447
Kenny Root3e319a92010-09-07 13:58:28 -0700448 int64_t codesize = 0;
449 int64_t datasize = 0;
450 int64_t cachesize = 0;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700451 int64_t asecsize = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452
453 /* count the source apk as code -- but only if it's not
Suchi Amalapurapu8a9ab242010-03-11 16:49:16 -0800454 * on the /system partition and its not on the sdcard.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 */
Kenny Root86c95842011-03-31 13:16:12 -0700456 if (validate_system_app_path(apkpath) &&
457 strncmp(apkpath, android_asec_dir.path, android_asec_dir.len) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800458 if (stat(apkpath, &s) == 0) {
459 codesize += stat_size(&s);
460 }
461 }
462 /* count the forward locked apk as code if it is given
463 */
464 if (fwdlock_apkpath != NULL && fwdlock_apkpath[0] != '!') {
465 if (stat(fwdlock_apkpath, &s) == 0) {
466 codesize += stat_size(&s);
467 }
468 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469 /* count the cached dexfile as code */
470 if (!create_cache_path(path, apkpath)) {
471 if (stat(path, &s) == 0) {
472 codesize += stat_size(&s);
473 }
474 }
475
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700476 /* compute asec size if it is given
477 */
478 if (asecpath != NULL && asecpath[0] != '!') {
479 if (stat(asecpath, &s) == 0) {
480 asecsize += stat_size(&s);
481 }
482 }
483
Dianne Hackborn0c380492012-08-20 17:23:30 -0700484 if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, persona)) {
Kenny Root35ab3ad2011-02-02 16:42:14 -0800485 goto done;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486 }
487
488 d = opendir(path);
489 if (d == NULL) {
490 goto done;
491 }
492 dfd = dirfd(d);
493
Kenny Root86c95842011-03-31 13:16:12 -0700494 /* most stuff in the pkgdir is data, except for the "cache"
495 * directory and below, which is cache, and the "lib" directory
496 * and below, which is code...
497 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800498 while ((de = readdir(d))) {
499 const char *name = de->d_name;
500
501 if (de->d_type == DT_DIR) {
502 int subfd;
503 /* always skip "." and ".." */
504 if (name[0] == '.') {
505 if (name[1] == 0) continue;
506 if ((name[1] == '.') && (name[2] == 0)) continue;
507 }
508 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
509 if (subfd >= 0) {
Kenny Root3e319a92010-09-07 13:58:28 -0700510 int64_t size = calculate_dir_size(subfd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511 if (!strcmp(name,"lib")) {
512 codesize += size;
513 } else if(!strcmp(name,"cache")) {
514 cachesize += size;
515 } else {
516 datasize += size;
517 }
518 }
519 } else {
520 if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
521 datasize += stat_size(&s);
522 }
523 }
524 }
525 closedir(d);
526done:
527 *_codesize = codesize;
528 *_datasize = datasize;
529 *_cachesize = cachesize;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700530 *_asecsize = asecsize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 return 0;
532}
533
534
535/* a simpler version of dexOptGenerateCacheFileName() */
536int create_cache_path(char path[PKG_PATH_MAX], const char *src)
537{
538 char *tmp;
539 int srclen;
540 int dstlen;
541
542 srclen = strlen(src);
543
544 /* demand that we are an absolute path */
545 if ((src == 0) || (src[0] != '/') || strstr(src,"..")) {
546 return -1;
547 }
548
549 if (srclen > PKG_PATH_MAX) { // XXX: PKG_NAME_MAX?
550 return -1;
551 }
552
553 dstlen = srclen + strlen(DALVIK_CACHE_PREFIX) +
554 strlen(DALVIK_CACHE_POSTFIX) + 1;
555
556 if (dstlen > PKG_PATH_MAX) {
557 return -1;
558 }
559
560 sprintf(path,"%s%s%s",
561 DALVIK_CACHE_PREFIX,
562 src + 1, /* skip the leading / */
563 DALVIK_CACHE_POSTFIX);
564
565 for(tmp = path + strlen(DALVIK_CACHE_PREFIX); *tmp; tmp++) {
566 if (*tmp == '/') {
567 *tmp = '@';
568 }
569 }
570
571 return 0;
572}
573
574static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name,
575 const char* dexopt_flags)
576{
577 static const char* DEX_OPT_BIN = "/system/bin/dexopt";
578 static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
579 char zip_num[MAX_INT_LEN];
580 char odex_num[MAX_INT_LEN];
581
582 sprintf(zip_num, "%d", zip_fd);
583 sprintf(odex_num, "%d", odex_fd);
584
585 execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name,
586 dexopt_flags, (char*) NULL);
Steve Block3762c312012-01-06 19:20:56 +0000587 ALOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588}
589
590static int wait_dexopt(pid_t pid, const char* apk_path)
591{
592 int status;
593 pid_t got_pid;
594
595 /*
596 * Wait for the optimization process to finish.
597 */
598 while (1) {
599 got_pid = waitpid(pid, &status, 0);
600 if (got_pid == -1 && errno == EINTR) {
601 printf("waitpid interrupted, retrying\n");
602 } else {
603 break;
604 }
605 }
606 if (got_pid != pid) {
Steve Block8564c8d2012-01-05 23:22:43 +0000607 ALOGW("waitpid failed: wanted %d, got %d: %s\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608 (int) pid, (int) got_pid, strerror(errno));
609 return 1;
610 }
611
612 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100613 ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614 return 0;
615 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000616 ALOGW("DexInv: --- END '%s' --- status=0x%04x, process failed\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800617 apk_path, status);
618 return status; /* always nonzero */
619 }
620}
621
622int dexopt(const char *apk_path, uid_t uid, int is_public)
623{
624 struct utimbuf ut;
625 struct stat apk_stat, dex_stat;
626 char dex_path[PKG_PATH_MAX];
627 char dexopt_flags[PROPERTY_VALUE_MAX];
628 char *end;
629 int res, zip_fd=-1, odex_fd=-1;
630
631 /* Before anything else: is there a .odex file? If so, we have
632 * pre-optimized the apk and there is nothing to do here.
633 */
634 if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
635 return -1;
636 }
637
638 /* platform-specific flags affecting optimization and verification */
639 property_get("dalvik.vm.dexopt-flags", dexopt_flags, "");
640
641 strcpy(dex_path, apk_path);
642 end = strrchr(dex_path, '.');
643 if (end != NULL) {
644 strcpy(end, ".odex");
645 if (stat(dex_path, &dex_stat) == 0) {
646 return 0;
647 }
648 }
649
650 if (create_cache_path(dex_path, apk_path)) {
651 return -1;
652 }
653
654 memset(&apk_stat, 0, sizeof(apk_stat));
655 stat(apk_path, &apk_stat);
656
657 zip_fd = open(apk_path, O_RDONLY, 0);
658 if (zip_fd < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000659 ALOGE("dexopt cannot open '%s' for input\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660 return -1;
661 }
662
663 unlink(dex_path);
664 odex_fd = open(dex_path, O_RDWR | O_CREAT | O_EXCL, 0644);
665 if (odex_fd < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000666 ALOGE("dexopt cannot open '%s' for output\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 goto fail;
668 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800669 if (fchmod(odex_fd,
670 S_IRUSR|S_IWUSR|S_IRGRP |
671 (is_public ? S_IROTH : 0)) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000672 ALOGE("dexopt cannot chmod '%s'\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800673 goto fail;
674 }
Nick Kralevich812b19a2012-08-31 16:08:06 -0700675 if (fchown(odex_fd, AID_SYSTEM, uid) < 0) {
676 ALOGE("dexopt cannot chown '%s'\n", dex_path);
677 goto fail;
678 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679
Steve Block71f2cf12011-10-20 11:56:00 +0100680 ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800681
682 pid_t pid;
683 pid = fork();
684 if (pid == 0) {
685 /* child -- drop privileges before continuing */
686 if (setgid(uid) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000687 ALOGE("setgid(%d) failed during dexopt\n", uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 exit(64);
689 }
690 if (setuid(uid) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000691 ALOGE("setuid(%d) during dexopt\n", uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800692 exit(65);
693 }
Nick Kralevich812b19a2012-08-31 16:08:06 -0700694 // drop capabilities
695 struct __user_cap_header_struct capheader;
696 struct __user_cap_data_struct capdata[2];
697 memset(&capheader, 0, sizeof(capheader));
698 memset(&capdata, 0, sizeof(capdata));
699 capheader.version = _LINUX_CAPABILITY_VERSION_3;
700 if (capset(&capheader, &capdata[0]) < 0) {
701 ALOGE("capset failed: %s\n", strerror(errno));
702 exit(66);
703 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800704 if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000705 ALOGE("flock(%s) failed: %s\n", dex_path, strerror(errno));
Nick Kralevich812b19a2012-08-31 16:08:06 -0700706 exit(67);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800707 }
708
709 run_dexopt(zip_fd, odex_fd, apk_path, dexopt_flags);
Nick Kralevich812b19a2012-08-31 16:08:06 -0700710 exit(68); /* only get here on exec failure */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800711 } else {
712 res = wait_dexopt(pid, apk_path);
713 if (res != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000714 ALOGE("dexopt failed on '%s' res = %d\n", dex_path, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715 goto fail;
716 }
717 }
718
719 ut.actime = apk_stat.st_atime;
720 ut.modtime = apk_stat.st_mtime;
721 utime(dex_path, &ut);
722
723 close(odex_fd);
724 close(zip_fd);
725 return 0;
726
727fail:
728 if (odex_fd >= 0) {
729 close(odex_fd);
730 unlink(dex_path);
731 }
732 if (zip_fd >= 0) {
733 close(zip_fd);
734 }
735 return -1;
736}
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800737
Dianne Hackbornc1552392010-03-03 16:19:01 -0800738void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid,
739 struct stat* statbuf)
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800740{
741 while (path[basepos] != 0) {
742 if (path[basepos] == '/') {
743 path[basepos] = 0;
Dianne Hackbornc1552392010-03-03 16:19:01 -0800744 if (lstat(path, statbuf) < 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100745 ALOGV("Making directory: %s\n", path);
Dianne Hackbornc1552392010-03-03 16:19:01 -0800746 if (mkdir(path, mode) == 0) {
747 chown(path, uid, gid);
748 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000749 ALOGW("Unable to make directory %s: %s\n", path, strerror(errno));
Dianne Hackbornc1552392010-03-03 16:19:01 -0800750 }
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800751 }
752 path[basepos] = '/';
753 basepos++;
754 }
755 basepos++;
756 }
757}
758
Dianne Hackbornc1552392010-03-03 16:19:01 -0800759int movefileordir(char* srcpath, char* dstpath, int dstbasepos,
760 int dstuid, int dstgid, struct stat* statbuf)
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800761{
762 DIR *d;
763 struct dirent *de;
764 int res;
765
766 int srcend = strlen(srcpath);
767 int dstend = strlen(dstpath);
768
769 if (lstat(srcpath, statbuf) < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000770 ALOGW("Unable to stat %s: %s\n", srcpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800771 return 1;
772 }
773
774 if ((statbuf->st_mode&S_IFDIR) == 0) {
Dianne Hackbornc1552392010-03-03 16:19:01 -0800775 mkinnerdirs(dstpath, dstbasepos, S_IRWXU|S_IRWXG|S_IXOTH,
776 dstuid, dstgid, statbuf);
Steve Block71f2cf12011-10-20 11:56:00 +0100777 ALOGV("Renaming %s to %s (uid %d)\n", srcpath, dstpath, dstuid);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800778 if (rename(srcpath, dstpath) >= 0) {
779 if (chown(dstpath, dstuid, dstgid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000780 ALOGE("cannot chown %s: %s\n", dstpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800781 unlink(dstpath);
782 return 1;
783 }
784 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000785 ALOGW("Unable to rename %s to %s: %s\n",
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800786 srcpath, dstpath, strerror(errno));
787 return 1;
788 }
789 return 0;
790 }
791
792 d = opendir(srcpath);
793 if (d == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000794 ALOGW("Unable to opendir %s: %s\n", srcpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800795 return 1;
796 }
797
798 res = 0;
799
800 while ((de = readdir(d))) {
801 const char *name = de->d_name;
802 /* always skip "." and ".." */
803 if (name[0] == '.') {
804 if (name[1] == 0) continue;
805 if ((name[1] == '.') && (name[2] == 0)) continue;
806 }
807
808 if ((srcend+strlen(name)) >= (PKG_PATH_MAX-2)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000809 ALOGW("Source path too long; skipping: %s/%s\n", srcpath, name);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800810 continue;
811 }
812
813 if ((dstend+strlen(name)) >= (PKG_PATH_MAX-2)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000814 ALOGW("Destination path too long; skipping: %s/%s\n", dstpath, name);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800815 continue;
816 }
817
818 srcpath[srcend] = dstpath[dstend] = '/';
819 strcpy(srcpath+srcend+1, name);
820 strcpy(dstpath+dstend+1, name);
821
Dianne Hackbornc1552392010-03-03 16:19:01 -0800822 if (movefileordir(srcpath, dstpath, dstbasepos, dstuid, dstgid, statbuf) != 0) {
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800823 res = 1;
824 }
825
826 // Note: we will be leaving empty directories behind in srcpath,
827 // but that is okay, the package manager will be erasing all of the
828 // data associated with .apks that disappear.
829
830 srcpath[srcend] = dstpath[dstend] = 0;
831 }
832
833 closedir(d);
834 return res;
835}
836
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800837int movefiles()
838{
839 DIR *d;
840 int dfd, subfd;
841 struct dirent *de;
842 struct stat s;
843 char buf[PKG_PATH_MAX+1];
844 int bufp, bufe, bufi, readlen;
845
846 char srcpkg[PKG_NAME_MAX];
847 char dstpkg[PKG_NAME_MAX];
848 char srcpath[PKG_PATH_MAX];
849 char dstpath[PKG_PATH_MAX];
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800850 int dstuid=-1, dstgid=-1;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800851 int hasspace;
852
853 d = opendir(UPDATE_COMMANDS_DIR_PREFIX);
854 if (d == NULL) {
855 goto done;
856 }
857 dfd = dirfd(d);
858
859 /* Iterate through all files in the directory, executing the
860 * file movements requested there-in.
861 */
862 while ((de = readdir(d))) {
863 const char *name = de->d_name;
864
865 if (de->d_type == DT_DIR) {
866 continue;
867 } else {
868 subfd = openat(dfd, name, O_RDONLY);
869 if (subfd < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000870 ALOGW("Unable to open update commands at %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800871 UPDATE_COMMANDS_DIR_PREFIX, name);
872 continue;
873 }
874
875 bufp = 0;
876 bufe = 0;
877 buf[PKG_PATH_MAX] = 0;
878 srcpkg[0] = dstpkg[0] = 0;
879 while (1) {
880 bufi = bufp;
881 while (bufi < bufe && buf[bufi] != '\n') {
882 bufi++;
883 }
884 if (bufi < bufe) {
885 buf[bufi] = 0;
Steve Block71f2cf12011-10-20 11:56:00 +0100886 ALOGV("Processing line: %s\n", buf+bufp);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800887 hasspace = 0;
888 while (bufp < bufi && isspace(buf[bufp])) {
889 hasspace = 1;
890 bufp++;
891 }
892 if (buf[bufp] == '#' || bufp == bufi) {
893 // skip comments and empty lines.
894 } else if (hasspace) {
895 if (dstpkg[0] == 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000896 ALOGW("Path before package line in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800897 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
898 } else if (srcpkg[0] == 0) {
899 // Skip -- source package no longer exists.
900 } else {
Steve Block71f2cf12011-10-20 11:56:00 +0100901 ALOGV("Move file: %s (from %s to %s)\n", buf+bufp, srcpkg, dstpkg);
Kenny Root86c95842011-03-31 13:16:12 -0700902 if (!create_move_path(srcpath, srcpkg, buf+bufp, 0) &&
903 !create_move_path(dstpath, dstpkg, buf+bufp, 0)) {
Dianne Hackbornc1552392010-03-03 16:19:01 -0800904 movefileordir(srcpath, dstpath,
905 strlen(dstpath)-strlen(buf+bufp),
906 dstuid, dstgid, &s);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800907 }
908 }
909 } else {
910 char* div = strchr(buf+bufp, ':');
911 if (div == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000912 ALOGW("Bad package spec in %s%s; no ':' sep: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800913 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
914 } else {
915 *div = 0;
916 div++;
917 if (strlen(buf+bufp) < PKG_NAME_MAX) {
918 strcpy(dstpkg, buf+bufp);
919 } else {
920 srcpkg[0] = dstpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000921 ALOGW("Package name too long in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800922 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
923 }
924 if (strlen(div) < PKG_NAME_MAX) {
925 strcpy(srcpkg, div);
926 } else {
927 srcpkg[0] = dstpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000928 ALOGW("Package name too long in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800929 UPDATE_COMMANDS_DIR_PREFIX, name, div);
930 }
931 if (srcpkg[0] != 0) {
Kenny Root86c95842011-03-31 13:16:12 -0700932 if (!create_pkg_path(srcpath, srcpkg, PKG_DIR_POSTFIX, 0)) {
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800933 if (lstat(srcpath, &s) < 0) {
934 // Package no longer exists -- skip.
935 srcpkg[0] = 0;
936 }
937 } else {
938 srcpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000939 ALOGW("Can't create path %s in %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800940 div, UPDATE_COMMANDS_DIR_PREFIX, name);
941 }
942 if (srcpkg[0] != 0) {
Kenny Root86c95842011-03-31 13:16:12 -0700943 if (!create_pkg_path(dstpath, dstpkg, PKG_DIR_POSTFIX, 0)) {
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800944 if (lstat(dstpath, &s) == 0) {
945 dstuid = s.st_uid;
946 dstgid = s.st_gid;
947 } else {
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800948 // Destination package doesn't
949 // exist... due to original-package,
950 // this is normal, so don't be
951 // noisy about it.
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800952 srcpkg[0] = 0;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800953 }
954 } else {
955 srcpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000956 ALOGW("Can't create path %s in %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800957 div, UPDATE_COMMANDS_DIR_PREFIX, name);
958 }
959 }
Steve Block71f2cf12011-10-20 11:56:00 +0100960 ALOGV("Transfering from %s to %s: uid=%d\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800961 srcpkg, dstpkg, dstuid);
962 }
963 }
964 }
965 bufp = bufi+1;
966 } else {
967 if (bufp == 0) {
968 if (bufp < bufe) {
Steve Block8564c8d2012-01-05 23:22:43 +0000969 ALOGW("Line too long in %s%s, skipping: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800970 UPDATE_COMMANDS_DIR_PREFIX, name, buf);
971 }
972 } else if (bufp < bufe) {
973 memcpy(buf, buf+bufp, bufe-bufp);
974 bufe -= bufp;
975 bufp = 0;
976 }
977 readlen = read(subfd, buf+bufe, PKG_PATH_MAX-bufe);
978 if (readlen < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000979 ALOGW("Failure reading update commands in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800980 UPDATE_COMMANDS_DIR_PREFIX, name, strerror(errno));
981 break;
982 } else if (readlen == 0) {
983 break;
984 }
985 bufe += readlen;
986 buf[bufe] = 0;
Steve Block71f2cf12011-10-20 11:56:00 +0100987 ALOGV("Read buf: %s\n", buf);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800988 }
989 }
990 close(subfd);
991 }
992 }
993 closedir(d);
994done:
995 return 0;
996}
Kenny Root6a6b0072010-10-07 16:46:10 -0700997
998int linklib(const char* dataDir, const char* asecLibDir)
999{
1000 char libdir[PKG_PATH_MAX];
1001 struct stat s, libStat;
1002 int rc = 0;
1003
1004 const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
1005 if (libdirLen >= PKG_PATH_MAX) {
Steve Block3762c312012-01-06 19:20:56 +00001006 ALOGE("library dir len too large");
Kenny Root0332d1c2010-10-21 16:14:06 -07001007 return -1;
Kenny Root6a6b0072010-10-07 16:46:10 -07001008 }
1009
1010 if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
Steve Block3762c312012-01-06 19:20:56 +00001011 ALOGE("library dir not written successfully: %s\n", strerror(errno));
Kenny Root0332d1c2010-10-21 16:14:06 -07001012 return -1;
Kenny Root6a6b0072010-10-07 16:46:10 -07001013 }
1014
1015 if (stat(dataDir, &s) < 0) return -1;
1016
1017 if (chown(dataDir, 0, 0) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001018 ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001019 return -1;
1020 }
1021
1022 if (chmod(dataDir, 0700) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001023 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001024 rc = -1;
1025 goto out;
1026 }
1027
1028 if (lstat(libdir, &libStat) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001029 ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001030 rc = -1;
1031 goto out;
1032 }
1033
1034 if (S_ISDIR(libStat.st_mode)) {
1035 if (delete_dir_contents(libdir, 1, 0) < 0) {
1036 rc = -1;
1037 goto out;
1038 }
1039 } else if (S_ISLNK(libStat.st_mode)) {
1040 if (unlink(libdir) < 0) {
1041 rc = -1;
1042 goto out;
1043 }
1044 }
1045
1046 if (symlink(asecLibDir, libdir) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001047 ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libdir, asecLibDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001048 rc = -errno;
1049 goto out;
1050 }
1051
1052 if (lchown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001053 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001054 unlink(libdir);
1055 rc = -errno;
1056 goto out;
1057 }
1058
1059out:
1060 if (chmod(dataDir, s.st_mode) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001061 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Dianne Hackbornd0c5f512012-06-07 16:53:59 -07001062 rc = -errno;
Kenny Root6a6b0072010-10-07 16:46:10 -07001063 }
1064
1065 if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001066 ALOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001067 return -errno;
1068 }
1069
1070 return rc;
1071}
1072
1073int unlinklib(const char* dataDir)
1074{
1075 char libdir[PKG_PATH_MAX];
1076 struct stat s, libStat;
1077 int rc = 0;
1078
1079 const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
1080 if (libdirLen >= PKG_PATH_MAX) {
1081 return -1;
1082 }
1083
1084 if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
Steve Block3762c312012-01-06 19:20:56 +00001085 ALOGE("library dir not written successfully: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001086 return -1;
1087 }
1088
1089 if (stat(dataDir, &s) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001090 ALOGE("couldn't state data dir");
Kenny Root6a6b0072010-10-07 16:46:10 -07001091 return -1;
1092 }
1093
1094 if (chown(dataDir, 0, 0) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001095 ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001096 return -1;
1097 }
1098
1099 if (chmod(dataDir, 0700) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001100 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001101 rc = -1;
1102 goto out;
1103 }
1104
1105 if (lstat(libdir, &libStat) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001106 ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001107 rc = -1;
1108 goto out;
1109 }
1110
1111 if (S_ISDIR(libStat.st_mode)) {
1112 if (delete_dir_contents(libdir, 1, 0) < 0) {
1113 rc = -1;
1114 goto out;
1115 }
1116 } else if (S_ISLNK(libStat.st_mode)) {
1117 if (unlink(libdir) < 0) {
1118 rc = -1;
1119 goto out;
1120 }
1121 }
1122
1123 if (mkdir(libdir, 0755) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001124 ALOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001125 rc = -errno;
1126 goto out;
1127 }
Kenny Root515087d2012-07-30 15:00:16 -07001128 if (chmod(libdir, 0755) < 0) {
1129 ALOGE("cannot chmod dir '%s': %s\n", libdir, strerror(errno));
1130 unlink(libdir);
1131 rc = -errno;
1132 goto out;
1133 }
Kenny Root6a6b0072010-10-07 16:46:10 -07001134 if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001135 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001136 unlink(libdir);
1137 rc = -errno;
1138 goto out;
1139 }
1140
1141out:
1142 if (chmod(dataDir, s.st_mode) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001143 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Dianne Hackbornd0c5f512012-06-07 16:53:59 -07001144 rc = -1;
Kenny Root6a6b0072010-10-07 16:46:10 -07001145 }
1146
1147 if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001148 ALOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001149 return -1;
1150 }
1151
1152 return rc;
1153}