am cb9ae42: system/core: Remove old mountd code

Merge commit 'cb9ae42cd22cca46744bb964a2c412b145225748'

* commit 'cb9ae42cd22cca46744bb964a2c412b145225748':
  system/core: Remove old mountd code
This commit is contained in:
San Mehat 2009-04-29 15:17:35 -07:00 committed by The Android Open Source Project
commit e4da6a1a79
11 changed files with 0 additions and 3167 deletions

View File

@ -1,774 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** Android Secure External Cache
*/
#include "mountd.h"
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <dirent.h>
#include <ctype.h>
#include <pwd.h>
#include <stdlib.h>
#include <poll.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <linux/dm-ioctl.h>
#include <linux/loop.h>
#include <cutils/properties.h>
#include <cutils/misc.h>
#include "ASEC.h"
//#define MODULE_FAILURE_IS_FATAL
extern int init_module(void *, unsigned long, const char *);
extern int delete_module(const char *, unsigned int);
struct asec_context
{
char *name; // Device mapper volume name
char *srcPath; // Path to the source (original) mount
char *backingFile; // Name of the image file
unsigned int sectors; // Number of sectors
char *dstPath; // Destination mount point
char *crypt; // Crypt options
boolean needs_format;
boolean started;
int cacheFd;
int lo_num;
int dm_num;
unsigned char key[16];
};
static const char *MODULES[] = { "dm_mod", "crypto", "crypto_algapi", "crypto_blkcipher",
"cryptomgr", "dm_crypt", "jbd",
"twofish_common", "twofish", "cbc",
"mbcache", "ext3",
NULL };
static const char KEY_PATH[] = "/data/system/asec.key";
static const char MODULE_PATH[] = "/system/lib/modules";
static const char MKE2FS_PATH[] = "/system/bin/mke2fs";
static const char E2FSCK_PATH[] = "/system/bin/e2fsck";
boolean AsecIsStarted(void *Handle)
{
struct asec_context *ctx = (struct asec_context *) Handle;
return ctx->started;
}
const char *AsecMountPoint(void *Handle)
{
struct asec_context *ctx = (struct asec_context *) Handle;
return ctx->dstPath;
}
static boolean AsecIsEnabled()
{
char value[PROPERTY_VALUE_MAX];
int enabled;
property_get(ASEC_ENABLED, value, "0");
if (atoi(value) == 1)
return true;
return false;
}
void *AsecInit(const char *Name, const char *SrcPath, const char *BackingFile,
const char *Size, const char *DstPath, const char *Crypt)
{
struct asec_context *ctx;
if (!AsecIsEnabled())
return NULL;
LOG_ASEC("AsecInit(%s, %s, %s, %s, %s, %s):\n",
Name, SrcPath, BackingFile, Size, DstPath, Crypt);
if (!Name || !SrcPath || !BackingFile || !Size || !DstPath || !Crypt) {
LOG_ERROR("AsecInit(): Invalid arguments\n");
return NULL;
}
if (!(ctx = malloc(sizeof(struct asec_context)))) {
LOG_ERROR("AsecInit(): Out of memory\n");
return NULL;
}
memset(ctx, 0, sizeof(struct asec_context));
ctx->name = strdup(Name);
ctx->srcPath = strdup(SrcPath);
ctx->backingFile = strdup(BackingFile);
ctx->sectors = atoi(Size);
ctx->dstPath = strdup(DstPath);
ctx->crypt = strdup(Crypt);
return ctx;
}
void AsecDeinit(void *Handle)
{
struct asec_context *ctx = (struct asec_context *) Handle;
free(ctx->name);
free(ctx->srcPath);
free(ctx->backingFile);
free(ctx->dstPath);
free(ctx->crypt);
free(ctx);
}
static int AsecLoadModules()
{
int i;
for (i = 0; MODULES[i] != NULL; i++) {
const char *moduleName = MODULES[i];
char moduleFile[255];
int rc = 0;
void *module;
unsigned int size;
sprintf(moduleFile, "%s/%s.ko", MODULE_PATH, moduleName);
module = load_file(moduleFile, &size);
if (!module) {
LOG_ERROR("Failed to load module %s (%d)\n", moduleFile, errno);
return -1;
}
rc = init_module(module, size, "");
free(module);
if (rc && errno != EEXIST) {
LOG_ERROR("Failed to init module %s (%d)\n", moduleFile, errno);
return -errno;
}
}
return 0;
}
static int AsecUnloadModules()
{
int i, j, rc;
for (i = 0; MODULES[i] != NULL; i++);
for (j = (i - 1); j >= 0; j--) {
const char *moduleName = MODULES[j];
int maxretry = 10;
while(maxretry-- > 0) {
rc = delete_module(moduleName, O_NONBLOCK | O_EXCL);
if (rc < 0 && errno == EAGAIN)
usleep(500000);
else
break;
}
if (rc != 0) {
LOG_ERROR("Failed to unload module %s\n", moduleName);
return -errno;
}
}
return 0;
}
static int AsecGenerateKey(struct asec_context *ctx)
{
LOG_ASEC("AsecGenerateKey():\n");
memset((void *) ctx->key, 0x69, sizeof(ctx->key));
return 0;
}
static int AsecLoadGenerateKey(struct asec_context *ctx)
{
int fd;
int rc = 0;
if ((fd = open(KEY_PATH, O_RDWR | O_CREAT, 0600)) < 0) {
LOG_ERROR("Error opening / creating keyfile (%d)\n", errno);
return -errno;
}
if (read(fd, ctx->key, sizeof(ctx->key)) != sizeof(ctx->key)) {
LOG_ASEC("Generating key\n");
if ((rc = AsecGenerateKey(ctx)) < 0) {
LOG_ERROR("Error generating key (%d)\n", rc);
goto out;
}
if (write(fd, ctx->key, sizeof(ctx->key)) != sizeof(ctx->key)) {
LOG_ERROR("Error writing keyfile (%d)\n", errno);
rc = -1;
goto out;
}
}
out:
close (fd);
return rc;
}
static int AsecFormatFilesystem(struct asec_context *ctx)
{
char cmdline[255];
int rc;
sprintf(cmdline,
"%s -b 4096 -m 1 -j -L \"%s\" /dev/block/dm-%d",
MKE2FS_PATH, ctx->name, ctx->dm_num);
LOG_ASEC("Formatting filesystem (%s)\n", cmdline);
// XXX: PROTECT FROM VIKING KILLER
if ((rc = system(cmdline)) < 0) {
LOG_ERROR("Error executing format command (%d)\n", errno);
return -errno;
}
rc = WEXITSTATUS(rc);
if (!rc) {
LOG_ASEC("Format completed\n");
} else {
LOG_ASEC("Format failed (%d)\n", rc);
}
return rc;
}
static int AsecCheckFilesystem(struct asec_context *ctx)
{
char cmdline[255];
int rc;
sprintf(cmdline, "%s -p /dev/block/dm-%d", E2FSCK_PATH, ctx->dm_num);
LOG_ASEC("Checking filesystem (%s)\n", cmdline);
// XXX: PROTECT FROM VIKING KILLER
if ((rc = system(cmdline)) < 0) {
LOG_ERROR("Error executing check command (%d)\n", errno);
return -errno;
}
rc = WEXITSTATUS(rc);
if (rc == 0) {
LOG_ASEC("ASEC volume '%s' had no errors\n", ctx->name);
} else if (rc == 1) {
LOG_ASEC("ASEC volume '%s' had corrected errors\n", ctx->name);
rc = 0;
} else if (rc == 2) {
LOG_ERROR("ASEC volume '%s' had corrected errors (system should be rebooted)\n", ctx->name);
} else if (rc == 4) {
LOG_ERROR("ASEC volume '%s' had uncorrectable errors\n", ctx->name);
} else if (rc == 8) {
LOG_ERROR("Operational error while checking volume '%s'\n", ctx->name);
} else {
LOG_ERROR("Unknown e2fsck exit code (%d)\n", rc);
}
return rc;
}
static int AsecOpenCreateCache(struct asec_context *ctx)
{
char filepath[255];
sprintf(filepath, "%s/%s", ctx->srcPath, ctx->backingFile);
if ((ctx->cacheFd = open(filepath, O_RDWR)) < 0) {
if (errno == ENOENT) {
int rc = 0;
LOG_ASEC("Creating cache file (%u sectors)\n", ctx->sectors);
if ((ctx->cacheFd = creat(filepath, 0600)) < 0) {
LOG_ERROR("Error creating cache (%d)\n", errno);
return -errno;
}
if (ftruncate(ctx->cacheFd, ctx->sectors * 512) < 0) {
LOG_ERROR("Error truncating cache (%d)\n", errno);
close(ctx->cacheFd);
unlink(filepath);
return -errno;
}
LOG_ASEC("Cache created (%u sectors) \n", ctx->sectors);
close(ctx->cacheFd); // creat() is WRONLY
if ((ctx->cacheFd = open(filepath, O_RDWR)) < 0) {
LOG_ERROR("Error opening cache file (%d)\n", errno);
close(ctx->cacheFd);
unlink(filepath);
return -errno;
}
ctx->needs_format = 1;
} else
return -errno;
} else {
struct stat stat_buf;
if (fstat(ctx->cacheFd, &stat_buf) < 0) {
LOG_ERROR("Failed to fstat cache (%d)\n", errno);
close(ctx->cacheFd);
return -errno;
}
if (stat_buf.st_size != ctx->sectors * 512) {
LOG_ERROR("Cache size %lld != configured size %u\n",
stat_buf.st_size, ctx->sectors * 512);
}
// XXX: Verify volume label matches ctx->name
}
return 0;
}
static void AsecCloseCache(struct asec_context *ctx)
{
close(ctx->cacheFd);
}
static void *_align(void *ptr, unsigned int a)
{
register unsigned long agn = --a;
return (void *) (((unsigned long) ptr + agn) & ~agn);
}
static struct dm_ioctl *_dm_ioctl_setup(struct asec_context *ctx, int flags)
{
void *buffer;
void *p;
const size_t min_size = 16 * 1024;
size_t len = sizeof(struct dm_ioctl);
struct dm_ioctl *io;
struct dm_target_spec *tgt;
int i;
char params[1024];
char key[80];
key[0] = '\0';
for (i = 0; i < (int) sizeof(ctx->key); i++) {
char tmp[8];
sprintf(tmp, "%02x", ctx->key[i]);
strcat(key, tmp);
}
// XXX: Handle ctx->crypt
sprintf(params, "twofish %s 0 /dev/block/loop%d 0", key, ctx->lo_num);
if (len < min_size)
len = min_size;
if (!(buffer = malloc(len))) {
LOG_ERROR("Unable to allocate memory\n");
return NULL;
}
memset(buffer, 0, len);
io = buffer;
tgt = (struct dm_target_spec *) &buffer[sizeof(struct dm_ioctl)];
io->version[0] = 4;
io->version[1] = 0;
io->version[2] = 0;
io->data_size = len;
io->data_start = sizeof(struct dm_ioctl);
io->flags = flags;
io->dev = 0;
io->target_count = 1;
io->event_nr = 1;
strncpy(io->name, ctx->name, sizeof(io->name));
tgt->status = 0;
tgt->sector_start = 0;
tgt->length = ctx->sectors;
strncpy(tgt->target_type, "crypt", sizeof(tgt->target_type));
p = buffer + sizeof(struct dm_ioctl) + sizeof(struct dm_target_spec);
strcpy((char *) p, params);
p+= strlen(params) + 1;
p = _align(p, 8);
tgt->next = p - buffer;
return io;
}
static int FindNextAvailableDm()
{
int i;
for (i = 0; i < 8; i++) {
char path[255];
sprintf(path, "/dev/block/dm-%d", i);
if ((access(path, F_OK) < 0) && (errno == ENOENT))
return i;
}
LOG_ERROR("Out of device mapper numbers\n");
return -1;
}
static int AsecCreateDeviceMapping(struct asec_context *ctx)
{
struct dm_ioctl *io;
int dmFd;
int rc = 0;
ctx->dm_num = FindNextAvailableDm();
if ((dmFd = open("/dev/device-mapper", O_RDWR)) < 0) {
LOG_ERROR("Error opening device mapper (%d)\n", errno);
return -errno;
}
if (!(io = _dm_ioctl_setup(ctx, 0))) {
LOG_ERROR("Unable to setup ioctl (out of memory)\n");
close(dmFd);
return -ENOMEM;
}
if ((rc = ioctl(dmFd, DM_DEV_CREATE, io)) < 0) {
LOG_ERROR("device-mapper create ioctl failed (%d)\n", errno);
rc = -errno;
goto out_free;
}
free(io);
if (!(io = _dm_ioctl_setup(ctx, DM_STATUS_TABLE_FLAG))) {
LOG_ERROR("Unable to setup ioctl (out of memory)\n");
rc = -ENOMEM;
goto out_nofree;
}
if ((rc = ioctl(dmFd, DM_TABLE_LOAD, io)) < 0) {
LOG_ERROR("device-mapper load ioctl failed (%d)\n", errno);
rc = -errno;
goto out_free;
}
free(io);
if (!(io = _dm_ioctl_setup(ctx, 0))) {
LOG_ERROR("Unable to setup ioctl (out of memory)\n");
rc = -ENOMEM;
goto out_nofree;
}
if ((rc = ioctl(dmFd, DM_DEV_SUSPEND, io)) < 0) {
LOG_ERROR("device-mapper resume ioctl failed (%d)\n", errno);
rc = -errno;
goto out_free;
}
out_free:
free (io);
out_nofree:
close (dmFd);
return rc;
}
static int AsecDestroyDeviceMapping(struct asec_context *ctx)
{
struct dm_ioctl *io;
int dmFd;
int rc = 0;
if ((dmFd = open("/dev/device-mapper", O_RDWR)) < 0) {
LOG_ERROR("Error opening device mapper (%d)\n", errno);
return -errno;
}
if (!(io = _dm_ioctl_setup(ctx, DM_PERSISTENT_DEV_FLAG))) {
LOG_ERROR("Unable to setup ioctl (out of memory)\n");
rc = -ENOMEM;
goto out_nofree;
}
if ((rc = ioctl(dmFd, DM_DEV_REMOVE, io)) < 0) {
LOG_ERROR("device-mapper remove ioctl failed (%d)\n", errno);
rc = -errno;
goto out_free;
}
out_free:
free (io);
out_nofree:
close (dmFd);
return rc;
}
static int AsecMountCache(struct asec_context *ctx)
{
int flags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_NOATIME | MS_NODIRATIME;
char devname[255];
if (access(ctx->dstPath, R_OK)) {
LOG_ERROR("Destination mount point '%s' unavailable (%d)\n", ctx->dstPath, errno);
return -errno;
}
sprintf(devname, "/dev/block/dm-%d", ctx->dm_num);
if (mount(devname, ctx->dstPath, "ext3", flags, NULL)) {
LOG_ERROR("ASEC mount failed (%d)\n", errno);
return -errno;
}
return 0;
}
static int AsecUnmountCache(struct asec_context *ctx)
{
if (umount(ctx->dstPath)) {
if (errno == EBUSY) {
LOG_ASEC("ASEC volume '%s' still busy\n", ctx->name);
} else {
LOG_ERROR("ASEC umount failed (%d)\n", errno);
}
return -errno;
}
LOG_ASEC("ASEC volume '%s' unmounted\n", ctx->name);
return 0;
}
static int FindNextAvailableLoop()
{
int i;
for (i = 0; i < MAX_LOOP; i++) {
struct loop_info info;
char devname[255];
int fd;
sprintf(devname, "/dev/block/loop%d", i);
if ((fd = open(devname, O_RDONLY)) < 0) {
LOG_ERROR("Unable to open %s (%d)\n", devname, errno);
return -errno;
}
if (ioctl(fd, LOOP_GET_STATUS, &info) < 0) {
close(fd);
if (errno == ENXIO)
return i;
LOG_ERROR("Unable to get loop status for %s (%d)\n", devname, errno);
return -errno;
}
close(fd);
}
return -ENXIO;
}
static int AsecCreateLoop(struct asec_context *ctx)
{
char devname[255];
int device_fd;
int rc = 0;
ctx->lo_num = FindNextAvailableLoop();
if (ctx->lo_num < 0) {
LOG_ERROR("No loop devices available\n");
return -ENXIO;
}
sprintf(devname, "/dev/block/loop%d", ctx->lo_num);
device_fd = open(devname, O_RDWR);
if (device_fd < 0) {
LOG_ERROR("failed to open loop device (%d)\n", errno);
return -errno;
}
if (ioctl(device_fd, LOOP_SET_FD, ctx->cacheFd) < 0) {
LOG_ERROR("loop_set_fd ioctl failed (%d)\n", errno);
rc = -errno;
}
close(device_fd);
return rc;
}
static int AsecDestroyLoop(struct asec_context *ctx)
{
char devname[255];
int device_fd;
int rc = 0;
sprintf(devname, "/dev/block/loop%d", ctx->lo_num);
device_fd = open(devname, O_RDONLY);
if (device_fd < 0) {
LOG_ERROR("Failed to open loop (%d)\n", errno);
return -errno;
}
if (ioctl(device_fd, LOOP_CLR_FD, 0) < 0) {
LOG_ERROR("Failed to destroy loop (%d)\n", errno);
rc = -errno;
}
close(device_fd);
return rc;
}
int AsecStart(void *Handle)
{
struct asec_context *ctx = (struct asec_context *) Handle;
char value[PROPERTY_VALUE_MAX];
int rc = 0;
if (!ctx)
return -EINVAL;
if (ctx->started)
return -EBUSY;
LOG_ASEC("AsecStart(%s):\n", ctx->name);
NotifyAsecState(ASEC_BUSY, ctx->dstPath);
if ((rc = AsecLoadModules()) < 0) {
LOG_ERROR("AsecStart: Failed to load kernel modules\n");
#ifdef MODULE_FAILURE_IS_FATAL
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
return rc;
#endif
}
if ((rc = AsecLoadGenerateKey(ctx))) {
LOG_ERROR("AsecStart: Failed to load / generate key\n");
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
return rc;
}
if ((rc = AsecOpenCreateCache(ctx)) < 0) {
LOG_ERROR("AsecStart: Failed to open / create cache\n");
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
return rc;
}
if ((rc = AsecCreateLoop(ctx)) < 0) {
LOG_ERROR("AsecStart: Failed to create loop\n");
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
goto fail_closecache;
}
if ((rc = AsecCreateDeviceMapping(ctx)) < 0) {
LOG_ERROR("AsecStart: Failed to create devmapping (%d)\n", rc);
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
goto fail_destroyloop;
}
if (ctx->needs_format) {
if ((rc = AsecFormatFilesystem(ctx))) {
LOG_ERROR("AsecStart: Failed to format cache (%d)\n", rc);
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
goto fail_destroydm;
}
ctx->needs_format = 0;
} else {
if ((rc = AsecCheckFilesystem(ctx))) {
LOG_ERROR("AsecStart: Failed to check filesystem (%d)\n", rc);
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
goto fail_destroydm;
}
}
if ((rc = AsecMountCache(ctx)) < 0) {
LOG_ERROR("AsecStart: Failed to mount cache (%d)\n", rc);
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
goto fail_destroydm;
}
NotifyAsecState(ASEC_AVAILABLE, ctx->dstPath);
ctx->started = true;
return rc;
fail_destroydm:
AsecDestroyDeviceMapping(ctx);
fail_destroyloop:
AsecDestroyLoop(ctx);
fail_closecache:
AsecCloseCache(ctx);
return rc;
}
int AsecStop(void *Handle)
{
struct asec_context *ctx = (struct asec_context *) Handle;
int rc = 0;
if (!ctx->started)
return -EINVAL;
LOG_ASEC("AsecStop(%s):\n", ctx->name);
NotifyAsecState(ASEC_BUSY, ctx->dstPath);
if ((rc = AsecUnmountCache(ctx)) < 0) {
LOG_ERROR("AsecStop: Failed to unmount cache (%d)\n", rc);
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
return rc;
}
if ((rc = AsecDestroyDeviceMapping(ctx)) < 0) {
LOG_ERROR("AsecStop: Failed to destroy devmapping (%d)\n", rc);
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
return rc;
}
if ((rc = AsecDestroyLoop(ctx)) < 0) {
LOG_ERROR("AsecStop: Failed to destroy loop device (%d)\n", rc);
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
return rc;
}
AsecCloseCache(ctx);
if ((rc = AsecUnloadModules()) < 0) {
if (rc == -EAGAIN) {
LOG_ASEC("AsecStop: Kernel modules still in use\n");
} else {
LOG_ERROR("AsecStop: Failed to unload kernel modules (%d)\n", rc);
#ifdef MODULE_FAILURE_IS_FATAL
NotifyAsecState(ASEC_FAILED_INTERR, ctx->dstPath);
return rc;
#endif
}
}
ctx->started = false;
NotifyAsecState(ASEC_DISABLED, ctx->dstPath);
return rc;
}

