blob: ab64747ab801867c62a4d7de0e7acd4aff0d89bd [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) {
Joshua Brindle365861e2012-07-10 10:22:36 -040082 ALOGE("cannot setfilecon dir '%s': %s\n", libdir, strerror(errno));
Stephen Smalley0b58e6a2012-01-13 08:27:42 -050083 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) {
Joshua Brindle365861e2012-07-10 10:22:36 -040098 ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
Kenny Root33ef4ee2012-06-18 10:26:36 -070099 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 }
Amith Yamasani794d62f2012-08-24 12:58:27 -0700197 if (chmod(pkgdir, 0751) < 0) {
198 ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
199 unlink(pkgdir);
200 return -errno;
201 }
Amith Yamasani0b285492011-04-14 17:35:23 -0700202 if (chown(pkgdir, uid, uid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000203 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
Amith Yamasani0b285492011-04-14 17:35:23 -0700204 unlink(pkgdir);
205 return -errno;
206 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500207
208#ifdef HAVE_SELINUX
209 if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
Joshua Brindle365861e2012-07-10 10:22:36 -0400210 ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500211 unlink(pkgdir);
212 return -errno;
213 }
214#endif
215
Amith Yamasani0b285492011-04-14 17:35:23 -0700216 return 0;
217}
218
219int delete_persona(uid_t persona)
220{
Jeff Sharkey5b1ada22012-08-14 18:47:09 -0700221 char data_path[PKG_PATH_MAX];
222 if (create_persona_path(data_path, persona)) {
Amith Yamasani0b285492011-04-14 17:35:23 -0700223 return -1;
Jeff Sharkey5b1ada22012-08-14 18:47:09 -0700224 }
225 if (delete_dir_contents(data_path, 1, NULL)) {
226 return -1;
227 }
Amith Yamasani0b285492011-04-14 17:35:23 -0700228
Jeff Sharkey5b1ada22012-08-14 18:47:09 -0700229 char media_path[PATH_MAX];
230 if (create_persona_media_path(media_path, (userid_t) persona) == -1) {
231 return -1;
232 }
233 if (delete_dir_contents(media_path, 1, NULL) == -1) {
234 return -1;
235 }
236
237 return 0;
Amith Yamasani0b285492011-04-14 17:35:23 -0700238}
239
Amith Yamasani742a6712011-05-04 14:49:28 -0700240int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy)
241{
242 char src_data_dir[PKG_PATH_MAX];
243 char pkg_path[PKG_PATH_MAX];
244 DIR *d;
245 struct dirent *de;
246 struct stat s;
247 uid_t uid;
248
249 if (create_persona_path(src_data_dir, src_persona)) {
250 return -1;
251 }
252
253 d = opendir(src_data_dir);
254 if (d != NULL) {
255 while ((de = readdir(d))) {
256 const char *name = de->d_name;
257
258 if (de->d_type == DT_DIR) {
259 int subfd;
260 /* always skip "." and ".." */
261 if (name[0] == '.') {
262 if (name[1] == 0) continue;
263 if ((name[1] == '.') && (name[2] == 0)) continue;
264 }
265 /* Create the full path to the package's data dir */
266 create_pkg_path(pkg_path, name, PKG_DIR_POSTFIX, src_persona);
267 /* Get the file stat */
268 if (stat(pkg_path, &s) < 0) continue;
269 /* Get the uid of the package */
270 ALOGI("Adding datadir for uid = %d\n", s.st_uid);
271 uid = (uid_t) s.st_uid % PER_USER_RANGE;
272 /* Create the directory for the target */
273 make_user_data(name, uid + target_persona * PER_USER_RANGE,
274 target_persona);
275 }
276 }
277 closedir(d);
278 }
Jeff Sharkey5b1ada22012-08-14 18:47:09 -0700279
Jeff Sharkey8ea0dc62012-08-27 15:46:54 -0700280 if (ensure_media_user_dirs((userid_t) target_persona) == -1) {
Jeff Sharkey5b1ada22012-08-14 18:47:09 -0700281 return -1;
282 }
Jeff Sharkey8ea0dc62012-08-27 15:46:54 -0700283
Amith Yamasani742a6712011-05-04 14:49:28 -0700284 return 0;
285}
286
Kenny Root35ab3ad2011-02-02 16:42:14 -0800287int delete_cache(const char *pkgname)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288{
289 char cachedir[PKG_PATH_MAX];
290
Kenny Root86c95842011-03-31 13:16:12 -0700291 if (create_pkg_path(cachedir, pkgname, CACHE_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800292 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800293
294 /* delete contents, not the directory, no exceptions */
295 return delete_dir_contents(cachedir, 0, 0);
296}
297
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298/* Try to ensure free_size bytes of storage are available.
299 * Returns 0 on success.
300 * This is rather simple-minded because doing a full LRU would
301 * be potentially memory-intensive, and without atime it would
302 * also require that apps constantly modify file metadata even
303 * when just reading from the cache, which is pretty awful.
304 */
Kenny Root3e319a92010-09-07 13:58:28 -0700305int free_cache(int64_t free_size)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306{
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700307 cache_t* cache;
308 int64_t avail;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800309 DIR *d;
310 struct dirent *de;
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700311 char tmpdir[PATH_MAX];
312 char *dirpos;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800313
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700314 avail = data_disk_free();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315 if (avail < 0) return -1;
316
Steve Block6215d3f2012-01-04 20:05:49 +0000317 ALOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318 if (avail >= free_size) return 0;
319
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700320 cache = start_cache_collection();
321
322 // Collect cache files for primary user.
323 if (create_persona_path(tmpdir, 0) == 0) {
324 //ALOGI("adding cache files from %s\n", tmpdir);
325 add_cache_files(cache, tmpdir, "cache");
Kenny Rootad757e92011-11-29 15:54:55 -0800326 }
327
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700328 // Search for other users and add any cache files from them.
329 snprintf(tmpdir, sizeof(tmpdir), "%s%s", android_data_dir.path,
330 SECONDARY_USER_PREFIX);
331 dirpos = tmpdir + strlen(tmpdir);
332 d = opendir(tmpdir);
333 if (d != NULL) {
334 while ((de = readdir(d))) {
335 if (de->d_type == DT_DIR) {
336 const char *name = de->d_name;
337 /* always skip "." and ".." */
338 if (name[0] == '.') {
339 if (name[1] == 0) continue;
340 if ((name[1] == '.') && (name[2] == 0)) continue;
341 }
342 if ((strlen(name)+(dirpos-tmpdir)) < (sizeof(tmpdir)-1)) {
343 strcpy(dirpos, name);
344 //ALOGI("adding cache files from %s\n", tmpdir);
345 add_cache_files(cache, tmpdir, "cache");
346 } else {
347 ALOGW("Path exceeds limit: %s%s", tmpdir, name);
348 }
349 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 }
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700351 closedir(d);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800352 }
Oscar Montemayora8529f62009-11-18 10:14:20 -0800353
Dianne Hackborn197a0c82012-07-12 14:46:04 -0700354 // Collect cache files on external storage (if it is mounted as part
355 // of the internal storage).
356 strcpy(tmpdir, android_media_dir.path);
357 if (lookup_media_dir(tmpdir, "Android") == 0
358 && lookup_media_dir(tmpdir, "data") == 0) {
359 //ALOGI("adding cache files from %s\n", tmpdir);
360 add_cache_files(cache, tmpdir, "cache");
361 }
362
363 clear_cache_files(cache, free_size);
364 finish_cache_collection(cache);
365
366 return data_disk_free() >= free_size ? 0 : -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367}
368
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369int move_dex(const char *src, const char *dst)
370{
371 char src_dex[PKG_PATH_MAX];
372 char dst_dex[PKG_PATH_MAX];
373
Kenny Root86c95842011-03-31 13:16:12 -0700374 if (validate_apk_path(src)) return -1;
375 if (validate_apk_path(dst)) return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376
377 if (create_cache_path(src_dex, src)) return -1;
378 if (create_cache_path(dst_dex, dst)) return -1;
379
Steve Block71f2cf12011-10-20 11:56:00 +0100380 ALOGV("move %s -> %s\n", src_dex, dst_dex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381 if (rename(src_dex, dst_dex) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000382 ALOGE("Couldn't move %s: %s\n", src_dex, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 return -1;
384 } else {
385 return 0;
386 }
387}
388
389int rm_dex(const char *path)
390{
391 char dex_path[PKG_PATH_MAX];
392
Kenny Root86c95842011-03-31 13:16:12 -0700393 if (validate_apk_path(path)) return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394 if (create_cache_path(dex_path, path)) return -1;
395
Steve Block71f2cf12011-10-20 11:56:00 +0100396 ALOGV("unlink %s\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 if (unlink(dex_path) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000398 ALOGE("Couldn't unlink %s: %s\n", dex_path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 return -1;
400 } else {
401 return 0;
402 }
403}
404
405int protect(char *pkgname, gid_t gid)
406{
407 struct stat s;
408 char pkgpath[PKG_PATH_MAX];
409
410 if (gid < AID_SYSTEM) return -1;
411
Kenny Root86c95842011-03-31 13:16:12 -0700412 if (create_pkg_path_in_dir(pkgpath, &android_app_private_dir, pkgname, ".apk"))
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 return -1;
414
415 if (stat(pkgpath, &s) < 0) return -1;
416
417 if (chown(pkgpath, s.st_uid, gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000418 ALOGE("failed to chgrp '%s': %s\n", pkgpath, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800419 return -1;
420 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421 if (chmod(pkgpath, S_IRUSR|S_IWUSR|S_IRGRP) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000422 ALOGE("failed to chmod '%s': %s\n", pkgpath, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423 return -1;
424 }
425
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500426#ifdef HAVE_SELINUX
427 if (selinux_android_setfilecon(pkgpath, pkgname, s.st_uid) < 0) {
Joshua Brindle365861e2012-07-10 10:22:36 -0400428 ALOGE("cannot setfilecon dir '%s': %s\n", pkgpath, strerror(errno));
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500429 return -1;
430 }
431#endif
432
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433 return 0;
434}
435
Dianne Hackborn0c380492012-08-20 17:23:30 -0700436int get_size(const char *pkgname, int persona, const char *apkpath,
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700437 const char *fwdlock_apkpath, const char *asecpath,
438 int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize,
439 int64_t* _asecsize)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440{
441 DIR *d;
442 int dfd;
443 struct dirent *de;
444 struct stat s;
445 char path[PKG_PATH_MAX];
446
Kenny Root3e319a92010-09-07 13:58:28 -0700447 int64_t codesize = 0;
448 int64_t datasize = 0;
449 int64_t cachesize = 0;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700450 int64_t asecsize = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451
452 /* count the source apk as code -- but only if it's not
Suchi Amalapurapu8a9ab242010-03-11 16:49:16 -0800453 * on the /system partition and its not on the sdcard.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800454 */
Kenny Root86c95842011-03-31 13:16:12 -0700455 if (validate_system_app_path(apkpath) &&
456 strncmp(apkpath, android_asec_dir.path, android_asec_dir.len) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 if (stat(apkpath, &s) == 0) {
458 codesize += stat_size(&s);
459 }
460 }
461 /* count the forward locked apk as code if it is given
462 */
463 if (fwdlock_apkpath != NULL && fwdlock_apkpath[0] != '!') {
464 if (stat(fwdlock_apkpath, &s) == 0) {
465 codesize += stat_size(&s);
466 }
467 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 /* count the cached dexfile as code */
469 if (!create_cache_path(path, apkpath)) {
470 if (stat(path, &s) == 0) {
471 codesize += stat_size(&s);
472 }
473 }
474
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700475 /* compute asec size if it is given
476 */
477 if (asecpath != NULL && asecpath[0] != '!') {
478 if (stat(asecpath, &s) == 0) {
479 asecsize += stat_size(&s);
480 }
481 }
482
Dianne Hackborn0c380492012-08-20 17:23:30 -0700483 if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, persona)) {
Kenny Root35ab3ad2011-02-02 16:42:14 -0800484 goto done;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485 }
486
487 d = opendir(path);
488 if (d == NULL) {
489 goto done;
490 }
491 dfd = dirfd(d);
492
Kenny Root86c95842011-03-31 13:16:12 -0700493 /* most stuff in the pkgdir is data, except for the "cache"
494 * directory and below, which is cache, and the "lib" directory
495 * and below, which is code...
496 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497 while ((de = readdir(d))) {
498 const char *name = de->d_name;
499
500 if (de->d_type == DT_DIR) {
501 int subfd;
502 /* always skip "." and ".." */
503 if (name[0] == '.') {
504 if (name[1] == 0) continue;
505 if ((name[1] == '.') && (name[2] == 0)) continue;
506 }
507 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
508 if (subfd >= 0) {
Kenny Root3e319a92010-09-07 13:58:28 -0700509 int64_t size = calculate_dir_size(subfd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800510 if (!strcmp(name,"lib")) {
511 codesize += size;
512 } else if(!strcmp(name,"cache")) {
513 cachesize += size;
514 } else {
515 datasize += size;
516 }
517 }
518 } else {
519 if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
520 datasize += stat_size(&s);
521 }
522 }
523 }
524 closedir(d);
525done:
526 *_codesize = codesize;
527 *_datasize = datasize;
528 *_cachesize = cachesize;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700529 *_asecsize = asecsize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800530 return 0;
531}
532
533
534/* a simpler version of dexOptGenerateCacheFileName() */
535int create_cache_path(char path[PKG_PATH_MAX], const char *src)
536{
537 char *tmp;
538 int srclen;
539 int dstlen;
540
541 srclen = strlen(src);
542
543 /* demand that we are an absolute path */
544 if ((src == 0) || (src[0] != '/') || strstr(src,"..")) {
545 return -1;
546 }
547
548 if (srclen > PKG_PATH_MAX) { // XXX: PKG_NAME_MAX?
549 return -1;
550 }
551
552 dstlen = srclen + strlen(DALVIK_CACHE_PREFIX) +
553 strlen(DALVIK_CACHE_POSTFIX) + 1;
554
555 if (dstlen > PKG_PATH_MAX) {
556 return -1;
557 }
558
559 sprintf(path,"%s%s%s",
560 DALVIK_CACHE_PREFIX,
561 src + 1, /* skip the leading / */
562 DALVIK_CACHE_POSTFIX);
563
564 for(tmp = path + strlen(DALVIK_CACHE_PREFIX); *tmp; tmp++) {
565 if (*tmp == '/') {
566 *tmp = '@';
567 }
568 }
569
570 return 0;
571}
572
573static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name,
574 const char* dexopt_flags)
575{
576 static const char* DEX_OPT_BIN = "/system/bin/dexopt";
577 static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
578 char zip_num[MAX_INT_LEN];
579 char odex_num[MAX_INT_LEN];
580
581 sprintf(zip_num, "%d", zip_fd);
582 sprintf(odex_num, "%d", odex_fd);
583
584 execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name,
585 dexopt_flags, (char*) NULL);
Steve Block3762c312012-01-06 19:20:56 +0000586 ALOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800587}
588
589static int wait_dexopt(pid_t pid, const char* apk_path)
590{
591 int status;
592 pid_t got_pid;
593
594 /*
595 * Wait for the optimization process to finish.
596 */
597 while (1) {
598 got_pid = waitpid(pid, &status, 0);
599 if (got_pid == -1 && errno == EINTR) {
600 printf("waitpid interrupted, retrying\n");
601 } else {
602 break;
603 }
604 }
605 if (got_pid != pid) {
Steve Block8564c8d2012-01-05 23:22:43 +0000606 ALOGW("waitpid failed: wanted %d, got %d: %s\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607 (int) pid, (int) got_pid, strerror(errno));
608 return 1;
609 }
610
611 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100612 ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613 return 0;
614 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000615 ALOGW("DexInv: --- END '%s' --- status=0x%04x, process failed\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616 apk_path, status);
617 return status; /* always nonzero */
618 }
619}
620
621int dexopt(const char *apk_path, uid_t uid, int is_public)
622{
623 struct utimbuf ut;
624 struct stat apk_stat, dex_stat;
625 char dex_path[PKG_PATH_MAX];
626 char dexopt_flags[PROPERTY_VALUE_MAX];
627 char *end;
628 int res, zip_fd=-1, odex_fd=-1;
629
630 /* Before anything else: is there a .odex file? If so, we have
631 * pre-optimized the apk and there is nothing to do here.
632 */
633 if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
634 return -1;
635 }
636
637 /* platform-specific flags affecting optimization and verification */
638 property_get("dalvik.vm.dexopt-flags", dexopt_flags, "");
639
640 strcpy(dex_path, apk_path);
641 end = strrchr(dex_path, '.');
642 if (end != NULL) {
643 strcpy(end, ".odex");
644 if (stat(dex_path, &dex_stat) == 0) {
645 return 0;
646 }
647 }
648
649 if (create_cache_path(dex_path, apk_path)) {
650 return -1;
651 }
652
653 memset(&apk_stat, 0, sizeof(apk_stat));
654 stat(apk_path, &apk_stat);
655
656 zip_fd = open(apk_path, O_RDONLY, 0);
657 if (zip_fd < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000658 ALOGE("dexopt cannot open '%s' for input\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 return -1;
660 }
661
662 unlink(dex_path);
663 odex_fd = open(dex_path, O_RDWR | O_CREAT | O_EXCL, 0644);
664 if (odex_fd < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000665 ALOGE("dexopt cannot open '%s' for output\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800666 goto fail;
667 }
668 if (fchown(odex_fd, AID_SYSTEM, uid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000669 ALOGE("dexopt cannot chown '%s'\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800670 goto fail;
671 }
672 if (fchmod(odex_fd,
673 S_IRUSR|S_IWUSR|S_IRGRP |
674 (is_public ? S_IROTH : 0)) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000675 ALOGE("dexopt cannot chmod '%s'\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800676 goto fail;
677 }
678
Steve Block71f2cf12011-10-20 11:56:00 +0100679 ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800680
681 pid_t pid;
682 pid = fork();
683 if (pid == 0) {
684 /* child -- drop privileges before continuing */
685 if (setgid(uid) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000686 ALOGE("setgid(%d) failed during dexopt\n", uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800687 exit(64);
688 }
689 if (setuid(uid) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000690 ALOGE("setuid(%d) during dexopt\n", uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800691 exit(65);
692 }
693 if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000694 ALOGE("flock(%s) failed: %s\n", dex_path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695 exit(66);
696 }
697
698 run_dexopt(zip_fd, odex_fd, apk_path, dexopt_flags);
699 exit(67); /* only get here on exec failure */
700 } else {
701 res = wait_dexopt(pid, apk_path);
702 if (res != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000703 ALOGE("dexopt failed on '%s' res = %d\n", dex_path, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800704 goto fail;
705 }
706 }
707
708 ut.actime = apk_stat.st_atime;
709 ut.modtime = apk_stat.st_mtime;
710 utime(dex_path, &ut);
711
712 close(odex_fd);
713 close(zip_fd);
714 return 0;
715
716fail:
717 if (odex_fd >= 0) {
718 close(odex_fd);
719 unlink(dex_path);
720 }
721 if (zip_fd >= 0) {
722 close(zip_fd);
723 }
724 return -1;
725}
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800726
Dianne Hackbornc1552392010-03-03 16:19:01 -0800727void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid,
728 struct stat* statbuf)
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800729{
730 while (path[basepos] != 0) {
731 if (path[basepos] == '/') {
732 path[basepos] = 0;
Dianne Hackbornc1552392010-03-03 16:19:01 -0800733 if (lstat(path, statbuf) < 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100734 ALOGV("Making directory: %s\n", path);
Dianne Hackbornc1552392010-03-03 16:19:01 -0800735 if (mkdir(path, mode) == 0) {
736 chown(path, uid, gid);
737 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000738 ALOGW("Unable to make directory %s: %s\n", path, strerror(errno));
Dianne Hackbornc1552392010-03-03 16:19:01 -0800739 }
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800740 }
741 path[basepos] = '/';
742 basepos++;
743 }
744 basepos++;
745 }
746}
747
Dianne Hackbornc1552392010-03-03 16:19:01 -0800748int movefileordir(char* srcpath, char* dstpath, int dstbasepos,
749 int dstuid, int dstgid, struct stat* statbuf)
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800750{
751 DIR *d;
752 struct dirent *de;
753 int res;
754
755 int srcend = strlen(srcpath);
756 int dstend = strlen(dstpath);
757
758 if (lstat(srcpath, statbuf) < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000759 ALOGW("Unable to stat %s: %s\n", srcpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800760 return 1;
761 }
762
763 if ((statbuf->st_mode&S_IFDIR) == 0) {
Dianne Hackbornc1552392010-03-03 16:19:01 -0800764 mkinnerdirs(dstpath, dstbasepos, S_IRWXU|S_IRWXG|S_IXOTH,
765 dstuid, dstgid, statbuf);
Steve Block71f2cf12011-10-20 11:56:00 +0100766 ALOGV("Renaming %s to %s (uid %d)\n", srcpath, dstpath, dstuid);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800767 if (rename(srcpath, dstpath) >= 0) {
768 if (chown(dstpath, dstuid, dstgid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000769 ALOGE("cannot chown %s: %s\n", dstpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800770 unlink(dstpath);
771 return 1;
772 }
773 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000774 ALOGW("Unable to rename %s to %s: %s\n",
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800775 srcpath, dstpath, strerror(errno));
776 return 1;
777 }
778 return 0;
779 }
780
781 d = opendir(srcpath);
782 if (d == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000783 ALOGW("Unable to opendir %s: %s\n", srcpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800784 return 1;
785 }
786
787 res = 0;
788
789 while ((de = readdir(d))) {
790 const char *name = de->d_name;
791 /* always skip "." and ".." */
792 if (name[0] == '.') {
793 if (name[1] == 0) continue;
794 if ((name[1] == '.') && (name[2] == 0)) continue;
795 }
796
797 if ((srcend+strlen(name)) >= (PKG_PATH_MAX-2)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000798 ALOGW("Source path too long; skipping: %s/%s\n", srcpath, name);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800799 continue;
800 }
801
802 if ((dstend+strlen(name)) >= (PKG_PATH_MAX-2)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000803 ALOGW("Destination path too long; skipping: %s/%s\n", dstpath, name);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800804 continue;
805 }
806
807 srcpath[srcend] = dstpath[dstend] = '/';
808 strcpy(srcpath+srcend+1, name);
809 strcpy(dstpath+dstend+1, name);
810
Dianne Hackbornc1552392010-03-03 16:19:01 -0800811 if (movefileordir(srcpath, dstpath, dstbasepos, dstuid, dstgid, statbuf) != 0) {
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800812 res = 1;
813 }
814
815 // Note: we will be leaving empty directories behind in srcpath,
816 // but that is okay, the package manager will be erasing all of the
817 // data associated with .apks that disappear.
818
819 srcpath[srcend] = dstpath[dstend] = 0;
820 }
821
822 closedir(d);
823 return res;
824}
825
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800826int movefiles()
827{
828 DIR *d;
829 int dfd, subfd;
830 struct dirent *de;
831 struct stat s;
832 char buf[PKG_PATH_MAX+1];
833 int bufp, bufe, bufi, readlen;
834
835 char srcpkg[PKG_NAME_MAX];
836 char dstpkg[PKG_NAME_MAX];
837 char srcpath[PKG_PATH_MAX];
838 char dstpath[PKG_PATH_MAX];
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800839 int dstuid=-1, dstgid=-1;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800840 int hasspace;
841
842 d = opendir(UPDATE_COMMANDS_DIR_PREFIX);
843 if (d == NULL) {
844 goto done;
845 }
846 dfd = dirfd(d);
847
848 /* Iterate through all files in the directory, executing the
849 * file movements requested there-in.
850 */
851 while ((de = readdir(d))) {
852 const char *name = de->d_name;
853
854 if (de->d_type == DT_DIR) {
855 continue;
856 } else {
857 subfd = openat(dfd, name, O_RDONLY);
858 if (subfd < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000859 ALOGW("Unable to open update commands at %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800860 UPDATE_COMMANDS_DIR_PREFIX, name);
861 continue;
862 }
863
864 bufp = 0;
865 bufe = 0;
866 buf[PKG_PATH_MAX] = 0;
867 srcpkg[0] = dstpkg[0] = 0;
868 while (1) {
869 bufi = bufp;
870 while (bufi < bufe && buf[bufi] != '\n') {
871 bufi++;
872 }
873 if (bufi < bufe) {
874 buf[bufi] = 0;
Steve Block71f2cf12011-10-20 11:56:00 +0100875 ALOGV("Processing line: %s\n", buf+bufp);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800876 hasspace = 0;
877 while (bufp < bufi && isspace(buf[bufp])) {
878 hasspace = 1;
879 bufp++;
880 }
881 if (buf[bufp] == '#' || bufp == bufi) {
882 // skip comments and empty lines.
883 } else if (hasspace) {
884 if (dstpkg[0] == 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000885 ALOGW("Path before package line in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800886 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
887 } else if (srcpkg[0] == 0) {
888 // Skip -- source package no longer exists.
889 } else {
Steve Block71f2cf12011-10-20 11:56:00 +0100890 ALOGV("Move file: %s (from %s to %s)\n", buf+bufp, srcpkg, dstpkg);
Kenny Root86c95842011-03-31 13:16:12 -0700891 if (!create_move_path(srcpath, srcpkg, buf+bufp, 0) &&
892 !create_move_path(dstpath, dstpkg, buf+bufp, 0)) {
Dianne Hackbornc1552392010-03-03 16:19:01 -0800893 movefileordir(srcpath, dstpath,
894 strlen(dstpath)-strlen(buf+bufp),
895 dstuid, dstgid, &s);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800896 }
897 }
898 } else {
899 char* div = strchr(buf+bufp, ':');
900 if (div == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000901 ALOGW("Bad package spec in %s%s; no ':' sep: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800902 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
903 } else {
904 *div = 0;
905 div++;
906 if (strlen(buf+bufp) < PKG_NAME_MAX) {
907 strcpy(dstpkg, buf+bufp);
908 } else {
909 srcpkg[0] = dstpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000910 ALOGW("Package name too long in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800911 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
912 }
913 if (strlen(div) < PKG_NAME_MAX) {
914 strcpy(srcpkg, div);
915 } else {
916 srcpkg[0] = dstpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000917 ALOGW("Package name too long in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800918 UPDATE_COMMANDS_DIR_PREFIX, name, div);
919 }
920 if (srcpkg[0] != 0) {
Kenny Root86c95842011-03-31 13:16:12 -0700921 if (!create_pkg_path(srcpath, srcpkg, PKG_DIR_POSTFIX, 0)) {
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800922 if (lstat(srcpath, &s) < 0) {
923 // Package no longer exists -- skip.
924 srcpkg[0] = 0;
925 }
926 } else {
927 srcpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000928 ALOGW("Can't create path %s in %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800929 div, UPDATE_COMMANDS_DIR_PREFIX, name);
930 }
931 if (srcpkg[0] != 0) {
Kenny Root86c95842011-03-31 13:16:12 -0700932 if (!create_pkg_path(dstpath, dstpkg, PKG_DIR_POSTFIX, 0)) {
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800933 if (lstat(dstpath, &s) == 0) {
934 dstuid = s.st_uid;
935 dstgid = s.st_gid;
936 } else {
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800937 // Destination package doesn't
938 // exist... due to original-package,
939 // this is normal, so don't be
940 // noisy about it.
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800941 srcpkg[0] = 0;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800942 }
943 } else {
944 srcpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000945 ALOGW("Can't create path %s in %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800946 div, UPDATE_COMMANDS_DIR_PREFIX, name);
947 }
948 }
Steve Block71f2cf12011-10-20 11:56:00 +0100949 ALOGV("Transfering from %s to %s: uid=%d\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800950 srcpkg, dstpkg, dstuid);
951 }
952 }
953 }
954 bufp = bufi+1;
955 } else {
956 if (bufp == 0) {
957 if (bufp < bufe) {
Steve Block8564c8d2012-01-05 23:22:43 +0000958 ALOGW("Line too long in %s%s, skipping: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800959 UPDATE_COMMANDS_DIR_PREFIX, name, buf);
960 }
961 } else if (bufp < bufe) {
962 memcpy(buf, buf+bufp, bufe-bufp);
963 bufe -= bufp;
964 bufp = 0;
965 }
966 readlen = read(subfd, buf+bufe, PKG_PATH_MAX-bufe);
967 if (readlen < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000968 ALOGW("Failure reading update commands in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800969 UPDATE_COMMANDS_DIR_PREFIX, name, strerror(errno));
970 break;
971 } else if (readlen == 0) {
972 break;
973 }
974 bufe += readlen;
975 buf[bufe] = 0;
Steve Block71f2cf12011-10-20 11:56:00 +0100976 ALOGV("Read buf: %s\n", buf);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800977 }
978 }
979 close(subfd);
980 }
981 }
982 closedir(d);
983done:
984 return 0;
985}
Kenny Root6a6b0072010-10-07 16:46:10 -0700986
987int linklib(const char* dataDir, const char* asecLibDir)
988{
989 char libdir[PKG_PATH_MAX];
990 struct stat s, libStat;
991 int rc = 0;
992
993 const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
994 if (libdirLen >= PKG_PATH_MAX) {
Steve Block3762c312012-01-06 19:20:56 +0000995 ALOGE("library dir len too large");
Kenny Root0332d1c2010-10-21 16:14:06 -0700996 return -1;
Kenny Root6a6b0072010-10-07 16:46:10 -0700997 }
998
999 if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
Steve Block3762c312012-01-06 19:20:56 +00001000 ALOGE("library dir not written successfully: %s\n", strerror(errno));
Kenny Root0332d1c2010-10-21 16:14:06 -07001001 return -1;
Kenny Root6a6b0072010-10-07 16:46:10 -07001002 }
1003
1004 if (stat(dataDir, &s) < 0) return -1;
1005
1006 if (chown(dataDir, 0, 0) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001007 ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001008 return -1;
1009 }
1010
1011 if (chmod(dataDir, 0700) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001012 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001013 rc = -1;
1014 goto out;
1015 }
1016
1017 if (lstat(libdir, &libStat) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001018 ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001019 rc = -1;
1020 goto out;
1021 }
1022
1023 if (S_ISDIR(libStat.st_mode)) {
1024 if (delete_dir_contents(libdir, 1, 0) < 0) {
1025 rc = -1;
1026 goto out;
1027 }
1028 } else if (S_ISLNK(libStat.st_mode)) {
1029 if (unlink(libdir) < 0) {
1030 rc = -1;
1031 goto out;
1032 }
1033 }
1034
1035 if (symlink(asecLibDir, libdir) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001036 ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libdir, asecLibDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001037 rc = -errno;
1038 goto out;
1039 }
1040
1041 if (lchown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001042 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001043 unlink(libdir);
1044 rc = -errno;
1045 goto out;
1046 }
1047
1048out:
1049 if (chmod(dataDir, s.st_mode) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001050 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Dianne Hackbornd0c5f512012-06-07 16:53:59 -07001051 rc = -errno;
Kenny Root6a6b0072010-10-07 16:46:10 -07001052 }
1053
1054 if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001055 ALOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001056 return -errno;
1057 }
1058
1059 return rc;
1060}
1061
1062int unlinklib(const char* dataDir)
1063{
1064 char libdir[PKG_PATH_MAX];
1065 struct stat s, libStat;
1066 int rc = 0;
1067
1068 const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
1069 if (libdirLen >= PKG_PATH_MAX) {
1070 return -1;
1071 }
1072
1073 if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
Steve Block3762c312012-01-06 19:20:56 +00001074 ALOGE("library dir not written successfully: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001075 return -1;
1076 }
1077
1078 if (stat(dataDir, &s) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001079 ALOGE("couldn't state data dir");
Kenny Root6a6b0072010-10-07 16:46:10 -07001080 return -1;
1081 }
1082
1083 if (chown(dataDir, 0, 0) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001084 ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001085 return -1;
1086 }
1087
1088 if (chmod(dataDir, 0700) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001089 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001090 rc = -1;
1091 goto out;
1092 }
1093
1094 if (lstat(libdir, &libStat) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001095 ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001096 rc = -1;
1097 goto out;
1098 }
1099
1100 if (S_ISDIR(libStat.st_mode)) {
1101 if (delete_dir_contents(libdir, 1, 0) < 0) {
1102 rc = -1;
1103 goto out;
1104 }
1105 } else if (S_ISLNK(libStat.st_mode)) {
1106 if (unlink(libdir) < 0) {
1107 rc = -1;
1108 goto out;
1109 }
1110 }
1111
1112 if (mkdir(libdir, 0755) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001113 ALOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001114 rc = -errno;
1115 goto out;
1116 }
Kenny Root515087d2012-07-30 15:00:16 -07001117 if (chmod(libdir, 0755) < 0) {
1118 ALOGE("cannot chmod dir '%s': %s\n", libdir, strerror(errno));
1119 unlink(libdir);
1120 rc = -errno;
1121 goto out;
1122 }
Kenny Root6a6b0072010-10-07 16:46:10 -07001123 if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001124 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001125 unlink(libdir);
1126 rc = -errno;
1127 goto out;
1128 }
1129
1130out:
1131 if (chmod(dataDir, s.st_mode) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001132 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Dianne Hackbornd0c5f512012-06-07 16:53:59 -07001133 rc = -1;
Kenny Root6a6b0072010-10-07 16:46:10 -07001134 }
1135
1136 if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001137 ALOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001138 return -1;
1139 }
1140
1141 return rc;
1142}