diff options
-rw-r--r-- | Android.mk | 43 | ||||
-rw-r--r-- | BlockDevice.cpp | 36 | ||||
-rw-r--r-- | BlockDevice.h | 39 | ||||
-rw-r--r-- | CommandListener.cpp | 96 | ||||
-rw-r--r-- | CommandListener.h | 67 | ||||
-rw-r--r-- | DeviceVolume.cpp | 73 | ||||
-rw-r--r-- | DeviceVolume.h | 44 | ||||
-rw-r--r-- | ErrorCode.h | 43 | ||||
-rw-r--r-- | NetlinkHandler.cpp | 91 | ||||
-rw-r--r-- | NetlinkHandler.h | 34 | ||||
-rw-r--r-- | NetlinkManager.cpp | 95 | ||||
-rw-r--r-- | NetlinkManager.h | 48 | ||||
-rw-r--r-- | VoldCommand.cpp | 21 | ||||
-rw-r--r-- | VoldCommand.h | 28 | ||||
-rw-r--r-- | Volume.cpp | 46 | ||||
-rw-r--r-- | Volume.h | 54 | ||||
-rw-r--r-- | VolumeManager.cpp | 103 | ||||
-rw-r--r-- | VolumeManager.h | 64 | ||||
-rw-r--r-- | main.cpp | 159 | ||||
-rw-r--r-- | vdc.c | 148 |
20 files changed, 1332 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..3af7544 --- /dev/null +++ b/Android.mk @@ -0,0 +1,43 @@ +BUILD_VOLD2 := false +ifeq ($(BUILD_VOLD2),true) + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + main.cpp \ + VolumeManager.cpp \ + CommandListener.cpp \ + VoldCommand.cpp \ + NetlinkManager.cpp \ + NetlinkHandler.cpp \ + BlockDevice.cpp \ + Volume.cpp \ + DeviceVolume.cpp + +LOCAL_MODULE:= vold + +LOCAL_C_INCLUDES := $(KERNEL_HEADERS) -I../../frameworks/base/include/ + +LOCAL_CFLAGS := + +LOCAL_SHARED_LIBRARIES := libsysutils + +include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES:= \ + vdc.c \ + +LOCAL_MODULE:= vdc + +LOCAL_C_INCLUDES := $(KERNEL_HEADERS) + +LOCAL_CFLAGS := + +LOCAL_SHARED_LIBRARIES := libcutils + +include $(BUILD_EXECUTABLE) + +endif # ifeq ($(BUILD_VOLD,true) diff --git a/BlockDevice.cpp b/BlockDevice.cpp new file mode 100644 index 0000000..97c980d --- /dev/null +++ b/BlockDevice.cpp @@ -0,0 +1,36 @@ +/* + * 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 <stdio.h> +#include <errno.h> +#include <string.h> + +#define LOG_TAG "Vold" + +#include <cutils/log.h> + +#include "BlockDevice.h" + +BlockDevice::BlockDevice(const char *devpath, int major, int minor) { + mDevpath = strdup(devpath); + mMajor = major; + mMinor = minor; +} + +BlockDevice::~BlockDevice() { + free(mDevpath); +} + diff --git a/BlockDevice.h b/BlockDevice.h new file mode 100644 index 0000000..0239824 --- /dev/null +++ b/BlockDevice.h @@ -0,0 +1,39 @@ +/* + * 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 _BLKDEVICE_H +#define _BLKDEVICE_H + +#include <utils/List.h> + +class BlockDevice { + + char *mDevpath; + int mMajor; + int mMinor; + +public: + BlockDevice(const char *devpath, int major, int minor); + virtual ~BlockDevice(); + + const char *getDevpath() { return mDevpath; } + int getMajor() { return mMajor; } + int getMinor() { return mMinor; } +}; + +typedef android::List<BlockDevice *> BlockDeviceCollection; + +#endif diff --git a/CommandListener.cpp b/CommandListener.cpp new file mode 100644 index 0000000..f395818 --- /dev/null +++ b/CommandListener.cpp @@ -0,0 +1,96 @@ +/* + * 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 <stdlib.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <errno.h> + +#define LOG_TAG "CommandListener" +#include <cutils/log.h> + +#include <sysutils/SocketClient.h> + +#include "CommandListener.h" +#include "VolumeManager.h" +#include "ErrorCode.h" + +CommandListener::CommandListener() : + FrameworkListener("vold") { + registerCmd(new ListVolumesCmd()); + registerCmd(new MountVolumeCmd()); + registerCmd(new UnmountVolumeCmd()); + registerCmd(new ShareVolumeCmd()); + registerCmd(new UnshareVolumeCmd()); +} + +CommandListener::ListVolumesCmd::ListVolumesCmd() : + VoldCommand("list_volumes") { +} + +int CommandListener::ListVolumesCmd::runCommand(SocketClient *cli, + int argc, char **argv) { + return VolumeManager::Instance()->listVolumes(cli); +} + +CommandListener::MountVolumeCmd::MountVolumeCmd() : + VoldCommand("mount_volume") { +} + +int CommandListener::MountVolumeCmd::runCommand(SocketClient *cli, + int argc, char **argv) { + VolumeManager *nm = VolumeManager::Instance(); + errno = ENOSYS; + cli->sendMsg(ErrorCode::OperationFailed, "Failed to mount volume", true); + return 0; +} + +CommandListener::UnmountVolumeCmd::UnmountVolumeCmd() : + VoldCommand("unmount_volume") { +} + +int CommandListener::UnmountVolumeCmd::runCommand(SocketClient *cli, + int argc, char **argv) { + VolumeManager *nm = VolumeManager::Instance(); + errno = ENOSYS; + cli->sendMsg(ErrorCode::OperationFailed, "Failed to unmount volume", true); + return 0; +} + +CommandListener::ShareVolumeCmd::ShareVolumeCmd() : + VoldCommand("share_volume") { +} + +int CommandListener::ShareVolumeCmd::runCommand(SocketClient *cli, + int argc, char **argv) { + VolumeManager *nm = VolumeManager::Instance(); + errno = ENOSYS; + cli->sendMsg(ErrorCode::OperationFailed, "Failed to share volume", true); + return 0; +} + +CommandListener::UnshareVolumeCmd::UnshareVolumeCmd() : + VoldCommand("unshare_volume") { +} + +int CommandListener::UnshareVolumeCmd::runCommand(SocketClient *cli, + int argc, char **argv) { + VolumeManager *nm = VolumeManager::Instance(); + errno = ENOSYS; + cli->sendMsg(ErrorCode::OperationFailed, "Failed to unshare volume", true); + return 0; +} diff --git a/CommandListener.h b/CommandListener.h new file mode 100644 index 0000000..9c770a2 --- /dev/null +++ b/CommandListener.h @@ -0,0 +1,67 @@ +/* + * 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 _COMMANDLISTENER_H__ +#define _COMMANDLISTENER_H__ + +#include <sysutils/FrameworkListener.h> +#include "VoldCommand.h" + +class CommandListener : public FrameworkListener { +public: + CommandListener(); + virtual ~CommandListener() {} + +private: + + class ListVolumesCmd : public VoldCommand { + public: + ListVolumesCmd(); + virtual ~ListVolumesCmd() {} + int runCommand(SocketClient *c, int argc, char ** argv); + }; + + class MountVolumeCmd : public VoldCommand { + public: + MountVolumeCmd(); + virtual ~MountVolumeCmd() {} + int runCommand(SocketClient *c, int argc, char ** argv); + }; + + class UnmountVolumeCmd : public VoldCommand { + public: + UnmountVolumeCmd(); + virtual ~UnmountVolumeCmd() {} + int runCommand(SocketClient *c, int argc, char ** argv); + }; + + class ShareVolumeCmd : public VoldCommand { + public: + ShareVolumeCmd(); + virtual ~ShareVolumeCmd() {} + int runCommand(SocketClient *c, int argc, char ** argv); + }; + + class UnshareVolumeCmd : public VoldCommand { + public: + UnshareVolumeCmd(); + virtual ~UnshareVolumeCmd() {} + int runCommand(SocketClient *c, int argc, char ** argv); + }; + +}; + +#endif diff --git a/DeviceVolume.cpp b/DeviceVolume.cpp new file mode 100644 index 0000000..187e97f --- /dev/null +++ b/DeviceVolume.cpp @@ -0,0 +1,73 @@ +/* + * 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 <stdio.h> +#include <errno.h> +#include <string.h> + +#define LOG_TAG "Vold" + +#include <cutils/log.h> + +#include "DeviceVolume.h" + +DeviceVolume::DeviceVolume(const char *label, const char *mount_point, int partIdx) : + Volume(label, mount_point) { + mPartIdx = partIdx; + + mPaths = new PathCollection(); +} + +DeviceVolume::~DeviceVolume() { + PathCollection::iterator it; + + for (it = mPaths->begin(); it != mPaths->end(); ++it) + free(*it); + delete mPaths; +} + +int DeviceVolume::addPath(const char *path) { + mPaths->push_back(strdup(path)); + return 0; +} + +int DeviceVolume::handleDiskInsertion(const char *dp, int maj, int min, + int nr_parts) { + PathCollection::iterator it; + + LOGD("Dv::diskInsertion - %s %d %d %d", dp, maj, min, nr_parts); + for (it = mPaths->begin(); it != mPaths->end(); ++it) { + LOGD("Dv::chk %s", *it); + if (!strncmp(dp, *it, strlen(*it))) { + /* + * We can handle this disk. If there are no partitions then we're + * good to go son! + */ + mDiskMaj = maj; + mDiskNumParts = nr_parts; + if (nr_parts == 0) { + LOGD("Dv::diskIns - No partitions - good to go"); + setState(Volume::State_Idle); + } else { + LOGD("Dv::diskIns - waiting for %d partitions", nr_parts); + setState(Volume::State_Pending); + } + return 0; + } + } + errno = ENODEV; + return -1; +} diff --git a/DeviceVolume.h b/DeviceVolume.h new file mode 100644 index 0000000..edf4c98 --- /dev/null +++ b/DeviceVolume.h @@ -0,0 +1,44 @@ +/* + * 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 _DEVICEVOLUME_H +#define _DEVICEVOLUME_H + +#include <utils/List.h> + +#include "Volume.h" + +typedef android::List<char *> PathCollection; + +class DeviceVolume : public Volume { +protected: + PathCollection *mPaths; + int mPartIdx; + int mDiskMaj; + int mDiskNumParts; + +public: + DeviceVolume(const char *label, const char *mount_point, int partIdx); + virtual ~DeviceVolume(); + + int addPath(const char *path); + + int handleDiskInsertion(const char *dp, int maj, int min, int nr_parts); +}; + +typedef android::List<DeviceVolume *> DeviceVolumeCollection; + +#endif diff --git a/ErrorCode.h b/ErrorCode.h new file mode 100644 index 0000000..328b2b1 --- /dev/null +++ b/ErrorCode.h @@ -0,0 +1,43 @@ +/* + * 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 _ERRORCODE_H +#define _ERRORCODE_H + +class ErrorCode { +public: + // 100 series - Requestion action was initiated; expect another reply + // before proceeding with a new command. + static const int ActionInitiated = 100; + + static const int VolumeListResult = 110; + + // 200 series - Requested action has been successfully completed + static const int CommandOkay = 200; + + // 400 series - The command was accepted but the requested action + // did not take place. + static const int OperationFailed = 400; + + // 500 series - The command was not accepted and the requested + // action did not take place. + static const int CommandSyntaxError = 500; + static const int CommandParameterError = 501; + + // 600 series - Unsolicited broadcasts + static const int UnsolicitedInformational = 600; +}; +#endif diff --git a/NetlinkHandler.cpp b/NetlinkHandler.cpp new file mode 100644 index 0000000..156079f --- /dev/null +++ b/NetlinkHandler.cpp @@ -0,0 +1,91 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> +#include <errno.h> + +#define LOG_TAG "Vold" + +#include <cutils/log.h> + +#include <sysutils/NetlinkEvent.h> +#include "NetlinkHandler.h" +#include "VolumeManager.h" + +NetlinkHandler::NetlinkHandler(int listenerSocket) : + NetlinkListener(listenerSocket) { +} + +NetlinkHandler::~NetlinkHandler() { +} + +int NetlinkHandler::start() { + return this->startListener(); +} + +int NetlinkHandler::stop() { + return this->stopListener(); +} + +void NetlinkHandler::onEvent(NetlinkEvent *evt) { + VolumeManager *vm = VolumeManager::Instance(); + const char *subsys = evt->getSubsystem(); + int action = evt->getAction(); + + if (!subsys) { + LOGW("No subsystem found in netlink event"); + return; + } + + if (!strcmp(subsys, "block")) { + const char *devpath = evt->findParam("DEVPATH"); + const char *devtype = evt->findParam("DEVTYPE"); + int major = atoi(evt->findParam("MAJOR")); + int minor = atoi(evt->findParam("MINOR")); + + LOGI("Block event %d, type %s, %d:%d, path '%s'", action, devtype, major, minor, devpath); + + if (!strcmp(devtype, "disk")) { + const char *tmp = evt->findParam("NPARTS"); + + if (!tmp) { + LOGE("Disk uevent missing 'NPARTS' parameter"); + return; + } + if (action == NetlinkEvent::NlActionAdd) + vm->handleDiskInserted(devpath, major, minor, atoi(tmp)); + else if (action == NetlinkEvent::NlActionRemove) + vm->handleDiskRemoved(major, minor); + } else { + const char *tmp = evt->findParam("PARTN"); + + if (!tmp) { + LOGE("Partition uevent missing 'PARTN' parameter"); + return; + } + if (action == NetlinkEvent::NlActionAdd) + vm->handlePartCreated(devpath, major, minor, atoi(tmp)); + else if (action == NetlinkEvent::NlActionRemove) + vm->handlePartRemoved(major, minor); + } + LOGD("Block event handled"); + } else if (!strcmp(subsys, "battery")) { + } else if (!strcmp(subsys, "power_supply")) { + } else { + LOGE("Dropping %s netlink event", subsys); + } +} diff --git a/NetlinkHandler.h b/NetlinkHandler.h new file mode 100644 index 0000000..00a31c8 --- /dev/null +++ b/NetlinkHandler.h @@ -0,0 +1,34 @@ +/* + * 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 _NETLINKHANDLER_H +#define _NETLINKHANDLER_H + +#include <sysutils/NetlinkListener.h> + +class NetlinkHandler: public NetlinkListener { + +public: + NetlinkHandler(int listenerSocket); + virtual ~NetlinkHandler(); + + int start(void); + int stop(void); + +protected: + virtual void onEvent(NetlinkEvent *evt); +}; +#endif diff --git a/NetlinkManager.cpp b/NetlinkManager.cpp new file mode 100644 index 0000000..271a75f --- /dev/null +++ b/NetlinkManager.cpp @@ -0,0 +1,95 @@ +/* + * 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 <stdio.h> +#include <errno.h> + +#include <sys/socket.h> +#include <sys/select.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/un.h> + +#include <linux/netlink.h> + +#define LOG_TAG "Vold" + +#include <cutils/log.h> + +#include "NetlinkManager.h" +#include "NetlinkHandler.h" + +NetlinkManager *NetlinkManager::sInstance = NULL; + +NetlinkManager *NetlinkManager::Instance() { + if (!sInstance) + sInstance = new NetlinkManager(); + return sInstance; +} + +NetlinkManager::NetlinkManager() { + mBroadcaster = NULL; +} + +NetlinkManager::~NetlinkManager() { +} + +int NetlinkManager::start() { + struct sockaddr_nl nladdr; + int sz = 64 * 1024; + + memset(&nladdr, 0, sizeof(nladdr)); + nladdr.nl_family = AF_NETLINK; + nladdr.nl_pid = getpid(); + nladdr.nl_groups = 0xffffffff; + + if ((mSock = socket(PF_NETLINK, + SOCK_DGRAM,NETLINK_KOBJECT_UEVENT)) < 0) { + LOGE("Unable to create uevent socket: %s", strerror(errno)); + return -1; + } + + if (setsockopt(mSock, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz)) < 0) { + LOGE("Unable to set uevent socket options: %s", strerror(errno)); + return -1; + } + + if (bind(mSock, (struct sockaddr *) &nladdr, sizeof(nladdr)) < 0) { + LOGE("Unable to bind uevent socket: %s", strerror(errno)); + return -1; + } + + mHandler = new NetlinkHandler(mSock); + if (mHandler->start()) { + LOGE("Unable to start NetlinkHandler: %s", strerror(errno)); + return -1; + } + return 0; +} + +int NetlinkManager::stop() { + if (mHandler->stop()) { + LOGE("Unable to stop NetlinkHandler: %s", strerror(errno)); + return -1; + } + delete mHandler; + mHandler = NULL; + + close(mSock); + mSock = -1; + + return 0; +} diff --git a/NetlinkManager.h b/NetlinkManager.h new file mode 100644 index 0000000..9c7ba11 --- /dev/null +++ b/NetlinkManager.h @@ -0,0 +1,48 @@ +/* + * 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 _NETLINKMANAGER_H +#define _NETLINKMANAGER_H + +#include <sysutils/SocketListener.h> +#include <sysutils/NetlinkListener.h> + +class NetlinkHandler; + +class NetlinkManager { +private: + static NetlinkManager *sInstance; + +private: + SocketListener *mBroadcaster; + NetlinkHandler *mHandler; + int mSock; + +public: + virtual ~NetlinkManager(); + + int start(); + int stop(); + + void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; } + SocketListener *getBroadcaster() { return mBroadcaster; } + + static NetlinkManager *Instance(); + +private: + NetlinkManager(); +}; +#endif diff --git a/VoldCommand.cpp b/VoldCommand.cpp new file mode 100644 index 0000000..3c0d58d --- /dev/null +++ b/VoldCommand.cpp @@ -0,0 +1,21 @@ +/* + * 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 "VoldCommand.h" + +VoldCommand::VoldCommand(const char *cmd) : + FrameworkCommand(cmd) { +} diff --git a/VoldCommand.h b/VoldCommand.h new file mode 100644 index 0000000..5ddc666 --- /dev/null +++ b/VoldCommand.h @@ -0,0 +1,28 @@ +/* + * 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 _VOLD_COMMAND_H +#define _VOLD_COMMAND_H + +#include <sysutils/FrameworkCommand.h> + +class VoldCommand : public FrameworkCommand { +public: + VoldCommand(const char *cmd); + virtual ~VoldCommand() {} +}; + +#endif diff --git a/Volume.cpp b/Volume.cpp new file mode 100644 index 0000000..aaccb2b --- /dev/null +++ b/Volume.cpp @@ -0,0 +1,46 @@ +/* + * 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 <stdio.h> +#include <errno.h> +#include <string.h> + +#define LOG_TAG "Vold" + +#include <cutils/log.h> + +#include "Volume.h" + +Volume::Volume(const char *label, const char *mount_point) { + mLabel = strdup(label); + mMountpoint = strdup(mount_point); + mState = Volume::State_Init; +} + +Volume::~Volume() { + free(mLabel); + free(mMountpoint); +} + +int Volume::handleDiskInsertion(const char *dp, int maj, int min, int nr_parts) { + errno = ENOSYS; + return -1; +} + +void Volume::setState(int state) { + LOGD("Volume %s state changing %d -> %d", mLabel, mState, state); + mState = state; +} diff --git a/Volume.h b/Volume.h new file mode 100644 index 0000000..bf2a799 --- /dev/null +++ b/Volume.h @@ -0,0 +1,54 @@ +/* + * 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 _VOLUME_H +#define _VOLUME_H + +#include <utils/List.h> + +class Volume { +private: + int mState; + +public: + static const int State_Init = -1; + static const int State_Idle = 1; + static const int State_Pending = 2; + static const int State_Mounted = 3; + static const int State_Checking = 4; + static const int State_Formatting = 5; + +protected: + char *mLabel; + char *mMountpoint; + +public: + Volume(const char *label, const char *mount_point); + virtual ~Volume(); + + const char *getLabel() { return mLabel; } + const char *getMountpoint() { return mMountpoint; } + int getState() { return mState; } + + virtual int handleDiskInsertion(const char *dp, int maj, int min, int nr_parts); + +protected: + void setState(int state); +}; + +typedef android::List<Volume *> VolumeCollection; + +#endif diff --git a/VolumeManager.cpp b/VolumeManager.cpp new file mode 100644 index 0000000..ffe4e22 --- /dev/null +++ b/VolumeManager.cpp @@ -0,0 +1,103 @@ +/* + * 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 <stdio.h> +#include <errno.h> + +#define LOG_TAG "Vold" + +#include <cutils/log.h> + +#include "VolumeManager.h" +#include "DeviceVolume.h" +#include "ErrorCode.h" + +VolumeManager *VolumeManager::sInstance = NULL; + +VolumeManager *VolumeManager::Instance() { + if (!sInstance) + sInstance = new VolumeManager(); + return sInstance; +} + +VolumeManager::VolumeManager() { + mBlockDevices = new BlockDeviceCollection(); + mVolumes = new VolumeCollection(); + mBroadcaster = NULL; +} + +VolumeManager::~VolumeManager() { + delete mBlockDevices; +} + +int VolumeManager::start() { + return 0; +} + +int VolumeManager::stop() { + return 0; +} + +int VolumeManager::addVolume(Volume *v) { + mVolumes->push_back(v); + return 0; +} + +void VolumeManager::handleDiskInserted(const char *devpath, int maj, int min, + int nr_parts) { + + /* Lookup possible candidate DeviceVolumes */ + VolumeCollection::iterator it; + bool hit = false; + for (it = mVolumes->begin(); it != mVolumes->end(); ++it) { + if (!(*it)->handleDiskInsertion(devpath, maj, min, nr_parts)) { + hit = true; + LOGD("Volume '%s' has handled disk insertion for '%s'", + (*it)->getLabel(), devpath); + break; + } + } + + if (!hit) { + LOGW("No volumes handled insertion of disk '%s'", devpath); + } +} + +void VolumeManager::handleDiskRemoved(int maj, int min) { +} + +void VolumeManager::handlePartCreated(const char *devpath, int maj, int min, + int part_no) { +} + +void VolumeManager::handlePartRemoved(int maj, int min) { +} + + +int VolumeManager::listVolumes(SocketClient *cli) { + VolumeCollection::iterator i; + + for (i = mVolumes->begin(); i != mVolumes->end(); ++i) { + char *buffer; + asprintf(&buffer, "%s %s %d", + (*i)->getLabel(), (*i)->getMountpoint(), + (*i)->getState()); + cli->sendMsg(ErrorCode::VolumeListResult, buffer, false); + free(buffer); + } + cli->sendMsg(ErrorCode::CommandOkay, "Volumes Listed", false); + return 0; +} diff --git a/VolumeManager.h b/VolumeManager.h new file mode 100644 index 0000000..8263805 --- /dev/null +++ b/VolumeManager.h @@ -0,0 +1,64 @@ +/* + * 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 _VOLUMEMANAGER_H +#define _VOLUMEMANAGER_H + +#include <pthread.h> + +#include <utils/List.h> +#include <sysutils/SocketListener.h> + +#include "BlockDevice.h" +#include "Volume.h" + +class VolumeManager { +private: + static VolumeManager *sInstance; + +private: + SocketListener *mBroadcaster; + BlockDeviceCollection *mBlockDevices; + + VolumeCollection *mVolumes; + +public: + virtual ~VolumeManager(); + + int start(); + int stop(); + + void handleDiskInserted(const char *devpath, int maj, int min, + int nr_parts); + void handleDiskRemoved(int maj, int min); + + void handlePartCreated(const char *devpath, int maj, int min, + int part_no); + void handlePartRemoved(int maj, int min); + + int addVolume(Volume *v); + + int listVolumes(SocketClient *cli); + + void setBroadcaster(SocketListener *sl) { mBroadcaster = sl; } + SocketListener *getBroadcaster() { return mBroadcaster; } + + static VolumeManager *Instance(); + +private: + VolumeManager(); +}; +#endif diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..1ccd147 --- /dev/null +++ b/main.cpp @@ -0,0 +1,159 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> + +#define LOG_TAG "Vold" + +#include "cutils/log.h" + +#include "VolumeManager.h" +#include "CommandListener.h" +#include "NetlinkManager.h" +#include "DeviceVolume.h" + +static int process_config(VolumeManager *vm); + +int main() { + + VolumeManager *vm; + CommandListener *cl; + NetlinkManager *nm; + + LOGI("Vold 2.0 firing up"); + + /* Create our singleton managers */ + if (!(vm = VolumeManager::Instance())) { + LOGE("Unable to create VolumeManager"); + exit(1); + }; + + if (!(nm = NetlinkManager::Instance())) { + LOGE("Unable to create NetlinkManager"); + exit(1); + }; + + cl = new CommandListener(); + vm->setBroadcaster((SocketListener *) cl); + nm->setBroadcaster((SocketListener *) cl); + + if (vm->start()) { + LOGE("Unable to start VolumeManager (%s)", strerror(errno)); + exit(1); + } + + if (process_config(vm)) { + LOGE("Error reading configuration (%s)", strerror(errno)); + exit(1); + } + + if (nm->start()) { + LOGE("Unable to start NetlinkManager (%s)", strerror(errno)); + exit(1); + } + + /* + * Now that we're up, we can respond to commands + */ + if (cl->startListener()) { + LOGE("Unable to start CommandListener (%s)", strerror(errno)); + exit(1); + } + + // Eventually we'll become the monitoring thread + while(1) { + sleep(1000); + } + + LOGI("Vold exiting"); + exit(0); +} + +static int process_config(VolumeManager *vm) { + FILE *fp; + int n = 0; + char line[255]; + + if (!(fp = fopen("/etc/vold.fstab", "r"))) { + return -1; + } + + while(fgets(line, sizeof(line), fp)) { + char *next = line; + char *type, *label, *mount_point; + + n++; + line[strlen(line)-1] = '\0'; + + if (line[0] == '#' || line[0] == '\0') + continue; + + if (!(type = strsep(&next, " \t"))) { + LOGE("Error parsing type"); + goto out_syntax; + } + if (!(label = strsep(&next, " \t"))) { + LOGE("Error parsing label"); + goto out_syntax; + } + if (!(mount_point = strsep(&next, " \t"))) { + LOGE("Error parsing mount point"); + goto out_syntax; + } + + if (!strcmp(type, "dev_mount")) { + DeviceVolume *dv = NULL; + char *part, *sysfs_path; + + if (!(part = strsep(&next, " \t"))) { + LOGE("Error parsing partition"); + goto out_syntax; + } + if (strcmp(part, "auto") && atoi(part) == 0) { + LOGE("Partition must either be 'auto' or 1 based index instead of '%s'", part); + goto out_syntax; + } + + dv = new DeviceVolume(label, mount_point, atoi(part)); + + while((sysfs_path = strsep(&next, " \t"))) { + if (dv->addPath(sysfs_path)) { + LOGE("Failed to add devpath %s to volume %s", sysfs_path, + label); + goto out_fail; + } + } + vm->addVolume(dv); + } else if (!strcmp(type, "map_mount")) { + } else { + LOGE("Unknown type '%s'", type); + goto out_syntax; + } + } + + fclose(fp); + return 0; + +out_syntax: + LOGE("Syntax error on config line %d", n); + errno = -EINVAL; +out_fail: + fclose(fp); + return -1; +} @@ -0,0 +1,148 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <signal.h> +#include <errno.h> +#include <fcntl.h> + +#include <sys/socket.h> +#include <sys/select.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/un.h> + +#include <cutils/sockets.h> +#include <private/android_filesystem_config.h> + +static void usage(char *progname); +static int do_monitor(int sock, int stop_after_cmd); +static int do_cmd(int sock, int argc, char **argv); + +int main(int argc, char **argv) { + int sock; + + if (argc < 2) + usage(argv[0]); + + if ((sock = socket_local_client("vold", + ANDROID_SOCKET_NAMESPACE_RESERVED, + SOCK_STREAM)) < 0) { + fprintf(stderr, "Error connecting (%s)\n", strerror(errno)); + exit(4); + } + + if (!strcmp(argv[1], "monitor")) + exit(do_monitor(sock, 0)); + exit(do_cmd(sock, argc, argv)); +} + +static int do_cmd(int sock, int argc, char **argv) { + char final_cmd[255] = { '\0' }; + int i; + + for (i = 1; i < argc; i++) { + char *cmp; + + if (!index(argv[i], ' ')) + asprintf(&cmp, "%s%s", argv[i], (i == (argc -1)) ? "" : " "); + else + asprintf(&cmp, "\"%s\"%s", argv[i], (i == (argc -1)) ? "" : " "); + + strcat(final_cmd, cmp); + free(cmp); + } + + if (write(sock, final_cmd, strlen(final_cmd) + 1) < 0) { + perror("write"); + return errno; + } + + return do_monitor(sock, 1); +} + +static int do_monitor(int sock, int stop_after_cmd) { + char *buffer = malloc(4096); + + if (!stop_after_cmd) + printf("[Connected to Vold]\n"); + + while(1) { + fd_set read_fds; + struct timeval to; + int rc = 0; + + to.tv_sec = 10; + to.tv_usec = 0; + + FD_ZERO(&read_fds); + FD_SET(sock, &read_fds); + + if ((rc = select(sock +1, &read_fds, NULL, NULL, &to)) < 0) { + fprintf(stderr, "Error in select (%s)\n", strerror(errno)); + free(buffer); + return errno; + } else if (!rc) { + continue; + fprintf(stderr, "[TIMEOUT]\n"); + return ETIMEDOUT; + } else if (FD_ISSET(sock, &read_fds)) { + memset(buffer, 0, 4096); + if ((rc = read(sock, buffer, 4096)) <= 0) { + if (rc == 0) + fprintf(stderr, "Lost connection to Vold - did it crash?\n"); + else + fprintf(stderr, "Error reading data (%s)\n", strerror(errno)); + free(buffer); + if (rc == 0) + return ECONNRESET; + return errno; + } + + int offset = 0; + int i = 0; + + for (i = 0; i < rc; i++) { + if (buffer[i] == '\0') { + int code; + char tmp[4]; + + strncpy(tmp, buffer + offset, 3); + tmp[3] = '\0'; + code = atoi(tmp); + + printf("%s\n", buffer + offset); + if (stop_after_cmd) { + if (code >= 200 && code < 600) + return 0; + } + offset = i + 1; + } + } + } + } + free(buffer); + return 0; +} + +static void usage(char *progname) { + fprintf(stderr, "Usage: %s <monitor>|<cmd> [arg1] [arg2...]\n", progname); + exit(1); +} + |