--- /dev/null
+BUILD_NETD := false
+ifneq ($(TARGET_SIMULATOR),true)
+ BUILD_NETD := true
+endif
+
+ifeq ($(BUILD_NETD),true)
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ main.cpp \
+ CommandListener.cpp \
+ NetdCommand.cpp \
+ NetlinkManager.cpp \
+ NetlinkHandler.cpp \
+ logwrapper.c
+
+LOCAL_MODULE:= netd
+
+LOCAL_C_INCLUDES := $(KERNEL_HEADERS) -I../../frameworks/base/include/
+
+LOCAL_CFLAGS :=
+
+LOCAL_SHARED_LIBRARIES := libsysutils libcutils
+
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= \
+ ndc.c \
+
+LOCAL_MODULE:= ndc
+
+LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
+
+LOCAL_CFLAGS :=
+
+LOCAL_SHARED_LIBRARIES := libcutils
+
+include $(BUILD_EXECUTABLE)
+
+endif # ifeq ($(BUILD_NETD,true)
--- /dev/null
+/*
+ * 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 <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <errno.h>
+
+#define LOG_TAG "CommandListener"
+#include <cutils/log.h>
+
+#include <sysutils/SocketClient.h>
+
+#include "CommandListener.h"
+#include "ResponseCode.h"
+
+CommandListener::CommandListener() :
+ FrameworkListener("netd") {
+ registerCmd(new ListInterfacesCmd());
+ registerCmd(new IpFwdCmd());
+ registerCmd(new TetherCmd());
+ registerCmd(new NatCmd());
+}
+
+CommandListener::ListInterfacesCmd::ListInterfacesCmd() :
+ NetdCommand("list_interfaces") {
+}
+
+int CommandListener::ListInterfacesCmd::runCommand(SocketClient *cli,
+ int argc, char **argv) {
+ cli->sendMsg(ResponseCode::CommandOkay, "Interfaces listed.", false);
+ return 0;
+}
+
+CommandListener::IpFwdCmd::IpFwdCmd() :
+ NetdCommand("ipfwd") {
+}
+
+int CommandListener::IpFwdCmd::runCommand(SocketClient *cli,
+ int argc, char **argv) {
+
+ return 0;
+}
+
+CommandListener::TetherCmd::TetherCmd() :
+ NetdCommand("tether") {
+}
+
+int CommandListener::TetherCmd::runCommand(SocketClient *cli,
+ int argc, char **argv) {
+ if (argc < 2) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
+ return 0;
+ }
+
+ if (!strcmp(argv[1], "start")) {
+ } else if (!strcmp(argv[1], "stop")) {
+ } else if (!strcmp(argv[1], "status")) {
+ } else if (!strcmp(argv[1], "interface")) {
+ } else if (!strcmp(argv[1], "dns")) {
+ } else {
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown tether cmd", false);
+ return 0;
+ }
+
+ return 0;
+}
+
+CommandListener::NatCmd::NatCmd() :
+ NetdCommand("nat") {
+}
+
+int CommandListener::NatCmd::runCommand(SocketClient *cli,
+ int argc, char **argv) {
+
+ return 0;
+}
+
--- /dev/null
+/*
+ * 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 "NetdCommand.h"
+
+class CommandListener : public FrameworkListener {
+public:
+ CommandListener();
+ virtual ~CommandListener() {}
+
+private:
+
+ class ListInterfacesCmd : public NetdCommand {
+ public:
+ ListInterfacesCmd();
+ virtual ~ListInterfacesCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
+
+ class IpFwdCmd : public NetdCommand {
+ public:
+ IpFwdCmd();
+ virtual ~IpFwdCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
+
+ class TetherCmd : public NetdCommand {
+ public:
+ TetherCmd();
+ virtual ~TetherCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
+
+ class NatCmd : public NetdCommand {
+ public:
+ NatCmd();
+ virtual ~NatCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
+};
+
+#endif
--- /dev/null
+/*
+ * 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 "NetdCommand.h"
+
+NetdCommand::NetdCommand(const char *cmd) :
+ FrameworkCommand(cmd) {
+}
--- /dev/null
+/*
+ * 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 _NETD_COMMAND_H
+#define _NETD_COMMAND_H
+
+#include <sysutils/FrameworkCommand.h>
+
+class NetdCommand : public FrameworkCommand {
+public:
+ NetdCommand(const char *cmd);
+ virtual ~NetdCommand() {}
+};
+
+#endif
--- /dev/null
+/*
+ * 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 "Netd"
+
+#include <cutils/log.h>
+
+#include <sysutils/NetlinkEvent.h>
+#include "NetlinkHandler.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) {
+ const char *subsys = evt->getSubsystem();
+
+ if (!subsys) {
+ LOGW("No subsystem found in netlink event");
+ return;
+ }
+
+ if (!strcmp(subsys, "block")) {
+ } else if (!strcmp(subsys, "switch")) {
+ } else if (!strcmp(subsys, "battery")) {
+ } else if (!strcmp(subsys, "power_supply")) {
+ } else {
+ LOGE("Dropping %s netlink event", subsys);
+ }
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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 "Netd"
+
+#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;
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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 _RESPONSECODE_H
+#define _RESPONSECODE_H
+
+class ResponseCode {
+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;
+ static const int AsecListResult = 111;
+
+ // 200 series - Requested action has been successfully completed
+ static const int CommandOkay = 200;
+ static const int ShareAvailabilityResult = 210;
+ static const int AsecPathResult = 211;
+
+ // 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;
+ static const int VolumeStateChange = 605;
+ static const int VolumeMountFailedBlank = 610;
+ static const int VolumeMountFailedDamaged = 611;
+ static const int VolumeMountFailedNoMedia = 612;
+
+ static const int ShareAvailabilityChange = 620;
+
+ static const int VolumeDiskInserted = 630;
+ static const int VolumeDiskRemoved = 631;
+ static const int VolumeBadRemoval = 632;
+};
+#endif
--- /dev/null
+/*
+ * 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, "%s", &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, const 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 (execv(argv_child[0], argv_child)) {
+ LOG(LOG_ERROR, "logwrapper",
+ "executing %s failed: %s", argv_child[0], strerror(errno));
+ exit(-1);
+ }
+}
+
+int logwrap(int argc, const char* argv[], int background)
+{
+ 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");
+ return -errno;
+ }
+
+ if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
+ ((child_devname = (char*)ptsname(parent_ptty)) == 0)) {
+ LOG(LOG_ERROR, "logwrapper", "Problem with /dev/ptmx");
+ return -1;
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ LOG(LOG_ERROR, "logwrapper", "Failed to fork");
+ 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");
+ return -errno;
+ }
+
+ // redirect stdout and stderr
+ close(parent_ptty);
+ dup2(child_ptty, 1);
+ dup2(child_ptty, 2);
+ close(child_ptty);
+
+ if (background) {
+ int fd = open("/dev/cpuctl/bg_non_interactive/tasks", O_WRONLY);
+
+ if (fd >=0 ) {
+ char text[64];
+
+ sprintf(text, "%d", getpid());
+ if (write(fd, text, strlen(text)) < 0) {
+ LOG(LOG_WARN, "logwrapper",
+ "Unable to background process (%s)", strerror(errno));
+ close(fd);
+ }
+ close(fd);
+ } else {
+ LOG(LOG_WARN, "logwrapper",
+ "Unable to background process (%s)", strerror(errno));
+ }
+ }
+
+ child(argc, argv);
+ } else {
+ return parent(argv[0], parent_ptty);
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * 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>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <fcntl.h>
+#include <dirent.h>
+
+#define LOG_TAG "Netd"
+
+#include "cutils/log.h"
+
+#include "CommandListener.h"
+#include "NetlinkManager.h"
+
+static void coldboot(const char *path);
+
+int main() {
+
+ CommandListener *cl;
+ NetlinkManager *nm;
+
+ LOGI("Netd 1.0 starting");
+
+ if (!(nm = NetlinkManager::Instance())) {
+ LOGE("Unable to create NetlinkManager");
+ exit(1);
+ };
+
+
+ cl = new CommandListener();
+ nm->setBroadcaster((SocketListener *) cl);
+
+ 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("Netd exiting");
+ exit(0);
+}
+
+static void do_coldboot(DIR *d, int lvl)
+{
+ struct dirent *de;
+ int dfd, fd;
+
+ dfd = dirfd(d);
+
+ fd = openat(dfd, "uevent", O_WRONLY);
+ if(fd >= 0) {
+ write(fd, "add\n", 4);
+ close(fd);
+ }
+
+ while((de = readdir(d))) {
+ DIR *d2;
+
+ if (de->d_name[0] == '.')
+ continue;
+
+ if (de->d_type != DT_DIR && lvl > 0)
+ continue;
+
+ fd = openat(dfd, de->d_name, O_RDONLY | O_DIRECTORY);
+ if(fd < 0)
+ continue;
+
+ d2 = fdopendir(fd);
+ if(d2 == 0)
+ close(fd);
+ else {
+ do_coldboot(d2, lvl + 1);
+ closedir(d2);
+ }
+ }
+}
+
+static void coldboot(const char *path)
+{
+ DIR *d = opendir(path);
+ if(d) {
+ do_coldboot(d, 0);
+ closedir(d);
+ }
+}
--- /dev/null
+/*
+ * 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 Netd]\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);
+}
+