blob: a6aab9c52556ff39c4cbdc2bb401463004e9592b [file] [log] [blame]
The Android Open Source Project35237d12008-12-17 18:08:08 -08001/*
2 * Copyright (C) 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/*
18** Android Secure External Cache
19*/
20
21#include "mountd.h"
22
23#include <stdio.h>
24#include <unistd.h>
25#include <string.h>
26#include <fcntl.h>
27#include <dirent.h>
28#include <ctype.h>
29#include <pwd.h>
30#include <stdlib.h>
31#include <poll.h>
32#include <errno.h>
33
34#include <sys/ioctl.h>
35#include <sys/mount.h>
36#include <sys/stat.h>
37
The Android Open Source Project5ae090e2009-01-09 17:51:25 -080038#include <linux/dm-ioctl.h>
The Android Open Source Project35237d12008-12-17 18:08:08 -080039#include <linux/loop.h>
40
41#include <cutils/properties.h>
42#include <cutils/misc.h>
43
44#include "ASEC.h"
The Android Open Source Project5ae090e2009-01-09 17:51:25 -080045
46//#define MODULE_FAILURE_IS_FATAL
The Android Open Source Project35237d12008-12-17 18:08:08 -080047
48extern int init_module(void *, unsigned long, const char *);
49extern int delete_module(const char *, unsigned int);
50
51struct asec_context
52{
53 char *name; // Device mapper volume name
54 char *srcPath; // Path to the source (original) mount
55 char *backingFile; // Name of the image file
56 unsigned int sectors; // Number of sectors
57 char *dstPath; // Destination mount point
58 char *crypt; // Crypt options
59
60 boolean needs_format;
61 boolean started;
62 int cacheFd;
63 int lo_num;
64 int dm_num;
65 unsigned char key[16];
66};
67
68static const char *MODULES[] = { "dm_mod", "crypto", "crypto_algapi", "crypto_blkcipher",
69 "cryptomgr", "dm_crypt", "jbd",
70 "twofish_common", "twofish", "cbc",
71 "mbcache", "ext3",
72 NULL };
73static const char KEY_PATH[] = "/data/system/asec.key";
74static const char MODULE_PATH[] = "/system/lib/modules";
75static const char MKE2FS_PATH[] = "/system/bin/mke2fs";
76static const char E2FSCK_PATH[] = "/system/bin/e2fsck";
77
78boolean AsecIsStarted(void *Handle)
79{
80 struct asec_context *ctx = (struct asec_context *) Handle;
81
82 return ctx->started;
83}
84
85const char *AsecMountPoint(void *Handle)
86{
87 struct asec_context *ctx = (struct asec_context *) Handle;
88
89 return ctx->dstPath;
90}
91
92static boolean AsecIsEnabled()
93{
94 char value[PROPERTY_VALUE_MAX];
95 int enabled;
96
97 property_get(ASEC_ENABLED, value, "0");
98
99 if (atoi(value) == 1)
100 return true;
101 return false;
102}
103
104void *AsecInit(const char *Name, const char *SrcPath, const char *BackingFile,
105 const char *Size, const char *DstPath, const char *Crypt)
106{
107 struct asec_context *ctx;
108
The Android Open Source Project5ae090e2009-01-09 17:51:25 -0800109 if (!AsecIsEnabled())
110 return NULL;
111
The Android Open Source Project35237d12008-12-17 18:08:08 -0800112 LOG_ASEC("AsecInit(%s, %s, %s, %s, %s, %s):\n",
113 Name, SrcPath, BackingFile, Size, DstPath, Crypt);
114
The Android Open Source Project35237d12008-12-17 18:08:08 -0800115 if (!Name || !SrcPath || !BackingFile || !Size || !DstPath || !Crypt) {
116 LOG_ERROR("AsecInit(): Invalid arguments\n");
117 return NULL;
118 }
119
120 if (!(ctx = malloc(sizeof(struct asec_context)))) {
121 LOG_ERROR("AsecInit(): Out of memory\n");
122 return NULL;
123 }
124
125 memset(ctx, 0, sizeof(struct asec_context));
126 ctx->name = strdup(Name);
127 ctx->srcPath = strdup(SrcPath);
128 ctx->backingFile = strdup(BackingFile);
129 ctx->sectors = atoi(Size);
130 ctx->dstPath = strdup(DstPath);
131 ctx->crypt = strdup(Crypt);
132 return ctx;
133}
134
135void AsecDeinit(void *Handle)
136{
137 struct asec_context *ctx = (struct asec_context *) Handle;
138
139 free(ctx->name);
140 free(ctx->srcPath);
141 free(ctx->backingFile);
142 free(ctx->dstPath);
143 free(ctx->crypt);
144
145 free(ctx);
146}
147
148static int AsecLoadModules()
149{
150 int i;
151
152 for (i = 0; MODULES[i] != NULL; i++) {
153 const char *moduleName = MODULES[i];
154 char moduleFile[255];
155 int rc = 0;
156 void *module;
157 unsigned int size;
158
159 sprintf(moduleFile, "%s/%s.ko", MODULE_PATH, moduleName);
160 module = load_file(moduleFile, &size);
161 if (!module) {
The Android Open Source Project5ae090e2009-01-09 17:51:25 -0800162 LOG_ERROR("Failed to load module %s (%d)\n", moduleFile, errno);
The Android Open Source Project35237d12008-12-17 18:08:08 -0800163 return -1;
164 }
165
166 rc = init_module(module, size, "");
167 free(module);
168 if (rc && errno != EEXIST) {
169 LOG_ERROR("Failed to init module %s (%d)\n", moduleFile, errno);
170 return -errno;
171 }
172 }
173 return 0;
174}
175
176static int AsecUnloadModules()
177{
178 int i, j, rc;
179
180 for (i = 0; MODULES[i] != NULL; i++);
181
182 for (j = (i - 1); j >= 0; j--) {
183 const char *moduleName = MODULES[j];
184 int maxretry = 10;
185 while(maxretry-- > 0) {
186 rc = delete_module(moduleName, O_NONBLOCK | O_EXCL);
187 if (rc < 0 && errno == EAGAIN)
188 usleep(500000);
189 else
190 break;
191 }
192 if (rc != 0) {
193 LOG_ERROR("Failed to unload module %s\n", moduleName);
194 return -errno;
195 }
196 }
197 return 0;
198}
199
200static int AsecGenerateKey(struct asec_context *ctx)
201{
202 LOG_ASEC("AsecGenerateKey():\n");
203
204 memset((void *) ctx->key, 0x69, sizeof(ctx->key));
205 return 0;
206}
207
208static int AsecLoadGenerateKey(struct asec_context *ctx)
209{
210 int fd;
211 int rc = 0;
212
213 if ((fd = open(KEY_PATH, O_RDWR | O_CREAT, 0600)) < 0) {
214 LOG_ERROR("Error opening / creating keyfile (%d)\n", errno);
215 return -errno;
216 }
217
218 if (read(fd, ctx->key, sizeof(ctx->key)) != sizeof(ctx->key)) {
219 LOG_ASEC("Generating key\n");
220 if ((rc = AsecGenerateKey(ctx)) < 0) {
221 LOG_ERROR("Error generating key (%d)\n", rc);
222 goto out;
223 }
224 if (write(fd, ctx->key, sizeof(ctx->key)) != sizeof(ctx->key)) {
225 LOG_ERROR("Error writing keyfile (%d)\n", errno);
226 rc = -1;
227 goto out;
228 }
229 }
230
231 out:
232 close (fd);
233 return rc;
234}
235
236static int AsecFormatFilesystem(struct asec_context *ctx)
237{
238 char cmdline[255];
239 int rc;
240
241 sprintf(cmdline,
242 "%s -b 4096 -m 1 -j -L \"%s\" /dev/block/dm-%d",
243 MKE2FS_PATH, ctx->name, ctx->dm_num);
244
245 LOG_ASEC("Formatting filesystem (%s)\n", cmdline);
246 // XXX: PROTECT FROM VIKING KILLER
247 if ((rc = system(cmdline)) < 0) {
248 LOG_ERROR("Error executing format command (%d)\n", errno);
249 return -errno;
250 }
251
252 rc = WEXITSTATUS(rc);
253
254 if (!rc) {
255 LOG_ASEC("Format completed\n");
256 } else {
257 LOG_ASEC("Format failed (%d)\n", rc);
258 }
259
260 return rc;
261}
262
263static int AsecCheckFilesystem(struct asec_context *ctx)
264{
265 char cmdline[255];
266 int rc;
267
268 sprintf(cmdline, "%s -p /dev/block/dm-%d", E2FSCK_PATH, ctx->dm_num);
269
270 LOG_ASEC("Checking filesystem (%s)\n", cmdline);
271 // XXX: PROTECT FROM VIKING KILLER
272 if ((rc = system(cmdline)) < 0) {
273 LOG_ERROR("Error executing check command (%d)\n", errno);
274 return -errno;
275 }
276
277 rc = WEXITSTATUS(rc);
278
279 if (rc == 0) {
280 LOG_ASEC("ASEC volume '%s' had no errors\n", ctx->name);
281 } else if (rc == 1) {
282 LOG_ASEC("ASEC volume '%s' had corrected errors\n", ctx->name);
283 rc = 0;
284 } else if (rc == 2) {
285 LOG_ERROR("ASEC volume '%s' had corrected errors (system should be rebooted)\n", ctx->name);
286 } else if (rc == 4) {
287 LOG_ERROR("ASEC volume '%s' had uncorrectable errors\n", ctx->name);
288 } else if (rc == 8) {
289 LOG_ERROR("Operational error while checking volume '%s'\n", ctx->name);
290 } else {
291 LOG_ERROR("Unknown e2fsck exit code (%d)\n", rc);
292 }
293 return rc;
294}
295
296static int AsecOpenCreateCache(struct asec_context *ctx)
297{
298 char filepath[255];
299
300 sprintf(filepath, "%s/%s", ctx->srcPath, ctx->backingFile);
301
302 if ((ctx->cacheFd = open(filepath, O_RDWR)) < 0) {
303 if (errno == ENOENT) {
304 int rc = 0;
305
306 LOG_ASEC("Creating cache file (%u sectors)\n", ctx->sectors);
307 if ((ctx->cacheFd = creat(filepath, 0600)) < 0) {
308 LOG_ERROR("Error creating cache (%d)\n", errno);
309 return -errno;
310 }
311 if (ftruncate(ctx->cacheFd, ctx->sectors * 512) < 0) {
312 LOG_ERROR("Error truncating cache (%d)\n", errno);
313 close(ctx->cacheFd);
314 unlink(filepath);
315 return -errno;
316 }
317 LOG_ASEC("Cache created (%u sectors) \n", ctx->sectors);
318 close(ctx->cacheFd); // creat() is WRONLY
319
320 if ((ctx->cacheFd = open(filepath, O_RDWR)) < 0) {
321 LOG_ERROR("Error opening cache file (%d)\n", errno);
322 close(ctx->cacheFd);
323 unlink(filepath);
324 return -errno;
325 }
326
327 ctx->needs_format = 1;
328 } else
329 return -errno;
330 } else {
331 struct stat stat_buf;
332
333 if (fstat(ctx->cacheFd, &stat_buf) < 0) {
334 LOG_ERROR("Failed to fstat cache (%d)\n", errno);
335 close(ctx->cacheFd);
336 return -errno;
337 }
338 if (stat_buf.st_size != ctx->sectors * 512) {
339 LOG_ERROR("Cache size %lld != configured size %u\n",
340 stat_buf.st_size, ctx->sectors * 512);
341 }
342
343 // XXX: Verify volume label matches ctx->name
344 }
345
346 return 0;
347}
348
349static void AsecCloseCache(struct asec_context *ctx)
350{
351 close(ctx->cacheFd);
352}
353
354static void *_align(void *ptr, unsigned int a)
355{
356 register unsigned long agn = --a;
357
358 return (void *) (((unsigned long) ptr + agn) & ~agn);
359}
360
361static struct dm_ioctl *_dm_ioctl_setup(struct asec_context *ctx, int flags)
362{
363 void *buffer;
364 void *p;
365 const size_t min_size = 16 * 1024;
366 size_t len = sizeof(struct dm_ioctl);
367 struct dm_ioctl *io;
368 struct dm_target_spec *tgt;
369 int i;
370 char params[1024];
371 char key[80];
372
373 key[0] = '\0';
374
375 for (i = 0; i < (int) sizeof(ctx->key); i++) {
376 char tmp[8];
377
378 sprintf(tmp, "%02x", ctx->key[i]);
379 strcat(key, tmp);
380 }
381
382 // XXX: Handle ctx->crypt
383 sprintf(params, "twofish %s 0 /dev/block/loop%d 0", key, ctx->lo_num);
384
385 if (len < min_size)
386 len = min_size;
387
388 if (!(buffer = malloc(len))) {
389 LOG_ERROR("Unable to allocate memory\n");
390 return NULL;
391 }
392
393 memset(buffer, 0, len);
394 io = buffer;
395 tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
396
397 io->version[0] = 4;
398 io->version[1] = 0;
399 io->version[2] = 0;
400
401 io->data_size = len;
402 io->data_start = sizeof(struct dm_ioctl);
403
404 io->flags = flags;
405 io->dev = 0;
406
407 io->target_count = 1;
408 io->event_nr = 1;
409 strncpy(io->name, ctx->name, sizeof(io->name));
410
411 tgt->status = 0;
412 tgt->sector_start = 0;
413 tgt->length = ctx->sectors;
414 strncpy(tgt->target_type, "crypt", sizeof(tgt->target_type));
415
416 p = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
417 strcpy((char *) p, params);
418 p+= strlen(params) + 1;
419
420 p = _align(p, 8);
421 tgt->next = p - buffer;
422
423 return io;
424}
425
426static int FindNextAvailableDm()
427{
428 int i;
429
430 for (i = 0; i < 8; i++) {
431 char path[255];
432 sprintf(path, "/dev/block/dm-%d", i);
433 if ((access(path, F_OK) < 0) && (errno == ENOENT))
434 return i;
435 }
436
437 LOG_ERROR("Out of device mapper numbers\n");
438 return -1;
439}
440
441static int AsecCreateDeviceMapping(struct asec_context *ctx)
442{
443 struct dm_ioctl *io;
444 int dmFd;
445 int rc = 0;
446
447 ctx->dm_num = FindNextAvailableDm();
448
449 if ((dmFd = open("/dev/device-mapper", O_RDWR)) < 0) {
450 LOG_ERROR("Error opening device mapper (%d)\n", errno);
451 return -errno;
452 }
453
454 if (!(io = _dm_ioctl_setup(ctx, 0))) {
455 LOG_ERROR("Unable to setup ioctl (out of memory)\n");
456 close(dmFd);
457 return -ENOMEM;
458 }
459
460 if ((rc = ioctl(dmFd, DM_DEV_CREATE, io)) < 0) {
461 LOG_ERROR("device-mapper create ioctl failed (%d)\n", errno);
462 rc = -errno;
463 goto out_free;
464 }
465
466 free(io);
467
468 if (!(io = _dm_ioctl_setup(ctx, DM_STATUS_TABLE_FLAG))) {
469 LOG_ERROR("Unable to setup ioctl (out of memory)\n");
470 rc = -ENOMEM;
471 goto out_nofree;
472 }
473
474 if ((rc = ioctl(dmFd, DM_TABLE_LOAD, io)) < 0) {
475 LOG_ERROR("device-mapper load ioctl failed (%d)\n", errno);
476 rc = -errno;
477 goto out_free;
478 }
479
480 free(io);
481
482 if (!(io = _dm_ioctl_setup(ctx, 0))) {
483 LOG_ERROR("Unable to setup ioctl (out of memory)\n");
484 rc = -ENOMEM;
485 goto out_nofree;
486 }
487
488 if ((rc = ioctl(dmFd, DM_DEV_SUSPEND, io)) < 0) {
489 LOG_ERROR("device-mapper resume ioctl failed (%d)\n", errno);
490 rc = -errno;
491 goto out_free;
492 }
493
494out_free:
495 free (io);
496out_nofree:
497 close (dmFd);
498 return rc;
499}
500
501static int AsecDestroyDeviceMapping(struct asec_context *ctx)
502{
503 struct dm_ioctl *io;
504 int dmFd;
505 int rc = 0;
506
507 if ((dmFd = open("/dev/device-mapper", O_RDWR)) < 0) {
508 LOG_ERROR("Error opening device mapper (%d)\n", errno);
509 return -errno;
510 }
511
512 if (!(io = _dm_ioctl_setup(ctx, DM_PERSISTENT_DEV_FLAG))) {
513 LOG_ERROR("Unable to setup ioctl (out of memory)\n");
514 rc = -ENOMEM;
515 goto out_nofree;
516 }
517
518 if ((rc = ioctl(dmFd, DM_DEV_REMOVE, io)) < 0) {
519 LOG_ERROR("device-mapper remove ioctl failed (%d)\n", errno);
520 rc = -errno;
521 goto out_free;
522 }
523
524out_free:
525 free (io);
526out_nofree:
527 close (dmFd);
528 return rc;
529}
530
531static int AsecMountCache(struct asec_context *ctx)
532{
533 int flags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_NOATIME | MS_NODIRATIME;
534 char devname[255];
535
536 if (access(ctx->dstPath, R_OK)) {
537 LOG_ERROR("Destination mount point '%s' unavailable (%d)\n", ctx->dstPath, errno);
538 return -errno;
539 }
540
541 sprintf(devname, "/dev/block/dm-%d", ctx->dm_num);
542
543 if (mount(devname, ctx->dstPath, "ext3", flags, NULL)) {
544 LOG_ERROR("ASEC mount failed (%d)\n", errno);
545 return -errno;
546 }
547
548 return 0;
549}
550
551static int AsecUnmountCache(struct asec_context *ctx)
552{
553 if (umount(ctx->dstPath)) {
554 if (errno == EBUSY) {
555 LOG_ASEC("ASEC volume '%s' still busy\n", ctx->name);
556 } else {
557 LOG_ERROR("ASEC umount failed (%d)\n", errno);
558 }
559 return -errno;
560 }
561 LOG_ASEC("ASEC volume '%s' unmounted\n", ctx->name);
562 return 0;
563}
564
565static int FindNextAvailableLoop()
566{
567 int i;
568
569 for (i = 0; i < MAX_LOOP; i++) {
570 struct loop_info info;
571 char devname[255];
572 int fd;
573
574 sprintf(devname, "/dev/block/loop%d", i);
575
576 if ((fd = open(devname, O_RDONLY)) < 0) {
577 LOG_ERROR("Unable to open %s (%d)\n", devname, errno);
578 return -errno;
579 }
580
581 if (ioctl(fd, LOOP_GET_STATUS, &info) < 0) {
582 close(fd);
583
584 if (errno == ENXIO)
585 return i;
586
587 LOG_ERROR("Unable to get loop status for %s (%d)\n", devname, errno);
588 return -errno;
589 }
590 close(fd);
591 }
592 return -ENXIO;
593}
594
595static int AsecCreateLoop(struct asec_context *ctx)
596{
597 char devname[255];
598 int device_fd;
599 int rc = 0;
600
601 ctx->lo_num = FindNextAvailableLoop();
602 if (ctx->lo_num < 0) {
603 LOG_ERROR("No loop devices available\n");
604 return -ENXIO;
605 }
606
607 sprintf(devname, "/dev/block/loop%d", ctx->lo_num);
608 device_fd = open(devname, O_RDWR);
609 if (device_fd < 0) {
610 LOG_ERROR("failed to open loop device (%d)\n", errno);
611 return -errno;
612 }
613
614 if (ioctl(device_fd, LOOP_SET_FD, ctx->cacheFd) < 0) {
615 LOG_ERROR("loop_set_fd ioctl failed (%d)\n", errno);
616 rc = -errno;
617 }
618 close(device_fd);
619 return rc;
620}
621
622static int AsecDestroyLoop(struct asec_context *ctx)
623{
624 char devname[255];
625 int device_fd;
626 int rc = 0;
627
628 sprintf(devname, "/dev/block/loop%d", ctx->lo_num);
629 device_fd = open(devname, O_RDONLY);
630 if (device_fd < 0) {
631 LOG_ERROR("Failed to open loop (%d)\n", errno);
632 return -errno;
633 }
634
635 if (ioctl(device_fd, LOOP_CLR_FD, 0) < 0) {
636 LOG_ERROR("Failed to destroy loop (%d)\n", errno);
637 rc = -errno;
638 }
639
640 close(device_fd);
641 return rc;
642}
643
644int AsecStart(void *Handle)
645{
646 struct asec_context *ctx = (struct asec_context *) Handle;
647 char value[PROPERTY_VALUE_MAX];
648 int rc = 0;
649
650 if (!ctx)
651 return -EINVAL;
652
653 if (ctx->started)
654 return -EBUSY;
655
656 LOG_ASEC("AsecStart(%s):\n", ctx->name);
657
658 NotifyAsecState(ASEC_BUSY, ctx->dstPath);
659
660 if ((rc = AsecLoadModules()) < 0) {
661 LOG_ERROR("AsecStart: Failed to load kernel modules\n");
The Android Open Source Project5ae090e2009-01-09 17:51:25 -0800662#ifdef MODULE_FAILURE_IS_FATAL
The Android Open Source Project35237d12008-12-17 18:08:08 -0800663 NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
664 return rc;
The Android Open Source Project5ae090e2009-01-09 17:51:25 -0800665#endif
The Android Open Source Project35237d12008-12-17 18:08:08 -0800666 }
667
668 if ((rc = AsecLoadGenerateKey(ctx))) {
669 LOG_ERROR("AsecStart: Failed to load / generate key\n");
670 NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
671 return rc;
672 }
673
674 if ((rc = AsecOpenCreateCache(ctx)) < 0) {
675 LOG_ERROR("AsecStart: Failed to open / create cache\n");
676 NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
677 return rc;
678 }
679
680 if ((rc = AsecCreateLoop(ctx)) < 0) {
681 LOG_ERROR("AsecStart: Failed to create loop\n");
682 NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
683 goto fail_closecache;
684 }
685
686 if ((rc = AsecCreateDeviceMapping(ctx)) < 0) {
687 LOG_ERROR("AsecStart: Failed to create devmapping (%d)\n", rc);
688 NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
689 goto fail_destroyloop;
690 }
691
692 if (ctx->needs_format) {
693 if ((rc = AsecFormatFilesystem(ctx))) {
694 LOG_ERROR("AsecStart: Failed to format cache (%d)\n", rc);
695 NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
696 goto fail_destroydm;
697 }
698 ctx->needs_format = 0;
699 } else {
700 if ((rc = AsecCheckFilesystem(ctx))) {
701 LOG_ERROR("AsecStart: Failed to check filesystem (%d)\n", rc);
702 NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
703 goto fail_destroydm;
704 }
705 }
706
707 if ((rc = AsecMountCache(ctx)) < 0) {
708 LOG_ERROR("AsecStart: Failed to mount cache (%d)\n", rc);
709 NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
710 goto fail_destroydm;
711 }
712
713 NotifyAsecState(ASEC_AVAILABLE, ctx->dstPath);
714 ctx->started = true;
715
716 return rc;
717
718 fail_destroydm:
719 AsecDestroyDeviceMapping(ctx);
720 fail_destroyloop:
721 AsecDestroyLoop(ctx);
722 fail_closecache:
723 AsecCloseCache(ctx);
724 return rc;
725}
726
727int AsecStop(void *Handle)
728{
729 struct asec_context *ctx = (struct asec_context *) Handle;
730 int rc = 0;
731
732 if (!ctx->started)
733 return -EINVAL;
734
735 LOG_ASEC("AsecStop(%s):\n", ctx->name);
736
737 NotifyAsecState(ASEC_BUSY, ctx->dstPath);
738
739 if ((rc = AsecUnmountCache(ctx)) < 0) {
740 LOG_ERROR("AsecStop: Failed to unmount cache (%d)\n", rc);
741 NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
742 return rc;
743 }
744
745 if ((rc = AsecDestroyDeviceMapping(ctx)) < 0) {
746 LOG_ERROR("AsecStop: Failed to destroy devmapping (%d)\n", rc);
747 NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
748 return rc;
749 }
750
751 if ((rc = AsecDestroyLoop(ctx)) < 0) {
752 LOG_ERROR("AsecStop: Failed to destroy loop device (%d)\n", rc);
753 NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
754 return rc;
755 }
756
757 AsecCloseCache(ctx);
758
759 if ((rc = AsecUnloadModules()) < 0) {
760 if (rc == -EAGAIN) {
761 LOG_ASEC("AsecStop: Kernel modules still in use\n");
762 } else {
763 LOG_ERROR("AsecStop: Failed to unload kernel modules (%d)\n", rc);
The Android Open Source Project5ae090e2009-01-09 17:51:25 -0800764#ifdef MODULE_FAILURE_IS_FATAL
The Android Open Source Project35237d12008-12-17 18:08:08 -0800765 NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
766 return rc;
The Android Open Source Project5ae090e2009-01-09 17:51:25 -0800767#endif
The Android Open Source Project35237d12008-12-17 18:08:08 -0800768 }
769 }
770
771 ctx->started = false;
772 NotifyAsecState(ASEC_DISABLED, ctx->dstPath);
773 return rc;
774}