blob: 0d0a6f0740ef0bd16aac7994bbe682b8759e88b4 [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>
Stephen Smalley0b58e6a2012-01-13 08:27:42 -050019#include <selinux/android.h>
Stephen Smalley0b58e6a2012-01-13 08:27:42 -050020
Kenny Root86c95842011-03-31 13:16:12 -070021/* Directory records that are used in execution of commands. */
22dir_rec_t android_data_dir;
23dir_rec_t android_asec_dir;
24dir_rec_t android_app_dir;
25dir_rec_t android_app_private_dir;
26dir_rec_array_t android_system_dirs;
27
Kenny Root35ab3ad2011-02-02 16:42:14 -080028int install(const char *pkgname, uid_t uid, gid_t gid)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029{
30 char pkgdir[PKG_PATH_MAX];
31 char libdir[PKG_PATH_MAX];
32
33 if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
Steve Block3762c312012-01-06 19:20:56 +000034 ALOGE("invalid uid/gid: %d %d\n", uid, gid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036 }
Oscar Montemayora8529f62009-11-18 10:14:20 -080037
Kenny Root86c95842011-03-31 13:16:12 -070038 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
Steve Block3762c312012-01-06 19:20:56 +000039 ALOGE("cannot create package path\n");
Kenny Root35ab3ad2011-02-02 16:42:14 -080040 return -1;
Kenny Root86c95842011-03-31 13:16:12 -070041 }
42
43 if (create_pkg_path(libdir, pkgname, PKG_LIB_POSTFIX, 0)) {
Steve Block3762c312012-01-06 19:20:56 +000044 ALOGE("cannot create package lib path\n");
Kenny Root35ab3ad2011-02-02 16:42:14 -080045 return -1;
Kenny Root86c95842011-03-31 13:16:12 -070046 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047
David 'Digit' Turner0dd50e62010-02-09 19:02:38 -080048 if (mkdir(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000049 ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050 return -errno;
51 }
Nick Kralevichf68327e2011-04-14 16:20:03 -070052 if (chmod(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000053 ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
Nick Kralevichf68327e2011-04-14 16:20:03 -070054 unlink(pkgdir);
55 return -errno;
56 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -050057
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058 if (mkdir(libdir, 0755) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000059 ALOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060 unlink(pkgdir);
61 return -errno;
62 }
Nick Kralevichf68327e2011-04-14 16:20:03 -070063 if (chmod(libdir, 0755) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000064 ALOGE("cannot chmod dir '%s': %s\n", libdir, strerror(errno));
Nick Kralevichf68327e2011-04-14 16:20:03 -070065 unlink(libdir);
66 unlink(pkgdir);
67 return -errno;
68 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069 if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000070 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071 unlink(libdir);
72 unlink(pkgdir);
73 return -errno;
74 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -050075
Kenny Root57c63d82012-10-17 09:50:35 -070076 if (selinux_android_setfilecon(libdir, pkgname, AID_SYSTEM) < 0) {
Joshua Brindle365861e2012-07-10 10:22:36 -040077 ALOGE("cannot setfilecon dir '%s': %s\n", libdir, strerror(errno));
Stephen Smalley0b58e6a2012-01-13 08:27:42 -050078 unlink(libdir);
79 unlink(pkgdir);
80 return -errno;
81 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -050082
Kenny Root57c63d82012-10-17 09:50:35 -070083 if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
84 ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
85 unlink(libdir);
86 unlink(pkgdir);
87 return -errno;
88 }
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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097 return 0;
98}
99
Amith Yamasani0b285492011-04-14 17:35:23 -0700100int uninstall(const char *pkgname, uid_t persona)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101{
102 char pkgdir[PKG_PATH_MAX];
103
Amith Yamasani0b285492011-04-14 17:35:23 -0700104 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800105 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106
Amith Yamasani0b285492011-04-14 17:35:23 -0700107 /* delete contents AND directory, no exceptions */
108 return delete_dir_contents(pkgdir, 1, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109}
110
Kenny Root35ab3ad2011-02-02 16:42:14 -0800111int renamepkg(const char *oldpkgname, const char *newpkgname)
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800112{
113 char oldpkgdir[PKG_PATH_MAX];
114 char newpkgdir[PKG_PATH_MAX];
115
Kenny Root86c95842011-03-31 13:16:12 -0700116 if (create_pkg_path(oldpkgdir, oldpkgname, PKG_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800117 return -1;
Kenny Root86c95842011-03-31 13:16:12 -0700118 if (create_pkg_path(newpkgdir, newpkgname, PKG_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800119 return -1;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800120
121 if (rename(oldpkgdir, newpkgdir) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000122 ALOGE("cannot rename dir '%s' to '%s': %s\n", oldpkgdir, newpkgdir, strerror(errno));
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800123 return -errno;
124 }
125 return 0;
126}
127
Dianne Hackbornd0c5f512012-06-07 16:53:59 -0700128int fix_uid(const char *pkgname, uid_t uid, gid_t gid)
129{
130 char pkgdir[PKG_PATH_MAX];
131 struct stat s;
132 int rc = 0;
133
134 if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
135 ALOGE("invalid uid/gid: %d %d\n", uid, gid);
136 return -1;
137 }
138
139 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
140 ALOGE("cannot create package path\n");
141 return -1;
142 }
143
144 if (stat(pkgdir, &s) < 0) return -1;
145
146 if (s.st_uid != 0 || s.st_gid != 0) {
147 ALOGE("fixing uid of non-root pkg: %s %d %d\n", pkgdir, s.st_uid, s.st_gid);
148 return -1;
149 }
150
151 if (chmod(pkgdir, 0751) < 0) {
152 ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
153 unlink(pkgdir);
154 return -errno;
155 }
156 if (chown(pkgdir, uid, gid) < 0) {
157 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
158 unlink(pkgdir);
159 return -errno;
160 }
161
162 return 0;
163}
164
Amith Yamasani0b285492011-04-14 17:35:23 -0700165int delete_user_data(const char *pkgname, uid_t persona)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166{
167 char pkgdir[PKG_PATH_MAX];
168
Amith Yamasani0b285492011-04-14 17:35:23 -0700169 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800170 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171
Amith Yamasani0b285492011-04-14 17:35:23 -0700172 /* delete contents, excluding "lib", but not the directory itself */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173 return delete_dir_contents(pkgdir, 0, "lib");
174}
175
Amith Yamasani0b285492011-04-14 17:35:23 -0700176int make_user_data(const char *pkgname, uid_t uid, uid_t persona)
177{
178 char pkgdir[PKG_PATH_MAX];
179 char real_libdir[PKG_PATH_MAX];
180
181 // Create the data dir for the package
182 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona)) {
183 return -1;
184 }
185 if (mkdir(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000186 ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
Amith Yamasani0b285492011-04-14 17:35:23 -0700187 return -errno;
188 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500189 if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
Joshua Brindle365861e2012-07-10 10:22:36 -0400190 ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500191 unlink(pkgdir);
192 return -errno;
193 }
Kenny Rootc9a1aab2012-10-16 23:28:21 -0700194 if (chown(pkgdir, uid, uid) < 0) {
195 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
196 unlink(pkgdir);
197 return -errno;
198 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500199
Amith Yamasani0b285492011-04-14 17:35:23 -0700200 return 0;
201}
202
203int delete_persona(uid_t persona)
204{
205 char pkgdir[PKG_PATH_MAX];
206
207 if (create_persona_path(pkgdir, persona))
208 return -1;
209
210 return delete_dir_contents(pkgdir, 1, NULL);
211}
212
Amith Yamasani742a6712011-05-04 14:49:28 -0700213int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy)
214{
215 char src_data_dir[PKG_PATH_MAX];
216 char pkg_path[PKG_PATH_MAX];
217 DIR *d;
218 struct dirent *de;
219 struct stat s;
220 uid_t uid;
221
222 if (create_persona_path(src_data_dir, src_persona)) {
223 return -1;
224 }
225
226 d = opendir(src_data_dir);
227 if (d != NULL) {
228 while ((de = readdir(d))) {
229 const char *name = de->d_name;
230
231 if (de->d_type == DT_DIR) {
232 int subfd;
233 /* always skip "." and ".." */
234 if (name[0] == '.') {
235 if (name[1] == 0) continue;
236 if ((name[1] == '.') && (name[2] == 0)) continue;
237 }
238 /* Create the full path to the package's data dir */
239 create_pkg_path(pkg_path, name, PKG_DIR_POSTFIX, src_persona);
240 /* Get the file stat */
241 if (stat(pkg_path, &s) < 0) continue;
242 /* Get the uid of the package */
243 ALOGI("Adding datadir for uid = %d\n", s.st_uid);
244 uid = (uid_t) s.st_uid % PER_USER_RANGE;
245 /* Create the directory for the target */
246 make_user_data(name, uid + target_persona * PER_USER_RANGE,
247 target_persona);
248 }
249 }
250 closedir(d);
251 }
252 return 0;
253}
254
Kenny Root35ab3ad2011-02-02 16:42:14 -0800255int delete_cache(const char *pkgname)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256{
257 char cachedir[PKG_PATH_MAX];
258
Kenny Root86c95842011-03-31 13:16:12 -0700259 if (create_pkg_path(cachedir, pkgname, CACHE_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800260 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261
262 /* delete contents, not the directory, no exceptions */
263 return delete_dir_contents(cachedir, 0, 0);
264}
265
Kenny Root3e319a92010-09-07 13:58:28 -0700266static int64_t disk_free()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267{
268 struct statfs sfs;
Kenny Root86c95842011-03-31 13:16:12 -0700269 if (statfs(android_data_dir.path, &sfs) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 return sfs.f_bavail * sfs.f_bsize;
271 } else {
Steve Block3762c312012-01-06 19:20:56 +0000272 ALOGE("Couldn't statfs %s: %s\n", android_data_dir.path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 return -1;
274 }
275}
276
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800277/* Try to ensure free_size bytes of storage are available.
278 * Returns 0 on success.
279 * This is rather simple-minded because doing a full LRU would
280 * be potentially memory-intensive, and without atime it would
281 * also require that apps constantly modify file metadata even
282 * when just reading from the cache, which is pretty awful.
283 */
Kenny Root3e319a92010-09-07 13:58:28 -0700284int free_cache(int64_t free_size)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285{
286 const char *name;
287 int dfd, subfd;
288 DIR *d;
289 struct dirent *de;
Kenny Root3e319a92010-09-07 13:58:28 -0700290 int64_t avail;
Kenny Rootad757e92011-11-29 15:54:55 -0800291 char datadir[PKG_PATH_MAX];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800292
293 avail = disk_free();
294 if (avail < 0) return -1;
295
Steve Block6215d3f2012-01-04 20:05:49 +0000296 ALOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297 if (avail >= free_size) return 0;
298
Kenny Rootad757e92011-11-29 15:54:55 -0800299 if (create_persona_path(datadir, 0)) {
Steve Block3762c312012-01-06 19:20:56 +0000300 ALOGE("couldn't get directory for persona 0");
Kenny Rootad757e92011-11-29 15:54:55 -0800301 return -1;
302 }
303
304 d = opendir(datadir);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800305 if (d == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000306 ALOGE("cannot open %s: %s\n", datadir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800307 return -1;
308 }
309 dfd = dirfd(d);
310
311 while ((de = readdir(d))) {
312 if (de->d_type != DT_DIR) continue;
313 name = de->d_name;
314
Oscar Montemayora8529f62009-11-18 10:14:20 -0800315 /* always skip "." and ".." */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 if (name[0] == '.') {
317 if (name[1] == 0) continue;
318 if ((name[1] == '.') && (name[2] == 0)) continue;
319 }
320
321 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
322 if (subfd < 0) continue;
323
324 delete_dir_contents_fd(subfd, "cache");
325 close(subfd);
326
327 avail = disk_free();
328 if (avail >= free_size) {
329 closedir(d);
330 return 0;
331 }
332 }
333 closedir(d);
Oscar Montemayora8529f62009-11-18 10:14:20 -0800334
335 /* Fail case - not possible to free space */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 return -1;
337}
338
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339int move_dex(const char *src, const char *dst)
340{
341 char src_dex[PKG_PATH_MAX];
342 char dst_dex[PKG_PATH_MAX];
343
Kenny Root86c95842011-03-31 13:16:12 -0700344 if (validate_apk_path(src)) return -1;
345 if (validate_apk_path(dst)) return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346
347 if (create_cache_path(src_dex, src)) return -1;
348 if (create_cache_path(dst_dex, dst)) return -1;
349
Steve Block71f2cf12011-10-20 11:56:00 +0100350 ALOGV("move %s -> %s\n", src_dex, dst_dex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 if (rename(src_dex, dst_dex) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000352 ALOGE("Couldn't move %s: %s\n", src_dex, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 return -1;
354 } else {
355 return 0;
356 }
357}
358
359int rm_dex(const char *path)
360{
361 char dex_path[PKG_PATH_MAX];
362
Kenny Root86c95842011-03-31 13:16:12 -0700363 if (validate_apk_path(path)) return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364 if (create_cache_path(dex_path, path)) return -1;
365
Steve Block71f2cf12011-10-20 11:56:00 +0100366 ALOGV("unlink %s\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 if (unlink(dex_path) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000368 ALOGE("Couldn't unlink %s: %s\n", dex_path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 return -1;
370 } else {
371 return 0;
372 }
373}
374
375int protect(char *pkgname, gid_t gid)
376{
377 struct stat s;
378 char pkgpath[PKG_PATH_MAX];
379
380 if (gid < AID_SYSTEM) return -1;
381
Kenny Root86c95842011-03-31 13:16:12 -0700382 if (create_pkg_path_in_dir(pkgpath, &android_app_private_dir, pkgname, ".apk"))
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 return -1;
384
385 if (stat(pkgpath, &s) < 0) return -1;
386
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 if (chmod(pkgpath, S_IRUSR|S_IWUSR|S_IRGRP) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000388 ALOGE("failed to chmod '%s': %s\n", pkgpath, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 return -1;
390 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500391 if (selinux_android_setfilecon(pkgpath, pkgname, s.st_uid) < 0) {
Joshua Brindle365861e2012-07-10 10:22:36 -0400392 ALOGE("cannot setfilecon dir '%s': %s\n", pkgpath, strerror(errno));
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500393 return -1;
394 }
Kenny Rootc9a1aab2012-10-16 23:28:21 -0700395 if (chown(pkgpath, s.st_uid, gid) < 0) {
396 ALOGE("failed to chgrp '%s': %s\n", pkgpath, strerror(errno));
397 return -1;
398 }
Stephen Smalley0b58e6a2012-01-13 08:27:42 -0500399
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 return 0;
401}
402
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403int get_size(const char *pkgname, const char *apkpath,
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700404 const char *fwdlock_apkpath, const char *asecpath,
405 int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize,
406 int64_t* _asecsize)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407{
408 DIR *d;
409 int dfd;
410 struct dirent *de;
411 struct stat s;
412 char path[PKG_PATH_MAX];
413
Kenny Root3e319a92010-09-07 13:58:28 -0700414 int64_t codesize = 0;
415 int64_t datasize = 0;
416 int64_t cachesize = 0;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700417 int64_t asecsize = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418
419 /* count the source apk as code -- but only if it's not
Suchi Amalapurapu8a9ab242010-03-11 16:49:16 -0800420 * on the /system partition and its not on the sdcard.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421 */
Kenny Root86c95842011-03-31 13:16:12 -0700422 if (validate_system_app_path(apkpath) &&
423 strncmp(apkpath, android_asec_dir.path, android_asec_dir.len) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 if (stat(apkpath, &s) == 0) {
425 codesize += stat_size(&s);
426 }
427 }
428 /* count the forward locked apk as code if it is given
429 */
430 if (fwdlock_apkpath != NULL && fwdlock_apkpath[0] != '!') {
431 if (stat(fwdlock_apkpath, &s) == 0) {
432 codesize += stat_size(&s);
433 }
434 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 /* count the cached dexfile as code */
436 if (!create_cache_path(path, apkpath)) {
437 if (stat(path, &s) == 0) {
438 codesize += stat_size(&s);
439 }
440 }
441
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700442 /* compute asec size if it is given
443 */
444 if (asecpath != NULL && asecpath[0] != '!') {
445 if (stat(asecpath, &s) == 0) {
446 asecsize += stat_size(&s);
447 }
448 }
449
Kenny Root86c95842011-03-31 13:16:12 -0700450 if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, 0)) {
Kenny Root35ab3ad2011-02-02 16:42:14 -0800451 goto done;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 }
453
454 d = opendir(path);
455 if (d == NULL) {
456 goto done;
457 }
458 dfd = dirfd(d);
459
Kenny Root86c95842011-03-31 13:16:12 -0700460 /* most stuff in the pkgdir is data, except for the "cache"
461 * directory and below, which is cache, and the "lib" directory
462 * and below, which is code...
463 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800464 while ((de = readdir(d))) {
465 const char *name = de->d_name;
466
467 if (de->d_type == DT_DIR) {
468 int subfd;
469 /* always skip "." and ".." */
470 if (name[0] == '.') {
471 if (name[1] == 0) continue;
472 if ((name[1] == '.') && (name[2] == 0)) continue;
473 }
474 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
475 if (subfd >= 0) {
Kenny Root3e319a92010-09-07 13:58:28 -0700476 int64_t size = calculate_dir_size(subfd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800477 if (!strcmp(name,"lib")) {
478 codesize += size;
479 } else if(!strcmp(name,"cache")) {
480 cachesize += size;
481 } else {
482 datasize += size;
483 }
484 }
485 } else {
486 if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
487 datasize += stat_size(&s);
488 }
489 }
490 }
491 closedir(d);
492done:
493 *_codesize = codesize;
494 *_datasize = datasize;
495 *_cachesize = cachesize;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700496 *_asecsize = asecsize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800497 return 0;
498}
499
500
501/* a simpler version of dexOptGenerateCacheFileName() */
502int create_cache_path(char path[PKG_PATH_MAX], const char *src)
503{
504 char *tmp;
505 int srclen;
506 int dstlen;
507
508 srclen = strlen(src);
509
510 /* demand that we are an absolute path */
511 if ((src == 0) || (src[0] != '/') || strstr(src,"..")) {
512 return -1;
513 }
514
515 if (srclen > PKG_PATH_MAX) { // XXX: PKG_NAME_MAX?
516 return -1;
517 }
518
519 dstlen = srclen + strlen(DALVIK_CACHE_PREFIX) +
520 strlen(DALVIK_CACHE_POSTFIX) + 1;
521
522 if (dstlen > PKG_PATH_MAX) {
523 return -1;
524 }
525
526 sprintf(path,"%s%s%s",
527 DALVIK_CACHE_PREFIX,
528 src + 1, /* skip the leading / */
529 DALVIK_CACHE_POSTFIX);
530
531 for(tmp = path + strlen(DALVIK_CACHE_PREFIX); *tmp; tmp++) {
532 if (*tmp == '/') {
533 *tmp = '@';
534 }
535 }
536
537 return 0;
538}
539
540static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name,
541 const char* dexopt_flags)
542{
543 static const char* DEX_OPT_BIN = "/system/bin/dexopt";
544 static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
545 char zip_num[MAX_INT_LEN];
546 char odex_num[MAX_INT_LEN];
547
548 sprintf(zip_num, "%d", zip_fd);
549 sprintf(odex_num, "%d", odex_fd);
550
551 execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name,
552 dexopt_flags, (char*) NULL);
Steve Block3762c312012-01-06 19:20:56 +0000553 ALOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800554}
555
556static int wait_dexopt(pid_t pid, const char* apk_path)
557{
558 int status;
559 pid_t got_pid;
560
561 /*
562 * Wait for the optimization process to finish.
563 */
564 while (1) {
565 got_pid = waitpid(pid, &status, 0);
566 if (got_pid == -1 && errno == EINTR) {
567 printf("waitpid interrupted, retrying\n");
568 } else {
569 break;
570 }
571 }
572 if (got_pid != pid) {
Steve Block8564c8d2012-01-05 23:22:43 +0000573 ALOGW("waitpid failed: wanted %d, got %d: %s\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800574 (int) pid, (int) got_pid, strerror(errno));
575 return 1;
576 }
577
578 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100579 ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 return 0;
581 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000582 ALOGW("DexInv: --- END '%s' --- status=0x%04x, process failed\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 apk_path, status);
584 return status; /* always nonzero */
585 }
586}
587
588int dexopt(const char *apk_path, uid_t uid, int is_public)
589{
590 struct utimbuf ut;
591 struct stat apk_stat, dex_stat;
592 char dex_path[PKG_PATH_MAX];
593 char dexopt_flags[PROPERTY_VALUE_MAX];
594 char *end;
595 int res, zip_fd=-1, odex_fd=-1;
596
597 /* Before anything else: is there a .odex file? If so, we have
598 * pre-optimized the apk and there is nothing to do here.
599 */
600 if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
601 return -1;
602 }
603
604 /* platform-specific flags affecting optimization and verification */
605 property_get("dalvik.vm.dexopt-flags", dexopt_flags, "");
606
607 strcpy(dex_path, apk_path);
608 end = strrchr(dex_path, '.');
609 if (end != NULL) {
610 strcpy(end, ".odex");
611 if (stat(dex_path, &dex_stat) == 0) {
612 return 0;
613 }
614 }
615
616 if (create_cache_path(dex_path, apk_path)) {
617 return -1;
618 }
619
620 memset(&apk_stat, 0, sizeof(apk_stat));
621 stat(apk_path, &apk_stat);
622
623 zip_fd = open(apk_path, O_RDONLY, 0);
624 if (zip_fd < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000625 ALOGE("dexopt cannot open '%s' for input\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800626 return -1;
627 }
628
629 unlink(dex_path);
630 odex_fd = open(dex_path, O_RDWR | O_CREAT | O_EXCL, 0644);
631 if (odex_fd < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000632 ALOGE("dexopt cannot open '%s' for output\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 goto fail;
634 }
635 if (fchown(odex_fd, AID_SYSTEM, uid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000636 ALOGE("dexopt cannot chown '%s'\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 goto fail;
638 }
639 if (fchmod(odex_fd,
640 S_IRUSR|S_IWUSR|S_IRGRP |
641 (is_public ? S_IROTH : 0)) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000642 ALOGE("dexopt cannot chmod '%s'\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800643 goto fail;
644 }
645
Steve Block71f2cf12011-10-20 11:56:00 +0100646 ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647
648 pid_t pid;
649 pid = fork();
650 if (pid == 0) {
651 /* child -- drop privileges before continuing */
652 if (setgid(uid) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000653 ALOGE("setgid(%d) failed during dexopt\n", uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800654 exit(64);
655 }
656 if (setuid(uid) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000657 ALOGE("setuid(%d) during dexopt\n", uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658 exit(65);
659 }
660 if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000661 ALOGE("flock(%s) failed: %s\n", dex_path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800662 exit(66);
663 }
664
665 run_dexopt(zip_fd, odex_fd, apk_path, dexopt_flags);
666 exit(67); /* only get here on exec failure */
667 } else {
668 res = wait_dexopt(pid, apk_path);
669 if (res != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000670 ALOGE("dexopt failed on '%s' res = %d\n", dex_path, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 goto fail;
672 }
673 }
674
675 ut.actime = apk_stat.st_atime;
676 ut.modtime = apk_stat.st_mtime;
677 utime(dex_path, &ut);
678
679 close(odex_fd);
680 close(zip_fd);
681 return 0;
682
683fail:
684 if (odex_fd >= 0) {
685 close(odex_fd);
686 unlink(dex_path);
687 }
688 if (zip_fd >= 0) {
689 close(zip_fd);
690 }
691 return -1;
692}
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800693
Dianne Hackbornc1552392010-03-03 16:19:01 -0800694void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid,
695 struct stat* statbuf)
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800696{
697 while (path[basepos] != 0) {
698 if (path[basepos] == '/') {
699 path[basepos] = 0;
Dianne Hackbornc1552392010-03-03 16:19:01 -0800700 if (lstat(path, statbuf) < 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100701 ALOGV("Making directory: %s\n", path);
Dianne Hackbornc1552392010-03-03 16:19:01 -0800702 if (mkdir(path, mode) == 0) {
703 chown(path, uid, gid);
704 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000705 ALOGW("Unable to make directory %s: %s\n", path, strerror(errno));
Dianne Hackbornc1552392010-03-03 16:19:01 -0800706 }
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800707 }
708 path[basepos] = '/';
709 basepos++;
710 }
711 basepos++;
712 }
713}
714
Dianne Hackbornc1552392010-03-03 16:19:01 -0800715int movefileordir(char* srcpath, char* dstpath, int dstbasepos,
716 int dstuid, int dstgid, struct stat* statbuf)
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800717{
718 DIR *d;
719 struct dirent *de;
720 int res;
721
722 int srcend = strlen(srcpath);
723 int dstend = strlen(dstpath);
724
725 if (lstat(srcpath, statbuf) < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000726 ALOGW("Unable to stat %s: %s\n", srcpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800727 return 1;
728 }
729
730 if ((statbuf->st_mode&S_IFDIR) == 0) {
Dianne Hackbornc1552392010-03-03 16:19:01 -0800731 mkinnerdirs(dstpath, dstbasepos, S_IRWXU|S_IRWXG|S_IXOTH,
732 dstuid, dstgid, statbuf);
Steve Block71f2cf12011-10-20 11:56:00 +0100733 ALOGV("Renaming %s to %s (uid %d)\n", srcpath, dstpath, dstuid);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800734 if (rename(srcpath, dstpath) >= 0) {
735 if (chown(dstpath, dstuid, dstgid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000736 ALOGE("cannot chown %s: %s\n", dstpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800737 unlink(dstpath);
738 return 1;
739 }
740 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000741 ALOGW("Unable to rename %s to %s: %s\n",
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800742 srcpath, dstpath, strerror(errno));
743 return 1;
744 }
745 return 0;
746 }
747
748 d = opendir(srcpath);
749 if (d == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000750 ALOGW("Unable to opendir %s: %s\n", srcpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800751 return 1;
752 }
753
754 res = 0;
755
756 while ((de = readdir(d))) {
757 const char *name = de->d_name;
758 /* always skip "." and ".." */
759 if (name[0] == '.') {
760 if (name[1] == 0) continue;
761 if ((name[1] == '.') && (name[2] == 0)) continue;
762 }
763
764 if ((srcend+strlen(name)) >= (PKG_PATH_MAX-2)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000765 ALOGW("Source path too long; skipping: %s/%s\n", srcpath, name);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800766 continue;
767 }
768
769 if ((dstend+strlen(name)) >= (PKG_PATH_MAX-2)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000770 ALOGW("Destination path too long; skipping: %s/%s\n", dstpath, name);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800771 continue;
772 }
773
774 srcpath[srcend] = dstpath[dstend] = '/';
775 strcpy(srcpath+srcend+1, name);
776 strcpy(dstpath+dstend+1, name);
777
Dianne Hackbornc1552392010-03-03 16:19:01 -0800778 if (movefileordir(srcpath, dstpath, dstbasepos, dstuid, dstgid, statbuf) != 0) {
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800779 res = 1;
780 }
781
782 // Note: we will be leaving empty directories behind in srcpath,
783 // but that is okay, the package manager will be erasing all of the
784 // data associated with .apks that disappear.
785
786 srcpath[srcend] = dstpath[dstend] = 0;
787 }
788
789 closedir(d);
790 return res;
791}
792
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800793int movefiles()
794{
795 DIR *d;
796 int dfd, subfd;
797 struct dirent *de;
798 struct stat s;
799 char buf[PKG_PATH_MAX+1];
800 int bufp, bufe, bufi, readlen;
801
802 char srcpkg[PKG_NAME_MAX];
803 char dstpkg[PKG_NAME_MAX];
804 char srcpath[PKG_PATH_MAX];
805 char dstpath[PKG_PATH_MAX];
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800806 int dstuid=-1, dstgid=-1;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800807 int hasspace;
808
809 d = opendir(UPDATE_COMMANDS_DIR_PREFIX);
810 if (d == NULL) {
811 goto done;
812 }
813 dfd = dirfd(d);
814
815 /* Iterate through all files in the directory, executing the
816 * file movements requested there-in.
817 */
818 while ((de = readdir(d))) {
819 const char *name = de->d_name;
820
821 if (de->d_type == DT_DIR) {
822 continue;
823 } else {
824 subfd = openat(dfd, name, O_RDONLY);
825 if (subfd < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000826 ALOGW("Unable to open update commands at %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800827 UPDATE_COMMANDS_DIR_PREFIX, name);
828 continue;
829 }
830
831 bufp = 0;
832 bufe = 0;
833 buf[PKG_PATH_MAX] = 0;
834 srcpkg[0] = dstpkg[0] = 0;
835 while (1) {
836 bufi = bufp;
837 while (bufi < bufe && buf[bufi] != '\n') {
838 bufi++;
839 }
840 if (bufi < bufe) {
841 buf[bufi] = 0;
Steve Block71f2cf12011-10-20 11:56:00 +0100842 ALOGV("Processing line: %s\n", buf+bufp);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800843 hasspace = 0;
844 while (bufp < bufi && isspace(buf[bufp])) {
845 hasspace = 1;
846 bufp++;
847 }
848 if (buf[bufp] == '#' || bufp == bufi) {
849 // skip comments and empty lines.
850 } else if (hasspace) {
851 if (dstpkg[0] == 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000852 ALOGW("Path before package line in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800853 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
854 } else if (srcpkg[0] == 0) {
855 // Skip -- source package no longer exists.
856 } else {
Steve Block71f2cf12011-10-20 11:56:00 +0100857 ALOGV("Move file: %s (from %s to %s)\n", buf+bufp, srcpkg, dstpkg);
Kenny Root86c95842011-03-31 13:16:12 -0700858 if (!create_move_path(srcpath, srcpkg, buf+bufp, 0) &&
859 !create_move_path(dstpath, dstpkg, buf+bufp, 0)) {
Dianne Hackbornc1552392010-03-03 16:19:01 -0800860 movefileordir(srcpath, dstpath,
861 strlen(dstpath)-strlen(buf+bufp),
862 dstuid, dstgid, &s);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800863 }
864 }
865 } else {
866 char* div = strchr(buf+bufp, ':');
867 if (div == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000868 ALOGW("Bad package spec in %s%s; no ':' sep: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800869 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
870 } else {
871 *div = 0;
872 div++;
873 if (strlen(buf+bufp) < PKG_NAME_MAX) {
874 strcpy(dstpkg, buf+bufp);
875 } else {
876 srcpkg[0] = dstpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000877 ALOGW("Package name too long in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800878 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
879 }
880 if (strlen(div) < PKG_NAME_MAX) {
881 strcpy(srcpkg, div);
882 } else {
883 srcpkg[0] = dstpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000884 ALOGW("Package name too long in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800885 UPDATE_COMMANDS_DIR_PREFIX, name, div);
886 }
887 if (srcpkg[0] != 0) {
Kenny Root86c95842011-03-31 13:16:12 -0700888 if (!create_pkg_path(srcpath, srcpkg, PKG_DIR_POSTFIX, 0)) {
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800889 if (lstat(srcpath, &s) < 0) {
890 // Package no longer exists -- skip.
891 srcpkg[0] = 0;
892 }
893 } else {
894 srcpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000895 ALOGW("Can't create path %s in %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800896 div, UPDATE_COMMANDS_DIR_PREFIX, name);
897 }
898 if (srcpkg[0] != 0) {
Kenny Root86c95842011-03-31 13:16:12 -0700899 if (!create_pkg_path(dstpath, dstpkg, PKG_DIR_POSTFIX, 0)) {
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800900 if (lstat(dstpath, &s) == 0) {
901 dstuid = s.st_uid;
902 dstgid = s.st_gid;
903 } else {
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800904 // Destination package doesn't
905 // exist... due to original-package,
906 // this is normal, so don't be
907 // noisy about it.
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800908 srcpkg[0] = 0;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800909 }
910 } else {
911 srcpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000912 ALOGW("Can't create path %s in %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800913 div, UPDATE_COMMANDS_DIR_PREFIX, name);
914 }
915 }
Steve Block71f2cf12011-10-20 11:56:00 +0100916 ALOGV("Transfering from %s to %s: uid=%d\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800917 srcpkg, dstpkg, dstuid);
918 }
919 }
920 }
921 bufp = bufi+1;
922 } else {
923 if (bufp == 0) {
924 if (bufp < bufe) {
Steve Block8564c8d2012-01-05 23:22:43 +0000925 ALOGW("Line too long in %s%s, skipping: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800926 UPDATE_COMMANDS_DIR_PREFIX, name, buf);
927 }
928 } else if (bufp < bufe) {
929 memcpy(buf, buf+bufp, bufe-bufp);
930 bufe -= bufp;
931 bufp = 0;
932 }
933 readlen = read(subfd, buf+bufe, PKG_PATH_MAX-bufe);
934 if (readlen < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000935 ALOGW("Failure reading update commands in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800936 UPDATE_COMMANDS_DIR_PREFIX, name, strerror(errno));
937 break;
938 } else if (readlen == 0) {
939 break;
940 }
941 bufe += readlen;
942 buf[bufe] = 0;
Steve Block71f2cf12011-10-20 11:56:00 +0100943 ALOGV("Read buf: %s\n", buf);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800944 }
945 }
946 close(subfd);
947 }
948 }
949 closedir(d);
950done:
951 return 0;
952}
Kenny Root6a6b0072010-10-07 16:46:10 -0700953
954int linklib(const char* dataDir, const char* asecLibDir)
955{
956 char libdir[PKG_PATH_MAX];
957 struct stat s, libStat;
958 int rc = 0;
959
960 const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
961 if (libdirLen >= PKG_PATH_MAX) {
Steve Block3762c312012-01-06 19:20:56 +0000962 ALOGE("library dir len too large");
Kenny Root0332d1c2010-10-21 16:14:06 -0700963 return -1;
Kenny Root6a6b0072010-10-07 16:46:10 -0700964 }
965
966 if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
Steve Block3762c312012-01-06 19:20:56 +0000967 ALOGE("library dir not written successfully: %s\n", strerror(errno));
Kenny Root0332d1c2010-10-21 16:14:06 -0700968 return -1;
Kenny Root6a6b0072010-10-07 16:46:10 -0700969 }
970
971 if (stat(dataDir, &s) < 0) return -1;
972
973 if (chown(dataDir, 0, 0) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000974 ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700975 return -1;
976 }
977
978 if (chmod(dataDir, 0700) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000979 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700980 rc = -1;
981 goto out;
982 }
983
984 if (lstat(libdir, &libStat) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000985 ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700986 rc = -1;
987 goto out;
988 }
989
990 if (S_ISDIR(libStat.st_mode)) {
991 if (delete_dir_contents(libdir, 1, 0) < 0) {
992 rc = -1;
993 goto out;
994 }
995 } else if (S_ISLNK(libStat.st_mode)) {
996 if (unlink(libdir) < 0) {
997 rc = -1;
998 goto out;
999 }
1000 }
1001
1002 if (symlink(asecLibDir, libdir) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001003 ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libdir, asecLibDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001004 rc = -errno;
1005 goto out;
1006 }
1007
1008 if (lchown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001009 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001010 unlink(libdir);
1011 rc = -errno;
1012 goto out;
1013 }
1014
1015out:
1016 if (chmod(dataDir, s.st_mode) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001017 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Dianne Hackbornd0c5f512012-06-07 16:53:59 -07001018 rc = -errno;
Kenny Root6a6b0072010-10-07 16:46:10 -07001019 }
1020
1021 if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001022 ALOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001023 return -errno;
1024 }
1025
1026 return rc;
1027}
1028
1029int unlinklib(const char* dataDir)
1030{
1031 char libdir[PKG_PATH_MAX];
1032 struct stat s, libStat;
1033 int rc = 0;
1034
1035 const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
1036 if (libdirLen >= PKG_PATH_MAX) {
1037 return -1;
1038 }
1039
1040 if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
Steve Block3762c312012-01-06 19:20:56 +00001041 ALOGE("library dir not written successfully: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001042 return -1;
1043 }
1044
1045 if (stat(dataDir, &s) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001046 ALOGE("couldn't state data dir");
Kenny Root6a6b0072010-10-07 16:46:10 -07001047 return -1;
1048 }
1049
1050 if (chown(dataDir, 0, 0) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001051 ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001052 return -1;
1053 }
1054
1055 if (chmod(dataDir, 0700) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001056 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001057 rc = -1;
1058 goto out;
1059 }
1060
1061 if (lstat(libdir, &libStat) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001062 ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001063 rc = -1;
1064 goto out;
1065 }
1066
1067 if (S_ISDIR(libStat.st_mode)) {
1068 if (delete_dir_contents(libdir, 1, 0) < 0) {
1069 rc = -1;
1070 goto out;
1071 }
1072 } else if (S_ISLNK(libStat.st_mode)) {
1073 if (unlink(libdir) < 0) {
1074 rc = -1;
1075 goto out;
1076 }
1077 }
1078
1079 if (mkdir(libdir, 0755) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001080 ALOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001081 rc = -errno;
1082 goto out;
1083 }
Kenny Root515087d2012-07-30 15:00:16 -07001084 if (chmod(libdir, 0755) < 0) {
1085 ALOGE("cannot chmod dir '%s': %s\n", libdir, strerror(errno));
1086 unlink(libdir);
1087 rc = -errno;
1088 goto out;
1089 }
Kenny Root6a6b0072010-10-07 16:46:10 -07001090 if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001091 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001092 unlink(libdir);
1093 rc = -errno;
1094 goto out;
1095 }
1096
1097out:
1098 if (chmod(dataDir, s.st_mode) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001099 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Dianne Hackbornd0c5f512012-06-07 16:53:59 -07001100 rc = -1;
Kenny Root6a6b0072010-10-07 16:46:10 -07001101 }
1102
1103 if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001104 ALOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001105 return -1;
1106 }
1107
1108 return rc;
1109}