blob: 0bc737185b91720074c1abefbd890294366ded13 [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
Kenny Root86c95842011-03-31 13:16:12 -070020/* Directory records that are used in execution of commands. */
21dir_rec_t android_data_dir;
22dir_rec_t android_asec_dir;
23dir_rec_t android_app_dir;
24dir_rec_t android_app_private_dir;
25dir_rec_array_t android_system_dirs;
26
Kenny Root35ab3ad2011-02-02 16:42:14 -080027int install(const char *pkgname, uid_t uid, gid_t gid)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028{
29 char pkgdir[PKG_PATH_MAX];
30 char libdir[PKG_PATH_MAX];
31
32 if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
Steve Block3762c312012-01-06 19:20:56 +000033 ALOGE("invalid uid/gid: %d %d\n", uid, gid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035 }
Oscar Montemayora8529f62009-11-18 10:14:20 -080036
Kenny Root86c95842011-03-31 13:16:12 -070037 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
Steve Block3762c312012-01-06 19:20:56 +000038 ALOGE("cannot create package path\n");
Kenny Root35ab3ad2011-02-02 16:42:14 -080039 return -1;
Kenny Root86c95842011-03-31 13:16:12 -070040 }
41
42 if (create_pkg_path(libdir, pkgname, PKG_LIB_POSTFIX, 0)) {
Steve Block3762c312012-01-06 19:20:56 +000043 ALOGE("cannot create package lib path\n");
Kenny Root35ab3ad2011-02-02 16:42:14 -080044 return -1;
Kenny Root86c95842011-03-31 13:16:12 -070045 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046
David 'Digit' Turner0dd50e62010-02-09 19:02:38 -080047 if (mkdir(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000048 ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049 return -errno;
50 }
Nick Kralevichf68327e2011-04-14 16:20:03 -070051 if (chmod(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000052 ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
Nick Kralevichf68327e2011-04-14 16:20:03 -070053 unlink(pkgdir);
54 return -errno;
55 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056 if (chown(pkgdir, uid, gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000057 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058 unlink(pkgdir);
59 return -errno;
60 }
61 if (mkdir(libdir, 0755) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000062 ALOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063 unlink(pkgdir);
64 return -errno;
65 }
Nick Kralevichf68327e2011-04-14 16:20:03 -070066 if (chmod(libdir, 0755) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000067 ALOGE("cannot chmod dir '%s': %s\n", libdir, strerror(errno));
Nick Kralevichf68327e2011-04-14 16:20:03 -070068 unlink(libdir);
69 unlink(pkgdir);
70 return -errno;
71 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072 if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +000073 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074 unlink(libdir);
75 unlink(pkgdir);
76 return -errno;
77 }
78 return 0;
79}
80
Amith Yamasani0b285492011-04-14 17:35:23 -070081int uninstall(const char *pkgname, uid_t persona)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082{
83 char pkgdir[PKG_PATH_MAX];
84
Amith Yamasani0b285492011-04-14 17:35:23 -070085 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
Kenny Root35ab3ad2011-02-02 16:42:14 -080086 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087
Amith Yamasani0b285492011-04-14 17:35:23 -070088 /* delete contents AND directory, no exceptions */
89 return delete_dir_contents(pkgdir, 1, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090}
91
Kenny Root35ab3ad2011-02-02 16:42:14 -080092int renamepkg(const char *oldpkgname, const char *newpkgname)
Dianne Hackbornb858dfd2010-02-02 10:49:14 -080093{
94 char oldpkgdir[PKG_PATH_MAX];
95 char newpkgdir[PKG_PATH_MAX];
96
Kenny Root86c95842011-03-31 13:16:12 -070097 if (create_pkg_path(oldpkgdir, oldpkgname, PKG_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -080098 return -1;
Kenny Root86c95842011-03-31 13:16:12 -070099 if (create_pkg_path(newpkgdir, newpkgname, PKG_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800100 return -1;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800101
102 if (rename(oldpkgdir, newpkgdir) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000103 ALOGE("cannot rename dir '%s' to '%s': %s\n", oldpkgdir, newpkgdir, strerror(errno));
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800104 return -errno;
105 }
106 return 0;
107}
108
Dianne Hackbornd0c5f512012-06-07 16:53:59 -0700109int fix_uid(const char *pkgname, uid_t uid, gid_t gid)
110{
111 char pkgdir[PKG_PATH_MAX];
112 struct stat s;
113 int rc = 0;
114
115 if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
116 ALOGE("invalid uid/gid: %d %d\n", uid, gid);
117 return -1;
118 }
119
120 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
121 ALOGE("cannot create package path\n");
122 return -1;
123 }
124
125 if (stat(pkgdir, &s) < 0) return -1;
126
127 if (s.st_uid != 0 || s.st_gid != 0) {
128 ALOGE("fixing uid of non-root pkg: %s %d %d\n", pkgdir, s.st_uid, s.st_gid);
129 return -1;
130 }
131
132 if (chmod(pkgdir, 0751) < 0) {
133 ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
134 unlink(pkgdir);
135 return -errno;
136 }
137 if (chown(pkgdir, uid, gid) < 0) {
138 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
139 unlink(pkgdir);
140 return -errno;
141 }
142
143 return 0;
144}
145
Amith Yamasani0b285492011-04-14 17:35:23 -0700146int delete_user_data(const char *pkgname, uid_t persona)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147{
148 char pkgdir[PKG_PATH_MAX];
149
Amith Yamasani0b285492011-04-14 17:35:23 -0700150 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800151 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152
Amith Yamasani0b285492011-04-14 17:35:23 -0700153 /* delete contents, excluding "lib", but not the directory itself */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154 return delete_dir_contents(pkgdir, 0, "lib");
155}
156
Amith Yamasani0b285492011-04-14 17:35:23 -0700157int make_user_data(const char *pkgname, uid_t uid, uid_t persona)
158{
159 char pkgdir[PKG_PATH_MAX];
160 char real_libdir[PKG_PATH_MAX];
161
162 // Create the data dir for the package
163 if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona)) {
164 return -1;
165 }
166 if (mkdir(pkgdir, 0751) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000167 ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
Amith Yamasani0b285492011-04-14 17:35:23 -0700168 return -errno;
169 }
170 if (chown(pkgdir, uid, uid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000171 ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
Amith Yamasani0b285492011-04-14 17:35:23 -0700172 unlink(pkgdir);
173 return -errno;
174 }
175 return 0;
176}
177
178int delete_persona(uid_t persona)
179{
180 char pkgdir[PKG_PATH_MAX];
181
182 if (create_persona_path(pkgdir, persona))
183 return -1;
184
185 return delete_dir_contents(pkgdir, 1, NULL);
186}
187
Amith Yamasani742a6712011-05-04 14:49:28 -0700188int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy)
189{
190 char src_data_dir[PKG_PATH_MAX];
191 char pkg_path[PKG_PATH_MAX];
192 DIR *d;
193 struct dirent *de;
194 struct stat s;
195 uid_t uid;
196
197 if (create_persona_path(src_data_dir, src_persona)) {
198 return -1;
199 }
200
201 d = opendir(src_data_dir);
202 if (d != NULL) {
203 while ((de = readdir(d))) {
204 const char *name = de->d_name;
205
206 if (de->d_type == DT_DIR) {
207 int subfd;
208 /* always skip "." and ".." */
209 if (name[0] == '.') {
210 if (name[1] == 0) continue;
211 if ((name[1] == '.') && (name[2] == 0)) continue;
212 }
213 /* Create the full path to the package's data dir */
214 create_pkg_path(pkg_path, name, PKG_DIR_POSTFIX, src_persona);
215 /* Get the file stat */
216 if (stat(pkg_path, &s) < 0) continue;
217 /* Get the uid of the package */
218 ALOGI("Adding datadir for uid = %d\n", s.st_uid);
219 uid = (uid_t) s.st_uid % PER_USER_RANGE;
220 /* Create the directory for the target */
221 make_user_data(name, uid + target_persona * PER_USER_RANGE,
222 target_persona);
223 }
224 }
225 closedir(d);
226 }
227 return 0;
228}
229
Kenny Root35ab3ad2011-02-02 16:42:14 -0800230int delete_cache(const char *pkgname)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231{
232 char cachedir[PKG_PATH_MAX];
233
Kenny Root86c95842011-03-31 13:16:12 -0700234 if (create_pkg_path(cachedir, pkgname, CACHE_DIR_POSTFIX, 0))
Kenny Root35ab3ad2011-02-02 16:42:14 -0800235 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236
237 /* delete contents, not the directory, no exceptions */
238 return delete_dir_contents(cachedir, 0, 0);
239}
240
Kenny Root3e319a92010-09-07 13:58:28 -0700241static int64_t disk_free()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242{
243 struct statfs sfs;
Kenny Root86c95842011-03-31 13:16:12 -0700244 if (statfs(android_data_dir.path, &sfs) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245 return sfs.f_bavail * sfs.f_bsize;
246 } else {
Steve Block3762c312012-01-06 19:20:56 +0000247 ALOGE("Couldn't statfs %s: %s\n", android_data_dir.path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 return -1;
249 }
250}
251
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252/* Try to ensure free_size bytes of storage are available.
253 * Returns 0 on success.
254 * This is rather simple-minded because doing a full LRU would
255 * be potentially memory-intensive, and without atime it would
256 * also require that apps constantly modify file metadata even
257 * when just reading from the cache, which is pretty awful.
258 */
Kenny Root3e319a92010-09-07 13:58:28 -0700259int free_cache(int64_t free_size)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260{
261 const char *name;
262 int dfd, subfd;
263 DIR *d;
264 struct dirent *de;
Kenny Root3e319a92010-09-07 13:58:28 -0700265 int64_t avail;
Kenny Rootad757e92011-11-29 15:54:55 -0800266 char datadir[PKG_PATH_MAX];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267
268 avail = disk_free();
269 if (avail < 0) return -1;
270
Steve Block6215d3f2012-01-04 20:05:49 +0000271 ALOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 if (avail >= free_size) return 0;
273
Kenny Rootad757e92011-11-29 15:54:55 -0800274 if (create_persona_path(datadir, 0)) {
Steve Block3762c312012-01-06 19:20:56 +0000275 ALOGE("couldn't get directory for persona 0");
Kenny Rootad757e92011-11-29 15:54:55 -0800276 return -1;
277 }
278
279 d = opendir(datadir);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280 if (d == NULL) {
Steve Block3762c312012-01-06 19:20:56 +0000281 ALOGE("cannot open %s: %s\n", datadir, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282 return -1;
283 }
284 dfd = dirfd(d);
285
286 while ((de = readdir(d))) {
287 if (de->d_type != DT_DIR) continue;
288 name = de->d_name;
289
Oscar Montemayora8529f62009-11-18 10:14:20 -0800290 /* always skip "." and ".." */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291 if (name[0] == '.') {
292 if (name[1] == 0) continue;
293 if ((name[1] == '.') && (name[2] == 0)) continue;
294 }
295
296 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
297 if (subfd < 0) continue;
298
299 delete_dir_contents_fd(subfd, "cache");
300 close(subfd);
301
302 avail = disk_free();
303 if (avail >= free_size) {
304 closedir(d);
305 return 0;
306 }
307 }
308 closedir(d);
Oscar Montemayora8529f62009-11-18 10:14:20 -0800309
310 /* Fail case - not possible to free space */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311 return -1;
312}
313
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800314int move_dex(const char *src, const char *dst)
315{
316 char src_dex[PKG_PATH_MAX];
317 char dst_dex[PKG_PATH_MAX];
318
Kenny Root86c95842011-03-31 13:16:12 -0700319 if (validate_apk_path(src)) return -1;
320 if (validate_apk_path(dst)) return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321
322 if (create_cache_path(src_dex, src)) return -1;
323 if (create_cache_path(dst_dex, dst)) return -1;
324
Steve Block71f2cf12011-10-20 11:56:00 +0100325 ALOGV("move %s -> %s\n", src_dex, dst_dex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326 if (rename(src_dex, dst_dex) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000327 ALOGE("Couldn't move %s: %s\n", src_dex, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328 return -1;
329 } else {
330 return 0;
331 }
332}
333
334int rm_dex(const char *path)
335{
336 char dex_path[PKG_PATH_MAX];
337
Kenny Root86c95842011-03-31 13:16:12 -0700338 if (validate_apk_path(path)) return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 if (create_cache_path(dex_path, path)) return -1;
340
Steve Block71f2cf12011-10-20 11:56:00 +0100341 ALOGV("unlink %s\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 if (unlink(dex_path) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000343 ALOGE("Couldn't unlink %s: %s\n", dex_path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344 return -1;
345 } else {
346 return 0;
347 }
348}
349
350int protect(char *pkgname, gid_t gid)
351{
352 struct stat s;
353 char pkgpath[PKG_PATH_MAX];
354
355 if (gid < AID_SYSTEM) return -1;
356
Kenny Root86c95842011-03-31 13:16:12 -0700357 if (create_pkg_path_in_dir(pkgpath, &android_app_private_dir, pkgname, ".apk"))
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 return -1;
359
360 if (stat(pkgpath, &s) < 0) return -1;
361
362 if (chown(pkgpath, s.st_uid, gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000363 ALOGE("failed to chgrp '%s': %s\n", pkgpath, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364 return -1;
365 }
366
367 if (chmod(pkgpath, S_IRUSR|S_IWUSR|S_IRGRP) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000368 ALOGE("failed to chmod '%s': %s\n", pkgpath, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 return -1;
370 }
371
372 return 0;
373}
374
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375int get_size(const char *pkgname, const char *apkpath,
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700376 const char *fwdlock_apkpath, const char *asecpath,
377 int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize,
378 int64_t* _asecsize)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379{
380 DIR *d;
381 int dfd;
382 struct dirent *de;
383 struct stat s;
384 char path[PKG_PATH_MAX];
385
Kenny Root3e319a92010-09-07 13:58:28 -0700386 int64_t codesize = 0;
387 int64_t datasize = 0;
388 int64_t cachesize = 0;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700389 int64_t asecsize = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390
391 /* count the source apk as code -- but only if it's not
Suchi Amalapurapu8a9ab242010-03-11 16:49:16 -0800392 * on the /system partition and its not on the sdcard.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800393 */
Kenny Root86c95842011-03-31 13:16:12 -0700394 if (validate_system_app_path(apkpath) &&
395 strncmp(apkpath, android_asec_dir.path, android_asec_dir.len) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 if (stat(apkpath, &s) == 0) {
397 codesize += stat_size(&s);
398 }
399 }
400 /* count the forward locked apk as code if it is given
401 */
402 if (fwdlock_apkpath != NULL && fwdlock_apkpath[0] != '!') {
403 if (stat(fwdlock_apkpath, &s) == 0) {
404 codesize += stat_size(&s);
405 }
406 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407 /* count the cached dexfile as code */
408 if (!create_cache_path(path, apkpath)) {
409 if (stat(path, &s) == 0) {
410 codesize += stat_size(&s);
411 }
412 }
413
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700414 /* compute asec size if it is given
415 */
416 if (asecpath != NULL && asecpath[0] != '!') {
417 if (stat(asecpath, &s) == 0) {
418 asecsize += stat_size(&s);
419 }
420 }
421
Kenny Root86c95842011-03-31 13:16:12 -0700422 if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, 0)) {
Kenny Root35ab3ad2011-02-02 16:42:14 -0800423 goto done;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 }
425
426 d = opendir(path);
427 if (d == NULL) {
428 goto done;
429 }
430 dfd = dirfd(d);
431
Kenny Root86c95842011-03-31 13:16:12 -0700432 /* most stuff in the pkgdir is data, except for the "cache"
433 * directory and below, which is cache, and the "lib" directory
434 * and below, which is code...
435 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 while ((de = readdir(d))) {
437 const char *name = de->d_name;
438
439 if (de->d_type == DT_DIR) {
440 int subfd;
441 /* always skip "." and ".." */
442 if (name[0] == '.') {
443 if (name[1] == 0) continue;
444 if ((name[1] == '.') && (name[2] == 0)) continue;
445 }
446 subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
447 if (subfd >= 0) {
Kenny Root3e319a92010-09-07 13:58:28 -0700448 int64_t size = calculate_dir_size(subfd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 if (!strcmp(name,"lib")) {
450 codesize += size;
451 } else if(!strcmp(name,"cache")) {
452 cachesize += size;
453 } else {
454 datasize += size;
455 }
456 }
457 } else {
458 if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
459 datasize += stat_size(&s);
460 }
461 }
462 }
463 closedir(d);
464done:
465 *_codesize = codesize;
466 *_datasize = datasize;
467 *_cachesize = cachesize;
Dianne Hackborn292f8bc2011-06-27 16:27:41 -0700468 *_asecsize = asecsize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469 return 0;
470}
471
472
473/* a simpler version of dexOptGenerateCacheFileName() */
474int create_cache_path(char path[PKG_PATH_MAX], const char *src)
475{
476 char *tmp;
477 int srclen;
478 int dstlen;
479
480 srclen = strlen(src);
481
482 /* demand that we are an absolute path */
483 if ((src == 0) || (src[0] != '/') || strstr(src,"..")) {
484 return -1;
485 }
486
487 if (srclen > PKG_PATH_MAX) { // XXX: PKG_NAME_MAX?
488 return -1;
489 }
490
491 dstlen = srclen + strlen(DALVIK_CACHE_PREFIX) +
492 strlen(DALVIK_CACHE_POSTFIX) + 1;
493
494 if (dstlen > PKG_PATH_MAX) {
495 return -1;
496 }
497
498 sprintf(path,"%s%s%s",
499 DALVIK_CACHE_PREFIX,
500 src + 1, /* skip the leading / */
501 DALVIK_CACHE_POSTFIX);
502
503 for(tmp = path + strlen(DALVIK_CACHE_PREFIX); *tmp; tmp++) {
504 if (*tmp == '/') {
505 *tmp = '@';
506 }
507 }
508
509 return 0;
510}
511
512static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name,
513 const char* dexopt_flags)
514{
515 static const char* DEX_OPT_BIN = "/system/bin/dexopt";
516 static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
517 char zip_num[MAX_INT_LEN];
518 char odex_num[MAX_INT_LEN];
519
520 sprintf(zip_num, "%d", zip_fd);
521 sprintf(odex_num, "%d", odex_fd);
522
523 execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name,
524 dexopt_flags, (char*) NULL);
Steve Block3762c312012-01-06 19:20:56 +0000525 ALOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800526}
527
528static int wait_dexopt(pid_t pid, const char* apk_path)
529{
530 int status;
531 pid_t got_pid;
532
533 /*
534 * Wait for the optimization process to finish.
535 */
536 while (1) {
537 got_pid = waitpid(pid, &status, 0);
538 if (got_pid == -1 && errno == EINTR) {
539 printf("waitpid interrupted, retrying\n");
540 } else {
541 break;
542 }
543 }
544 if (got_pid != pid) {
Steve Block8564c8d2012-01-05 23:22:43 +0000545 ALOGW("waitpid failed: wanted %d, got %d: %s\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800546 (int) pid, (int) got_pid, strerror(errno));
547 return 1;
548 }
549
550 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100551 ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800552 return 0;
553 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000554 ALOGW("DexInv: --- END '%s' --- status=0x%04x, process failed\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555 apk_path, status);
556 return status; /* always nonzero */
557 }
558}
559
560int dexopt(const char *apk_path, uid_t uid, int is_public)
561{
562 struct utimbuf ut;
563 struct stat apk_stat, dex_stat;
564 char dex_path[PKG_PATH_MAX];
565 char dexopt_flags[PROPERTY_VALUE_MAX];
566 char *end;
567 int res, zip_fd=-1, odex_fd=-1;
568
569 /* Before anything else: is there a .odex file? If so, we have
570 * pre-optimized the apk and there is nothing to do here.
571 */
572 if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
573 return -1;
574 }
575
576 /* platform-specific flags affecting optimization and verification */
577 property_get("dalvik.vm.dexopt-flags", dexopt_flags, "");
578
579 strcpy(dex_path, apk_path);
580 end = strrchr(dex_path, '.');
581 if (end != NULL) {
582 strcpy(end, ".odex");
583 if (stat(dex_path, &dex_stat) == 0) {
584 return 0;
585 }
586 }
587
588 if (create_cache_path(dex_path, apk_path)) {
589 return -1;
590 }
591
592 memset(&apk_stat, 0, sizeof(apk_stat));
593 stat(apk_path, &apk_stat);
594
595 zip_fd = open(apk_path, O_RDONLY, 0);
596 if (zip_fd < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000597 ALOGE("dexopt cannot open '%s' for input\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 return -1;
599 }
600
601 unlink(dex_path);
602 odex_fd = open(dex_path, O_RDWR | O_CREAT | O_EXCL, 0644);
603 if (odex_fd < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000604 ALOGE("dexopt cannot open '%s' for output\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800605 goto fail;
606 }
607 if (fchown(odex_fd, AID_SYSTEM, uid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000608 ALOGE("dexopt cannot chown '%s'\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 goto fail;
610 }
611 if (fchmod(odex_fd,
612 S_IRUSR|S_IWUSR|S_IRGRP |
613 (is_public ? S_IROTH : 0)) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000614 ALOGE("dexopt cannot chmod '%s'\n", dex_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800615 goto fail;
616 }
617
Steve Block71f2cf12011-10-20 11:56:00 +0100618 ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619
620 pid_t pid;
621 pid = fork();
622 if (pid == 0) {
623 /* child -- drop privileges before continuing */
624 if (setgid(uid) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000625 ALOGE("setgid(%d) failed during dexopt\n", uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800626 exit(64);
627 }
628 if (setuid(uid) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000629 ALOGE("setuid(%d) during dexopt\n", uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800630 exit(65);
631 }
632 if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000633 ALOGE("flock(%s) failed: %s\n", dex_path, strerror(errno));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800634 exit(66);
635 }
636
637 run_dexopt(zip_fd, odex_fd, apk_path, dexopt_flags);
638 exit(67); /* only get here on exec failure */
639 } else {
640 res = wait_dexopt(pid, apk_path);
641 if (res != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000642 ALOGE("dexopt failed on '%s' res = %d\n", dex_path, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800643 goto fail;
644 }
645 }
646
647 ut.actime = apk_stat.st_atime;
648 ut.modtime = apk_stat.st_mtime;
649 utime(dex_path, &ut);
650
651 close(odex_fd);
652 close(zip_fd);
653 return 0;
654
655fail:
656 if (odex_fd >= 0) {
657 close(odex_fd);
658 unlink(dex_path);
659 }
660 if (zip_fd >= 0) {
661 close(zip_fd);
662 }
663 return -1;
664}
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800665
Dianne Hackbornc1552392010-03-03 16:19:01 -0800666void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid,
667 struct stat* statbuf)
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800668{
669 while (path[basepos] != 0) {
670 if (path[basepos] == '/') {
671 path[basepos] = 0;
Dianne Hackbornc1552392010-03-03 16:19:01 -0800672 if (lstat(path, statbuf) < 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100673 ALOGV("Making directory: %s\n", path);
Dianne Hackbornc1552392010-03-03 16:19:01 -0800674 if (mkdir(path, mode) == 0) {
675 chown(path, uid, gid);
676 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000677 ALOGW("Unable to make directory %s: %s\n", path, strerror(errno));
Dianne Hackbornc1552392010-03-03 16:19:01 -0800678 }
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800679 }
680 path[basepos] = '/';
681 basepos++;
682 }
683 basepos++;
684 }
685}
686
Dianne Hackbornc1552392010-03-03 16:19:01 -0800687int movefileordir(char* srcpath, char* dstpath, int dstbasepos,
688 int dstuid, int dstgid, struct stat* statbuf)
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800689{
690 DIR *d;
691 struct dirent *de;
692 int res;
693
694 int srcend = strlen(srcpath);
695 int dstend = strlen(dstpath);
696
697 if (lstat(srcpath, statbuf) < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000698 ALOGW("Unable to stat %s: %s\n", srcpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800699 return 1;
700 }
701
702 if ((statbuf->st_mode&S_IFDIR) == 0) {
Dianne Hackbornc1552392010-03-03 16:19:01 -0800703 mkinnerdirs(dstpath, dstbasepos, S_IRWXU|S_IRWXG|S_IXOTH,
704 dstuid, dstgid, statbuf);
Steve Block71f2cf12011-10-20 11:56:00 +0100705 ALOGV("Renaming %s to %s (uid %d)\n", srcpath, dstpath, dstuid);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800706 if (rename(srcpath, dstpath) >= 0) {
707 if (chown(dstpath, dstuid, dstgid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000708 ALOGE("cannot chown %s: %s\n", dstpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800709 unlink(dstpath);
710 return 1;
711 }
712 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000713 ALOGW("Unable to rename %s to %s: %s\n",
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800714 srcpath, dstpath, strerror(errno));
715 return 1;
716 }
717 return 0;
718 }
719
720 d = opendir(srcpath);
721 if (d == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000722 ALOGW("Unable to opendir %s: %s\n", srcpath, strerror(errno));
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800723 return 1;
724 }
725
726 res = 0;
727
728 while ((de = readdir(d))) {
729 const char *name = de->d_name;
730 /* always skip "." and ".." */
731 if (name[0] == '.') {
732 if (name[1] == 0) continue;
733 if ((name[1] == '.') && (name[2] == 0)) continue;
734 }
735
736 if ((srcend+strlen(name)) >= (PKG_PATH_MAX-2)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000737 ALOGW("Source path too long; skipping: %s/%s\n", srcpath, name);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800738 continue;
739 }
740
741 if ((dstend+strlen(name)) >= (PKG_PATH_MAX-2)) {
Steve Block8564c8d2012-01-05 23:22:43 +0000742 ALOGW("Destination path too long; skipping: %s/%s\n", dstpath, name);
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800743 continue;
744 }
745
746 srcpath[srcend] = dstpath[dstend] = '/';
747 strcpy(srcpath+srcend+1, name);
748 strcpy(dstpath+dstend+1, name);
749
Dianne Hackbornc1552392010-03-03 16:19:01 -0800750 if (movefileordir(srcpath, dstpath, dstbasepos, dstuid, dstgid, statbuf) != 0) {
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800751 res = 1;
752 }
753
754 // Note: we will be leaving empty directories behind in srcpath,
755 // but that is okay, the package manager will be erasing all of the
756 // data associated with .apks that disappear.
757
758 srcpath[srcend] = dstpath[dstend] = 0;
759 }
760
761 closedir(d);
762 return res;
763}
764
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800765int movefiles()
766{
767 DIR *d;
768 int dfd, subfd;
769 struct dirent *de;
770 struct stat s;
771 char buf[PKG_PATH_MAX+1];
772 int bufp, bufe, bufi, readlen;
773
774 char srcpkg[PKG_NAME_MAX];
775 char dstpkg[PKG_NAME_MAX];
776 char srcpath[PKG_PATH_MAX];
777 char dstpath[PKG_PATH_MAX];
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800778 int dstuid=-1, dstgid=-1;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800779 int hasspace;
780
781 d = opendir(UPDATE_COMMANDS_DIR_PREFIX);
782 if (d == NULL) {
783 goto done;
784 }
785 dfd = dirfd(d);
786
787 /* Iterate through all files in the directory, executing the
788 * file movements requested there-in.
789 */
790 while ((de = readdir(d))) {
791 const char *name = de->d_name;
792
793 if (de->d_type == DT_DIR) {
794 continue;
795 } else {
796 subfd = openat(dfd, name, O_RDONLY);
797 if (subfd < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000798 ALOGW("Unable to open update commands at %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800799 UPDATE_COMMANDS_DIR_PREFIX, name);
800 continue;
801 }
802
803 bufp = 0;
804 bufe = 0;
805 buf[PKG_PATH_MAX] = 0;
806 srcpkg[0] = dstpkg[0] = 0;
807 while (1) {
808 bufi = bufp;
809 while (bufi < bufe && buf[bufi] != '\n') {
810 bufi++;
811 }
812 if (bufi < bufe) {
813 buf[bufi] = 0;
Steve Block71f2cf12011-10-20 11:56:00 +0100814 ALOGV("Processing line: %s\n", buf+bufp);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800815 hasspace = 0;
816 while (bufp < bufi && isspace(buf[bufp])) {
817 hasspace = 1;
818 bufp++;
819 }
820 if (buf[bufp] == '#' || bufp == bufi) {
821 // skip comments and empty lines.
822 } else if (hasspace) {
823 if (dstpkg[0] == 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000824 ALOGW("Path before package line in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800825 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
826 } else if (srcpkg[0] == 0) {
827 // Skip -- source package no longer exists.
828 } else {
Steve Block71f2cf12011-10-20 11:56:00 +0100829 ALOGV("Move file: %s (from %s to %s)\n", buf+bufp, srcpkg, dstpkg);
Kenny Root86c95842011-03-31 13:16:12 -0700830 if (!create_move_path(srcpath, srcpkg, buf+bufp, 0) &&
831 !create_move_path(dstpath, dstpkg, buf+bufp, 0)) {
Dianne Hackbornc1552392010-03-03 16:19:01 -0800832 movefileordir(srcpath, dstpath,
833 strlen(dstpath)-strlen(buf+bufp),
834 dstuid, dstgid, &s);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800835 }
836 }
837 } else {
838 char* div = strchr(buf+bufp, ':');
839 if (div == NULL) {
Steve Block8564c8d2012-01-05 23:22:43 +0000840 ALOGW("Bad package spec in %s%s; no ':' sep: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800841 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
842 } else {
843 *div = 0;
844 div++;
845 if (strlen(buf+bufp) < PKG_NAME_MAX) {
846 strcpy(dstpkg, buf+bufp);
847 } else {
848 srcpkg[0] = dstpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000849 ALOGW("Package name too long in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800850 UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp);
851 }
852 if (strlen(div) < PKG_NAME_MAX) {
853 strcpy(srcpkg, div);
854 } else {
855 srcpkg[0] = dstpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000856 ALOGW("Package name too long in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800857 UPDATE_COMMANDS_DIR_PREFIX, name, div);
858 }
859 if (srcpkg[0] != 0) {
Kenny Root86c95842011-03-31 13:16:12 -0700860 if (!create_pkg_path(srcpath, srcpkg, PKG_DIR_POSTFIX, 0)) {
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800861 if (lstat(srcpath, &s) < 0) {
862 // Package no longer exists -- skip.
863 srcpkg[0] = 0;
864 }
865 } else {
866 srcpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000867 ALOGW("Can't create path %s in %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800868 div, UPDATE_COMMANDS_DIR_PREFIX, name);
869 }
870 if (srcpkg[0] != 0) {
Kenny Root86c95842011-03-31 13:16:12 -0700871 if (!create_pkg_path(dstpath, dstpkg, PKG_DIR_POSTFIX, 0)) {
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800872 if (lstat(dstpath, &s) == 0) {
873 dstuid = s.st_uid;
874 dstgid = s.st_gid;
875 } else {
Dianne Hackbornd705fd22010-02-12 14:58:04 -0800876 // Destination package doesn't
877 // exist... due to original-package,
878 // this is normal, so don't be
879 // noisy about it.
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800880 srcpkg[0] = 0;
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800881 }
882 } else {
883 srcpkg[0] = 0;
Steve Block8564c8d2012-01-05 23:22:43 +0000884 ALOGW("Can't create path %s in %s%s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800885 div, UPDATE_COMMANDS_DIR_PREFIX, name);
886 }
887 }
Steve Block71f2cf12011-10-20 11:56:00 +0100888 ALOGV("Transfering from %s to %s: uid=%d\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800889 srcpkg, dstpkg, dstuid);
890 }
891 }
892 }
893 bufp = bufi+1;
894 } else {
895 if (bufp == 0) {
896 if (bufp < bufe) {
Steve Block8564c8d2012-01-05 23:22:43 +0000897 ALOGW("Line too long in %s%s, skipping: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800898 UPDATE_COMMANDS_DIR_PREFIX, name, buf);
899 }
900 } else if (bufp < bufe) {
901 memcpy(buf, buf+bufp, bufe-bufp);
902 bufe -= bufp;
903 bufp = 0;
904 }
905 readlen = read(subfd, buf+bufe, PKG_PATH_MAX-bufe);
906 if (readlen < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000907 ALOGW("Failure reading update commands in %s%s: %s\n",
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800908 UPDATE_COMMANDS_DIR_PREFIX, name, strerror(errno));
909 break;
910 } else if (readlen == 0) {
911 break;
912 }
913 bufe += readlen;
914 buf[bufe] = 0;
Steve Block71f2cf12011-10-20 11:56:00 +0100915 ALOGV("Read buf: %s\n", buf);
Dianne Hackbornb858dfd2010-02-02 10:49:14 -0800916 }
917 }
918 close(subfd);
919 }
920 }
921 closedir(d);
922done:
923 return 0;
924}
Kenny Root6a6b0072010-10-07 16:46:10 -0700925
926int linklib(const char* dataDir, const char* asecLibDir)
927{
928 char libdir[PKG_PATH_MAX];
929 struct stat s, libStat;
930 int rc = 0;
931
932 const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
933 if (libdirLen >= PKG_PATH_MAX) {
Steve Block3762c312012-01-06 19:20:56 +0000934 ALOGE("library dir len too large");
Kenny Root0332d1c2010-10-21 16:14:06 -0700935 return -1;
Kenny Root6a6b0072010-10-07 16:46:10 -0700936 }
937
938 if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
Steve Block3762c312012-01-06 19:20:56 +0000939 ALOGE("library dir not written successfully: %s\n", strerror(errno));
Kenny Root0332d1c2010-10-21 16:14:06 -0700940 return -1;
Kenny Root6a6b0072010-10-07 16:46:10 -0700941 }
942
943 if (stat(dataDir, &s) < 0) return -1;
944
945 if (chown(dataDir, 0, 0) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000946 ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700947 return -1;
948 }
949
950 if (chmod(dataDir, 0700) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000951 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700952 rc = -1;
953 goto out;
954 }
955
956 if (lstat(libdir, &libStat) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000957 ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700958 rc = -1;
959 goto out;
960 }
961
962 if (S_ISDIR(libStat.st_mode)) {
963 if (delete_dir_contents(libdir, 1, 0) < 0) {
964 rc = -1;
965 goto out;
966 }
967 } else if (S_ISLNK(libStat.st_mode)) {
968 if (unlink(libdir) < 0) {
969 rc = -1;
970 goto out;
971 }
972 }
973
974 if (symlink(asecLibDir, libdir) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000975 ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libdir, asecLibDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700976 rc = -errno;
977 goto out;
978 }
979
980 if (lchown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000981 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700982 unlink(libdir);
983 rc = -errno;
984 goto out;
985 }
986
987out:
988 if (chmod(dataDir, s.st_mode) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000989 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Dianne Hackbornd0c5f512012-06-07 16:53:59 -0700990 rc = -errno;
Kenny Root6a6b0072010-10-07 16:46:10 -0700991 }
992
993 if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +0000994 ALOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -0700995 return -errno;
996 }
997
998 return rc;
999}
1000
1001int unlinklib(const char* dataDir)
1002{
1003 char libdir[PKG_PATH_MAX];
1004 struct stat s, libStat;
1005 int rc = 0;
1006
1007 const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
1008 if (libdirLen >= PKG_PATH_MAX) {
1009 return -1;
1010 }
1011
1012 if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
Steve Block3762c312012-01-06 19:20:56 +00001013 ALOGE("library dir not written successfully: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001014 return -1;
1015 }
1016
1017 if (stat(dataDir, &s) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001018 ALOGE("couldn't state data dir");
Kenny Root6a6b0072010-10-07 16:46:10 -07001019 return -1;
1020 }
1021
1022 if (chown(dataDir, 0, 0) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001023 ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001024 return -1;
1025 }
1026
1027 if (chmod(dataDir, 0700) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001028 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001029 rc = -1;
1030 goto out;
1031 }
1032
1033 if (lstat(libdir, &libStat) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001034 ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001035 rc = -1;
1036 goto out;
1037 }
1038
1039 if (S_ISDIR(libStat.st_mode)) {
1040 if (delete_dir_contents(libdir, 1, 0) < 0) {
1041 rc = -1;
1042 goto out;
1043 }
1044 } else if (S_ISLNK(libStat.st_mode)) {
1045 if (unlink(libdir) < 0) {
1046 rc = -1;
1047 goto out;
1048 }
1049 }
1050
1051 if (mkdir(libdir, 0755) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001052 ALOGE("cannot create dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001053 rc = -errno;
1054 goto out;
1055 }
1056
1057 if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001058 ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001059 unlink(libdir);
1060 rc = -errno;
1061 goto out;
1062 }
1063
1064out:
1065 if (chmod(dataDir, s.st_mode) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001066 ALOGE("failed to chmod '%s': %s\n", dataDir, strerror(errno));
Dianne Hackbornd0c5f512012-06-07 16:53:59 -07001067 rc = -1;
Kenny Root6a6b0072010-10-07 16:46:10 -07001068 }
1069
1070 if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
Steve Block3762c312012-01-06 19:20:56 +00001071 ALOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
Kenny Root6a6b0072010-10-07 16:46:10 -07001072 return -1;
1073 }
1074
1075 return rc;
1076}