View File

@ -1,66 +0,0 @@
#ifndef _ASEC_H
#define _ASEC_H
#define ASEC_STORES_MAX 4
#define MAX_LOOP 8
typedef enum AsecState {
// Feature disabled
ASEC_DISABLED,
// Feature enabled and operational
ASEC_AVAILABLE,
// Busy
ASEC_BUSY,
// Internal Error
ASEC_FAILED_INTERR,
// No media available
ASEC_FAILED_NOMEDIA,
// Media is corrupt
ASEC_FAILED_BADMEDIA,
// Key mismatch
ASEC_FAILED_BADKEY,
} AsecState;
/*
* ASEC commands
*/
#define ASEC_CMD_SEND_STATUS "asec_send_status"
#define ASEC_CMD_ENABLE "asec_enable"
#define ASEC_CMD_DISABLE "asec_disable"
/*
* ASEC events
*/
// These events correspond to the states in the AsecState enum.
// A path to the ASEC mount point follows the colon
#define ASEC_EVENT_DISABLED "asec_disabled:"
#define ASEC_EVENT_AVAILABLE "asec_available:"
#define ASEC_EVENT_BUSY "asec_busy:"
#define ASEC_EVENT_FAILED_INTERR "asec_failed_interror:"
#define ASEC_EVENT_FAILED_NOMEDIA "asec_failed_nomedia"
#define ASEC_EVENT_FAILED_BADMEDIA "asec_failed_badmedia:"
#define ASEC_EVENT_FAILED_BADKEY "asec_failed_badkey:"
/*
* System Properties
*/
#define ASEC_ENABLED "asec.enabled"
#define ASEC_STATUS "ro.asec.status"
#define ASEC_STATUS_DISABLED "disabled"
#define ASEC_STATUS_AVAILABLE "available"
#define ASEC_STATUS_BUSY "busy"
#define ASEC_STATUS_FAILED_INTERR "internal_error"
#define ASEC_STATUS_FAILED_NOMEDIA "no_media"
#define ASEC_STATUS_FAILED_BADMEDIA "bad_media"
#define ASEC_STATUS_FAILED_BADKEY "bad_key"
#endif

View File

@ -1,22 +0,0 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
AutoMount.c \
ProcessKiller.c \
Server.c \
mountd.c \
ASEC.c \
logwrapper.c
LOCAL_MODULE:= mountd
LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
LOCAL_CFLAGS := -DCREATE_MOUNT_POINTS=0
LOCAL_SHARED_LIBRARIES := libcutils
# disabled - we are using vold now instead
# include $(BUILD_EXECUTABLE)

File diff suppressed because it is too large Load Diff

View File

@ -1,190 +0,0 @@
Copyright (c) 2005-2008, The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

View File

@ -1,222 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** mountd process killer
*/
#include "mountd.h"
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <dirent.h>
#include <ctype.h>
#include <pwd.h>
#include <stdlib.h>
#include <poll.h>
#include <sys/stat.h>
static boolean ReadSymLink(const char* path, char* link)
{
struct stat s;
int length;
if (lstat(path, &s) < 0)
return false;
if ((s.st_mode & S_IFMT) != S_IFLNK)
return false;
// we have a symlink
length = readlink(path, link, PATH_MAX - 1);
if (length <= 0)
return false;
link[length] = 0;
return true;
}
static boolean PathMatchesMountPoint(const char* path, const char* mountPoint)
{
int length = strlen(mountPoint);
if (length > 1 && strncmp(path, mountPoint, length) == 0)
{
// we need to do extra checking if mountPoint does not end in a '/'
if (mountPoint[length - 1] == '/')
return true;
// if mountPoint does not have a trailing slash, we need to make sure
// there is one in the path to avoid partial matches.
return (path[length] == 0 || path[length] == '/');
}
return false;
}
static void GetProcessName(int pid, char buffer[PATH_MAX])
{
int fd;
sprintf(buffer, "/proc/%d/cmdline", pid);
fd = open(buffer, O_RDONLY);
if (fd < 0) {
strcpy(buffer, "???");
} else {
int length = read(fd, buffer, PATH_MAX - 1);
buffer[length] = 0;
close(fd);
}
}
static boolean CheckFileDescriptorSymLinks(int pid, const char* mountPoint)
{
DIR* dir;
struct dirent* de;
boolean fileOpen = false;
char path[PATH_MAX];
char link[PATH_MAX];
int parent_length;
// compute path to process's directory of open files
sprintf(path, "/proc/%d/fd", pid);
dir = opendir(path);
if (!dir)
return false;
// remember length of the path
parent_length = strlen(path);
// append a trailing '/'
path[parent_length++] = '/';
while ((de = readdir(dir)) != 0 && !fileOpen) {
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
continue;
// append the file name, after truncating to parent directory
path[parent_length] = 0;
strcat(path, de->d_name);
if (ReadSymLink(path, link) && PathMatchesMountPoint(link, mountPoint))
{
char name[PATH_MAX];
GetProcessName(pid, name);
LOG_ERROR("process %s (%d) has open file %s\n", name, pid, link);
fileOpen = true;
}
}
closedir(dir);
return fileOpen;
}
static boolean CheckFileMaps(int pid, const char* mountPoint)
{
FILE* file;
char buffer[PATH_MAX + 100];
boolean mapOpen = false;
sprintf(buffer, "/proc/%d/maps", pid);
file = fopen(buffer, "r");
if (!file)
return false;
while (!mapOpen && fgets(buffer, sizeof(buffer), file))
{
// skip to the path
const char* path = strchr(buffer, '/');
if (path && PathMatchesMountPoint(path, mountPoint))
{
char name[PATH_MAX];
GetProcessName(pid, name);
LOG_ERROR("process %s (%d) has open file map for %s\n", name, pid, path);
mapOpen = true;
}
}
fclose(file);
return mapOpen;
}
static boolean CheckSymLink(int pid, const char* mountPoint, const char* name, const char* message)
{
char path[PATH_MAX];
char link[PATH_MAX];
sprintf(path, "/proc/%d/%s", pid, name);
if (ReadSymLink(path, link) && PathMatchesMountPoint(link, mountPoint))
{
char name[PATH_MAX];
GetProcessName(pid, name);
LOG_ERROR("process %s (%d) has %s in %s\n", name, pid, message, mountPoint);
return true;
}
else
return false;
}
static int get_pid(const char* s)
{
int result = 0;
while (*s) {
if (!isdigit(*s)) return -1;
result = 10 * result + (*s++ - '0');
}
return result;
}
// hunt down and kill processes that have files open on the given mount point
void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, int *excluded, int num_excluded)
{
DIR* dir;
struct dirent* de;
LOG_ERROR("KillProcessesWithOpenFiles %s\n", mountPoint);
dir = opendir("/proc");
if (!dir) return;
while ((de = readdir(dir)) != 0)
{
boolean killed = false;
// does the name look like a process ID?
int pid = get_pid(de->d_name);
if (pid == -1) continue;
if (CheckFileDescriptorSymLinks(pid, mountPoint) // check for open files
|| CheckFileMaps(pid, mountPoint) // check for mmap()
|| CheckSymLink(pid, mountPoint, "cwd", "working directory") // check working directory
|| CheckSymLink(pid, mountPoint, "root", "chroot") // check for chroot()
|| CheckSymLink(pid, mountPoint, "exe", "executable path") // check executable path
)
{
int i;
boolean hit = false;
for (i = 0; i < num_excluded; i++) {
if (pid == excluded[i]) {
LOG_ERROR("I just need a little more TIME captain!\n");
hit = true;
break;
}
}
if (!hit) {
LOG_ERROR("Killing process %d\n", pid);
kill(pid, (sigkill ? SIGKILL : SIGTERM));
}
}
}
closedir(dir);
}

View File

@ -1,313 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** mountd server support
*/
#include "mountd.h"
#include "ASEC.h"
#include <cutils/properties.h>
#include <cutils/sockets.h>
#include <pthread.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <private/android_filesystem_config.h>
// current client file descriptor
static int sFD = -1;
// to synchronize writing to client
static pthread_mutex_t sWriteMutex = PTHREAD_MUTEX_INITIALIZER;
// path for media that failed to mount before the runtime is connected
static char* sDeferredUnmountableMediaPath = NULL;
// last asec msg before the runtime was connected
static char* sAsecDeferredMessage = NULL;
static char* sAsecDeferredArgument = NULL;
static int Write(const char* message)
{
int result = -1;
pthread_mutex_lock(&sWriteMutex);
LOG_SERVER("Write: %s\n", message);
if (sFD >= 0)
result = write(sFD, message, strlen(message) + 1);
pthread_mutex_unlock(&sWriteMutex);
return result;
}
static int Write2(const char* message, const char* data)
{
int result = -1;
char* buffer = (char *)alloca(strlen(message) + strlen(data) + 1);
if (!buffer)
{
LOG_ERROR("alloca failed in Write2\n");
return -1;
}
strcpy(buffer, message);
strcat(buffer, data);
return Write(buffer);
}
static void SendStatus()
{
Write(IsMassStorageConnected() ? MOUNTD_UMS_CONNECTED : MOUNTD_UMS_DISCONNECTED);
Write(IsMassStorageEnabled() ? MOUNTD_UMS_ENABLED : MOUNTD_UMS_DISABLED);
}
static void DoCommand(const char* command)
{
LOG_SERVER("DoCommand %s\n", command);
if (strcmp(command, MOUNTD_ENABLE_UMS) == 0)
{
EnableMassStorage(true);
Write(MOUNTD_UMS_ENABLED);
}
else if (strcmp(command, MOUNTD_DISABLE_UMS) == 0)
{
EnableMassStorage(false);
Write(MOUNTD_UMS_DISABLED);
}
else if (strcmp(command, MOUNTD_SEND_STATUS) == 0)
{
SendStatus();
}
else if (strncmp(command, MOUNTD_MOUNT_MEDIA, strlen(MOUNTD_MOUNT_MEDIA)) == 0)
{
const char* path = command + strlen(MOUNTD_MOUNT_MEDIA);
MountMedia(path);
}
else if (strncmp(command, MOUNTD_EJECT_MEDIA, strlen(MOUNTD_EJECT_MEDIA)) == 0)
{
const char* path = command + strlen(MOUNTD_EJECT_MEDIA);
UnmountMedia(path);
}
else if (strncmp(command, ASEC_CMD_ENABLE, strlen(ASEC_CMD_ENABLE)) == 0) {
LOG_ASEC("Got ASEC_CMD_ENABLE\n");
// XXX: SAN: Impliment
}
else if (strncmp(command, ASEC_CMD_DISABLE, strlen(ASEC_CMD_DISABLE)) == 0) {
LOG_ASEC("Got ASEC_CMD_DISABLE\n");
// XXX: SAN: Impliment
}
else if (strncmp(command, ASEC_CMD_SEND_STATUS, strlen(ASEC_CMD_SEND_STATUS)) == 0) {
LOG_ASEC("Got ASEC_CMD_SEND_STATUS\n");
// XXX: SAN: Impliment
}
else
LOGE("unknown command %s\n", command);
}
int RunServer()
{
int socket = android_get_control_socket(MOUNTD_SOCKET);
if (socket < 0) {
LOGE("Obtaining file descriptor for socket '%s' failed: %s",
MOUNTD_SOCKET, strerror(errno));
return -1;
}
if (listen(socket, 4) < 0) {
LOGE("Unable to listen on file descriptor '%d' for socket '%s': %s",
socket, MOUNTD_SOCKET, strerror(errno));
return -1;
}
while (1)
{
struct sockaddr addr;
socklen_t alen;
struct ucred cred;
socklen_t size;
alen = sizeof(addr);
sFD = accept(socket, &addr, &alen);
if (sFD < 0)
continue;
if (sDeferredUnmountableMediaPath) {
NotifyMediaState(sDeferredUnmountableMediaPath, MEDIA_UNMOUNTABLE, false);
free(sDeferredUnmountableMediaPath);
sDeferredUnmountableMediaPath = NULL;
}
if (sAsecDeferredMessage) {
if (Write2(sAsecDeferredMessage, sAsecDeferredArgument) < 0)
LOG_ERROR("Failed to deliver deferred ASEC msg to framework\n");
free(sAsecDeferredMessage);
free(sAsecDeferredArgument);
sAsecDeferredMessage = sAsecDeferredArgument = NULL;
}
while (1)
{
char buffer[101];
int result = read(sFD, buffer, sizeof(buffer) - 1);
if (result > 0)
{
int start = 0;
int i;
// command should be zero terminated, but just in case
buffer[result] = 0;
for (i = 0; i < result; i++)
{
if (buffer[i] == 0)
{
DoCommand(buffer + start);
start = i + 1;
}
}
}
else
{
close(sFD);
sFD = -1;
break;
}
}
}
// should never get here
return 0;
}
void SendMassStorageConnected(boolean connected)
{
Write(connected ? MOUNTD_UMS_CONNECTED : MOUNTD_UMS_DISCONNECTED);
}
void SendUnmountRequest(const char* path)
{
Write2(MOUNTD_REQUEST_EJECT, path);
}
void NotifyAsecState(AsecState state, const char *argument)
{
const char *event = NULL;
const char *status = NULL;
boolean deferr = true;;
switch (state) {
case ASEC_DISABLED:
event = ASEC_EVENT_DISABLED;
status = ASEC_STATUS_DISABLED;
break;
case ASEC_AVAILABLE:
event = ASEC_EVENT_AVAILABLE;
status = ASEC_STATUS_AVAILABLE;
break;
case ASEC_BUSY:
event = ASEC_EVENT_BUSY;
status = ASEC_STATUS_BUSY;
deferr = false;
break;
case ASEC_FAILED_INTERR:
event = ASEC_EVENT_FAILED_INTERR;
status = ASEC_STATUS_FAILED_INTERR;
break;
case ASEC_FAILED_NOMEDIA:
event = ASEC_EVENT_FAILED_NOMEDIA;
status = ASEC_STATUS_FAILED_NOMEDIA;
break;
case ASEC_FAILED_BADMEDIA:
event = ASEC_EVENT_FAILED_BADMEDIA;
status = ASEC_STATUS_FAILED_BADMEDIA;
break;
case ASEC_FAILED_BADKEY:
event = ASEC_EVENT_FAILED_BADKEY;
status = ASEC_STATUS_FAILED_BADKEY;
break;
default:
LOG_ERROR("unknown AsecState %d in NotifyAsecState\n", state);
return;
}
property_set(ASEC_STATUS, status);
int result = Write2(event, argument);
if ((result < 0) && deferr) {
if (sAsecDeferredMessage)
free(sAsecDeferredMessage);
sAsecDeferredMessage = strdup(event);
if (sAsecDeferredArgument)
free(sAsecDeferredArgument);
sAsecDeferredArgument = strdup(argument);
LOG_ASEC("Deferring event '%s' arg '%s' until framework connects\n", event, argument);
}
}
void NotifyMediaState(const char* path, MediaState state, boolean readOnly)
{
const char* event = NULL;
const char* propertyValue = NULL;
switch (state) {
case MEDIA_REMOVED:
event = MOUNTD_MEDIA_REMOVED;
propertyValue = EXTERNAL_STORAGE_REMOVED;
break;
case MEDIA_UNMOUNTED:
event = MOUNTD_MEDIA_UNMOUNTED;
propertyValue = EXTERNAL_STORAGE_UNMOUNTED;
break;
case MEDIA_MOUNTED:
event = (readOnly ? MOUNTD_MEDIA_MOUNTED_READ_ONLY : MOUNTD_MEDIA_MOUNTED);
propertyValue = (readOnly ? EXTERNAL_STORAGE_MOUNTED_READ_ONLY : EXTERNAL_STORAGE_MOUNTED);
break;
case MEDIA_SHARED:
event = MOUNTD_MEDIA_SHARED;
propertyValue = EXTERNAL_STORAGE_SHARED;
break;
case MEDIA_BAD_REMOVAL:
event = MOUNTD_MEDIA_BAD_REMOVAL;
propertyValue = EXTERNAL_STORAGE_BAD_REMOVAL;
break;
case MEDIA_UNMOUNTABLE:
event = MOUNTD_MEDIA_UNMOUNTABLE;
propertyValue = EXTERNAL_STORAGE_UNMOUNTABLE;
break;
default:
LOG_ERROR("unknown MediaState %d in NotifyMediaState\n", state);
return;
}
property_set(EXTERNAL_STORAGE_STATE, propertyValue);
int result = Write2(event, path);
if (result < 0 && state == MEDIA_UNMOUNTABLE) {
// if we cannot communicate with the runtime, defer this message until the runtime is available
sDeferredUnmountableMediaPath = strdup(path);
}
}

View File

@ -1,154 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include "private/android_filesystem_config.h"
#include "cutils/log.h"
int parent(const char *tag, int parent_read) {
int status;
char buffer[4096];
int a = 0; // start index of unprocessed data
int b = 0; // end index of unprocessed data
int sz;
while ((sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b)) > 0) {
sz += b;
// Log one line at a time
for (b = 0; b < sz; b++) {
if (buffer[b] == '\r') {
buffer[b] = '\0';
} else if (buffer[b] == '\n') {
buffer[b] = '\0';
LOG(LOG_INFO, tag, &buffer[a]);
a = b + 1;
}
}
if (a == 0 && b == sizeof(buffer) - 1) {
// buffer is full, flush
buffer[b] = '\0';
LOG(LOG_INFO, tag, &buffer[a]);
b = 0;
} else if (a != b) {
// Keep left-overs
b -= a;
memmove(buffer, &buffer[a], b);
a = 0;
} else {
a = 0;
b = 0;
}
}
// Flush remaining data
if (a != b) {
buffer[b] = '\0';
LOG(LOG_INFO, tag, &buffer[a]);
}
status = 0xAAAA;
if (wait(&status) != -1) { // Wait for child
if (WIFEXITED(status)) {
LOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
WEXITSTATUS(status));
return WEXITSTATUS(status);
} else if (WIFSIGNALED(status))
LOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag,
WTERMSIG(status));
else if (WIFSTOPPED(status))
LOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag,
WSTOPSIG(status));
} else
LOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag,
strerror(errno), errno);
return -EAGAIN;
}
void child(int argc, char* argv[]) {
// create null terminated argv_child array
char* argv_child[argc + 1];
memcpy(argv_child, argv, argc * sizeof(char *));
argv_child[argc] = NULL;
// XXX: PROTECT FROM VIKING KILLER
if (execvp(argv_child[0], argv_child)) {
LOG(LOG_ERROR, "logwrapper",
"executing %s failed: %s\n", argv_child[0], strerror(errno));
exit(-1);
}
}
int logwrap(int argc, char* argv[])
{
pid_t pid;
int parent_ptty;
int child_ptty;
char *child_devname = NULL;
/* Use ptty instead of socketpair so that STDOUT is not buffered */
parent_ptty = open("/dev/ptmx", O_RDWR);
if (parent_ptty < 0) {
LOG(LOG_ERROR, "logwrapper", "Cannot create parent ptty\n");
return -errno;
}
if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
((child_devname = (char*)ptsname(parent_ptty)) == 0)) {
LOG(LOG_ERROR, "logwrapper", "Problem with /dev/ptmx\n");
return -1;
}
pid = fork();
if (pid < 0) {
LOG(LOG_ERROR, "logwrapper", "Failed to fork\n");
return -errno;
} else if (pid == 0) {
child_ptty = open(child_devname, O_RDWR);
if (child_ptty < 0) {
LOG(LOG_ERROR, "logwrapper", "Problem with child ptty\n");
return -errno;
}
// redirect stdout and stderr
close(parent_ptty);
dup2(child_ptty, 1);
dup2(child_ptty, 2);
close(child_ptty);
child(argc, argv);
} else {
// switch user and group to "log"
// this may fail if we are not root,
// but in that case switching user/group is unnecessary
// setgid(AID_LOG);
// setuid(AID_LOG);
return parent(argv[0], parent_ptty);
}
return 0;
}

View File

@ -1,174 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
** mountd main program
*/
#include "mountd.h"
#include <cutils/config_utils.h>
#include <cutils/cpu_info.h>
#include <cutils/properties.h>
#include <sys/mount.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <linux/capability.h>
#include <linux/prctl.h>
#include <private/android_filesystem_config.h>
#ifdef MOUNTD_LOG
FILE* logFile;
#endif
struct asec_cfg {
const char *name;
const char *backing_file;
const char *size;
const char *mount_point;
const char *crypt;
};
static int ProcessAsecData(cnode *node, struct asec_cfg *stores, int idx)
{
cnode *child = node->first_child;
const char *name = NULL;
const char *file = NULL;
const char *size = NULL;
const char *mp = NULL;
const char *crypt = NULL;
LOG_ASEC("ProcessAsecData(%s, %p, %d)\n", node->name, stores, idx);
while (child) {
if (!strcmp(child->name, "name"))
name = child->value;
else if (!strcmp(child->name, "backing_file"))
file = child->value;
else if (!strcmp(child->name, "size"))
size = child->value;
else if (!strcmp(child->name, "mount_point"))
mp = child->value;
else if (!strcmp(child->name, "crypt"))
crypt = child->value;
child = child->next;
}
if (!name || !file || !size || !mp || !crypt) {
LOG_ERROR("Missing required token from config. Skipping ASEC volume\n");
return -1;
} else if (idx == ASEC_STORES_MAX) {
LOG_ERROR("Maximum # of ASEC stores already defined\n");
return -1;
}
stores[idx].name = name;
stores[idx].backing_file = file;
stores[idx].size = size;
stores[idx].mount_point = mp;
stores[idx].crypt = crypt;
return ++idx;
}
static void ReadConfigFile(const char* path)
{
cnode* root = config_node("", "");
cnode* node;
config_load_file(root, path);
node = root->first_child;
while (node)
{
if (strcmp(node->name, "mount") == 0)
{
const char* block_device = NULL;
const char* mount_point = NULL;
const char* driver_store_path = NULL;
boolean enable_ums = false;
cnode* child = node->first_child;
struct asec_cfg asec_stores[ASEC_STORES_MAX];
int asec_idx = 0;
memset(asec_stores, 0, sizeof(asec_stores));
while (child)
{
const char* name = child->name;
const char* value = child->value;
if (!strncmp(name, "asec_", 5)) {
int rc = ProcessAsecData(child, asec_stores, asec_idx);
if (rc < 0) {
LOG_ERROR("Error processing ASEC cfg data\n");
} else
asec_idx = rc;
} else if (strcmp(name, "block_device") == 0)
block_device = value;
else if (strcmp(name, "mount_point") == 0)
mount_point = value;
else if (strcmp(name, "driver_store_path") == 0)
driver_store_path = value;
else if (strcmp(name, "enable_ums") == 0 &&
strcmp(value, "true") == 0)
enable_ums = true;
child = child->next;
}
// mount point and removable fields are optional
if (block_device && mount_point)
{
void *mp = AddMountPoint(block_device, mount_point, driver_store_path, enable_ums);
int i;
for (i = 0; i < asec_idx; i++) {
AddAsecToMountPoint(mp, asec_stores[i].name, asec_stores[i].backing_file,
asec_stores[i].size, asec_stores[i].mount_point,
asec_stores[i].crypt);
}
}
}
node = node->next;
}
}
int main(int argc, char* argv[])
{
const char* configPath = "/system/etc/mountd.conf";
int i;
for (i = 1; i < argc; i++)
{
const char* arg = argv[i];
if (strcmp(arg, "-f") == 0)
{
if (i < argc - 1)
configPath = argv[++i];
}
}
ReadConfigFile(configPath);
StartAutoMounter();
return RunServer();
}

View File

@ -1,190 +0,0 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MOUNTD_H__
#define MOUNTD_H__
#define LOG_TAG "mountd"
#include "cutils/log.h"
#include "ASEC.h"
typedef int boolean;
enum {
false = 0,
true = 1
};
#define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
// Set this for logging error messages
#define ENABLE_LOG_ERROR
// set this to log automounter events
#define ENABLE_LOG_MOUNT
// set this to log server events
//#define ENABLE_LOG_SERVER
// set this to log ASEC events
#define ENABLE_LOG_ASEC
#ifdef ENABLE_LOG_ERROR
#define LOG_ERROR(fmt, args...) \
{ LOGE(fmt , ## args); }
#else
#define LOG_ERROR(fmt, args...) \
do { } while (0)
#endif /* ENABLE_LOG_ERROR */
#ifdef ENABLE_LOG_MOUNT
#define LOG_MOUNT(fmt, args...) \
{ LOGD(fmt , ## args); }
#else
#define LOG_MOUNT(fmt, args...) \
do { } while (0)
#endif /* ENABLE_LOG_MOUNT */
#ifdef ENABLE_LOG_SERVER
#define LOG_SERVER(fmt, args...) \
{ LOGD(fmt , ## args); }
#else
#define LOG_SERVER(fmt, args...) \
do { } while (0)
#endif /* ENABLE_LOG_SERVER */
#ifdef ENABLE_LOG_ASEC
#define LOG_ASEC(fmt, args...) \
{ LOGD(fmt , ## args); }
#else
#define LOG_ASEC(fmt, args...) \
do { } while (0)
#endif /* ENABLE_LOG_ASEC */
typedef enum MediaState {
// no media in SD card slot
MEDIA_REMOVED,
// media in SD card slot, but not mounted
MEDIA_UNMOUNTED,
// media in SD card slot and mounted at its mount point
MEDIA_MOUNTED,
// media in SD card slot, unmounted, and shared as a mass storage device
MEDIA_SHARED,
// media was removed from SD card slot, but mount point was not unmounted
// this state is cleared after the mount point is unmounted
MEDIA_BAD_REMOVAL,
// media in SD card slot could not be mounted (corrupt file system?)
MEDIA_UNMOUNTABLE,
} MediaState;
// socket name for connecting to mountd
#define MOUNTD_SOCKET "mountd"
// mountd commands
// these must match the corresponding strings in //device/java/android/android/os/UsbListener.java
#define MOUNTD_ENABLE_UMS "enable_ums"
#define MOUNTD_DISABLE_UMS "disable_ums"
#define MOUNTD_SEND_STATUS "send_status"
// these commands should contain a mount point following the colon
#define MOUNTD_MOUNT_MEDIA "mount_media:"
#define MOUNTD_EJECT_MEDIA "eject_media:"
// mountd events
// these must match the corresponding strings in //device/java/android/android/os/UsbListener.java
#define MOUNTD_UMS_ENABLED "ums_enabled"
#define MOUNTD_UMS_DISABLED "ums_disabled"
#define MOUNTD_UMS_CONNECTED "ums_connected"
#define MOUNTD_UMS_DISCONNECTED "ums_disconnected"
// these events correspond to the states in the MediaState enum.
// a path to the mount point follows the colon.
#define MOUNTD_MEDIA_REMOVED "media_removed:"
#define MOUNTD_MEDIA_UNMOUNTED "media_unmounted:"
#define MOUNTD_MEDIA_MOUNTED "media_mounted:"
#define MOUNTD_MEDIA_MOUNTED_READ_ONLY "media_mounted_ro:"
#define MOUNTD_MEDIA_SHARED "media_shared:"
#define MOUNTD_MEDIA_BAD_REMOVAL "media_bad_removal:"
#define MOUNTD_MEDIA_UNMOUNTABLE "media_unmountable:"
// this event sent to request unmount for media mount point
#define MOUNTD_REQUEST_EJECT "request_eject:"
// system properties
// these must match the corresponding strings in //device/java/android/android/os/Environment.java
#define EXTERNAL_STORAGE_STATE "EXTERNAL_STORAGE_STATE"
#define EXTERNAL_STORAGE_REMOVED "removed"
#define EXTERNAL_STORAGE_UNMOUNTED "unmounted"
#define EXTERNAL_STORAGE_MOUNTED "mounted"
#define EXTERNAL_STORAGE_MOUNTED_READ_ONLY "mounted_ro"
#define EXTERNAL_STORAGE_SHARED "shared"
#define EXTERNAL_STORAGE_BAD_REMOVAL "bad_removal"
#define EXTERNAL_STORAGE_UNMOUNTABLE "unmountable"
// AutoMount.c
boolean IsMassStorageEnabled();
boolean IsMassStorageConnected();
void MountMedia(const char* mountPoint);
void UnmountMedia(const char* mountPoint);
void EnableMassStorage(boolean enable);
// call this before StartAutoMounter() to add a mount point to monitor
void *AddMountPoint(const char* device, const char* mountPoint, const char* driverStorePath,
boolean enableUms);
int AddAsecToMountPoint(void *Mp, const char *name, const char *backing_file,
const char *size, const char *mount_point, const char *crypt);
// start automounter thread
void StartAutoMounter();
// check /proc/mounts for mounted file systems, and notify mount or unmount for any that are in our automount list
void NotifyExistingMounts();
// ASEC.c
void *AsecInit(const char *Name, const char *SrcPath, const char *BackingFile,
const char *Size, const char *DstPath, const char *Crypt);
int AsecStart(void *Handle);
int AsecStop(void *Handle);
void AsecDeinit(void *Handle);
boolean AsecIsStarted(void *Handle);
const char *AsecMountPoint(void *Handle);
// ProcessKiller.c
void KillProcessesWithOpenFiles(const char* mountPoint, boolean sigkill, pid_t *excluded, int num_excluded);
// logwrapper.c
int logwrap(int argc, char* argv[]);
// Server.c
int RunServer();
void SendMassStorageConnected(boolean connected);
void SendUnmountRequest(const char* path);
void NotifyMediaState(const char* path, MediaState state, boolean readOnly);
void NotifyAsecState(AsecState state, const char *argument);
#endif // MOUNTD_H__