summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSan Mehat <san@google.com>2010-02-16 17:12:00 -0800
committerSan Mehat <san@google.com>2010-02-16 17:12:00 -0800
commit586536c60b773e3517531ad8a6cb0de6722c67fc (patch)
treeafd0ab67daf64d18ef7bfca282d82e14d74d2f09
parent8c940ef7dbd423cadc92982b44a65ed1014389e2 (diff)
downloadsystem_vold-586536c60b773e3517531ad8a6cb0de6722c67fc.tar.gz
system_vold-586536c60b773e3517531ad8a6cb0de6722c67fc.tar.bz2
system_vold-586536c60b773e3517531ad8a6cb0de6722c67fc.zip
vold: Refactor Processkiller and add command to return users of a mount point
Signed-off-by: San Mehat <san@google.com>
-rw-r--r--Android.mk2
-rw-r--r--CommandListener.cpp51
-rw-r--r--CommandListener.h6
-rw-r--r--Process.cpp221
-rw-r--r--Process.h35
-rw-r--r--ProcessKiller.c222
-rw-r--r--ResponseCode.h5
-rw-r--r--Volume.cpp4
-rw-r--r--VolumeManager.cpp5
9 files changed, 321 insertions, 230 deletions
diff --git a/Android.mk b/Android.mk
index d90b399..9036f78 100644
--- a/Android.mk
+++ b/Android.mk
@@ -20,7 +20,7 @@ LOCAL_SRC_FILES:= \
Volume.cpp \
DirectVolume.cpp \
logwrapper.c \
- ProcessKiller.c \
+ Process.cpp \
geom_mbr_enc.c \
Fat.cpp \
Loop.cpp \
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 59c431f..b25728f 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -30,12 +30,14 @@
#include "CommandListener.h"
#include "VolumeManager.h"
#include "ResponseCode.h"
+#include "Process.h"
CommandListener::CommandListener() :
FrameworkListener("vold") {
registerCmd(new VolumeCmd());
registerCmd(new AsecCmd());
registerCmd(new ShareCmd());
+ registerCmd(new StorageCmd());
}
CommandListener::VolumeCmd::VolumeCmd() :
@@ -134,6 +136,55 @@ int CommandListener::ShareCmd::runCommand(SocketClient *cli,
return 0;
}
+CommandListener::StorageCmd::StorageCmd() :
+ VoldCommand("storage") {
+}
+
+int CommandListener::StorageCmd::runCommand(SocketClient *cli,
+ int argc, char **argv) {
+ if (argc < 2) {
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
+ return 0;
+ }
+
+ if (!strcmp(argv[1], "users")) {
+ DIR *dir;
+ struct dirent *de;
+
+ if (!(dir = opendir("/proc"))) {
+ cli->sendMsg(ResponseCode::OperationFailed, "Failed to open /proc", true);
+ return 0;
+ }
+
+ while ((de = readdir(dir))) {
+ int pid = Process::getPid(de->d_name);
+
+ if (pid < 0) {
+ continue;
+ }
+
+ char processName[255];
+ Process::getProcessName(pid, processName, sizeof(processName));
+
+ if (Process::checkFileDescriptorSymLinks(pid, argv[2]) ||
+ Process::checkFileMaps(pid, argv[2]) ||
+ Process::checkSymLink(pid, argv[2], "cwd") ||
+ Process::checkSymLink(pid, argv[2], "root") ||
+ Process::checkSymLink(pid, argv[2], "exe")) {
+
+ char msg[1024];
+ snprintf(msg, sizeof(msg), "%d %s", pid, processName);
+ cli->sendMsg(ResponseCode::StorageUsersListResult, msg, false);
+ }
+ }
+ closedir(dir);
+ cli->sendMsg(ResponseCode::CommandOkay, "Storage user list complete", false);
+ } else {
+ cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown storage cmd", false);
+ }
+ return 0;
+}
+
CommandListener::AsecCmd::AsecCmd() :
VoldCommand("asec") {
}
diff --git a/CommandListener.h b/CommandListener.h
index e6fa805..7d4560f 100644
--- a/CommandListener.h
+++ b/CommandListener.h
@@ -48,6 +48,12 @@ private:
int runCommand(SocketClient *c, int argc, char ** argv);
};
+ class StorageCmd : public VoldCommand {
+ public:
+ StorageCmd();
+ virtual ~StorageCmd() {}
+ int runCommand(SocketClient *c, int argc, char ** argv);
+ };
};
#endif
diff --git a/Process.cpp b/Process.cpp
new file mode 100644
index 0000000..c3c9904
--- /dev/null
+++ b/Process.cpp
@@ -0,0 +1,221 @@
+/*
+ * 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 <unistd.h>
+#include <errno.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>
+#include <signal.h>
+
+#define LOG_TAG "ProcessKiller"
+#include <cutils/log.h>
+
+#include "Process.h"
+
+int Process::readSymLink(const char *path, char *link, size_t max) {
+ struct stat s;
+ int length;
+
+ if (lstat(path, &s) < 0)
+ return 0;
+ if ((s.st_mode & S_IFMT) != S_IFLNK)
+ return 0;
+
+ // we have a symlink
+ length = readlink(path, link, max- 1);
+ if (length <= 0)
+ return 0;
+ link[length] = 0;
+ return 1;
+}
+
+int Process::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 1;
+ // 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 0;
+}
+
+void Process::getProcessName(int pid, char *buffer, size_t max) {
+ int fd;
+ snprintf(buffer, max, "/proc/%d/cmdline", pid);
+ fd = open(buffer, O_RDONLY);
+ if (fd < 0) {
+ strcpy(buffer, "???");
+ } else {
+ int length = read(fd, buffer, max - 1);
+ buffer[length] = 0;
+ close(fd);
+ }
+}
+
+int Process::checkFileDescriptorSymLinks(int pid, const char *mountPoint) {
+ return checkFileDescriptorSymLinks(pid, mountPoint, NULL, 0);
+}
+
+int Process::checkFileDescriptorSymLinks(int pid, const char *mountPoint, char *openFilename, size_t max) {
+
+
+ // compute path to process's directory of open files
+ char path[PATH_MAX];
+ sprintf(path, "/proc/%d/fd", pid);
+ DIR *dir = opendir(path);
+ if (!dir)
+ return 0;
+
+ // remember length of the path
+ int parent_length = strlen(path);
+ // append a trailing '/'
+ path[parent_length++] = '/';
+
+ struct dirent* de;
+ while ((de = readdir(dir))) {
+ 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);
+
+ char link[PATH_MAX];
+
+ if (readSymLink(path, link, sizeof(link)) && pathMatchesMountPoint(link, mountPoint)) {
+ if (openFilename) {
+ memset(openFilename, 0, max);
+ strncpy(openFilename, link, max-1);
+ }
+ closedir(dir);
+ return 1;
+ }
+ }
+
+ closedir(dir);
+ return 0;
+}
+
+int Process::checkFileMaps(int pid, const char *mountPoint) {
+ return checkFileMaps(pid, mountPoint, NULL, 0);
+}
+
+int Process::checkFileMaps(int pid, const char *mountPoint, char *openFilename, size_t max) {
+ FILE *file;
+ char buffer[PATH_MAX + 100];
+
+ sprintf(buffer, "/proc/%d/maps", pid);
+ file = fopen(buffer, "r");
+ if (!file)
+ return 0;
+
+ while (fgets(buffer, sizeof(buffer), file)) {
+ // skip to the path
+ const char* path = strchr(buffer, '/');
+ if (path && pathMatchesMountPoint(path, mountPoint)) {
+ if (openFilename) {
+ memset(openFilename, 0, max);
+ strncpy(openFilename, path, max-1);
+ }
+ fclose(file);
+ return 1;
+ }
+ }
+
+ fclose(file);
+ return 0;
+}
+
+int Process::checkSymLink(int pid, const char *mountPoint, const char *name) {
+ char path[PATH_MAX];
+ char link[PATH_MAX];
+
+ sprintf(path, "/proc/%d/%s", pid, name);
+ if (readSymLink(path, link, sizeof(link)) && pathMatchesMountPoint(link, mountPoint))
+ return 1;
+ return 0;
+}
+
+int Process::getPid(const char *s) {
+ int result = 0;
+ while (*s) {
+ if (!isdigit(*s)) return -1;
+ result = 10 * result + (*s++ - '0');
+ }
+ return result;
+}
+
+/*
+ * Hunt down processes that have files open at the given mount point.
+ * action = 0 to just warn,
+ * action = 1 to SIGHUP,
+ * action = 2 to SIGKILL
+ */
+// hunt down and kill processes that have files open on the given mount point
+void Process::killProcessesWithOpenFiles(const char *path, int action) {
+ DIR* dir;
+ struct dirent* de;
+
+ if (!(dir = opendir("/proc"))) {
+ LOGE("opendir failed (%s)", strerror(errno));
+ return;
+ }
+
+ while ((de = readdir(dir))) {
+ int killed = 0;
+ int pid = getPid(de->d_name);
+ char name[PATH_MAX];
+
+ if (pid == -1)
+ continue;
+ getProcessName(pid, name, sizeof(name));
+
+ char openfile[PATH_MAX];
+
+ if (checkFileDescriptorSymLinks(pid, path, openfile, sizeof(openfile))) {
+ LOGE("Process %s (%d) has open file %s", name, pid, openfile);
+ } else if (checkFileMaps(pid, path, openfile, sizeof(openfile))) {
+ LOGE("Process %s (%d) has open filemap for %s", name, pid, openfile);
+ } else if (checkSymLink(pid, path, "cwd")) {
+ LOGE("Process %s (%d) has cwd within %s", name, pid, path);
+ } else if (checkSymLink(pid, path, "root")) {
+ LOGE("Process %s (%d) has chroot within %s", name, pid, path);
+ } else if (checkSymLink(pid, path, "exe")) {
+ LOGE("Process %s (%d) has executable path within %s", name, pid, path);
+ } else {
+ continue;
+ }
+ if (action == 1) {
+ LOGW("Sending SIGHUP to process %d", pid);
+ kill(pid, SIGTERM);
+ } else if (action == 2) {
+ LOGE("Sending SIGKILL to process %d", pid);
+ kill(pid, SIGKILL);
+ }
+ }
+ closedir(dir);
+}
diff --git a/Process.h b/Process.h
new file mode 100644
index 0000000..fc0c0b7
--- /dev/null
+++ b/Process.h
@@ -0,0 +1,35 @@
+/*
+ * 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 _PROCESS_H
+#define _PROCESS_H
+
+class Process {
+public:
+ static void killProcessesWithOpenFiles(const char *path, int action);
+ static int getPid(const char *s);
+ static int checkSymLink(int pid, const char *path, const char *name);
+ static int checkFileMaps(int pid, const char *path);
+ static int checkFileMaps(int pid, const char *path, char *openFilename, size_t max);
+ static int checkFileDescriptorSymLinks(int pid, const char *mountPoint);
+ static int checkFileDescriptorSymLinks(int pid, const char *mountPoint, char *openFilename, size_t max);
+ static void getProcessName(int pid, char *buffer, size_t max);
+private:
+ static int readSymLink(const char *path, char *link, size_t max);
+ static int pathMatchesMountPoint(const char *path, const char *mountPoint);
+};
+
+#endif
diff --git a/ProcessKiller.c b/ProcessKiller.c
deleted file mode 100644
index 7375ef3..0000000
--- a/ProcessKiller.c
+++ /dev/null
@@ -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 <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>
-#include <signal.h>
-
-#define LOG_TAG "ProcessKiller"
-#include <cutils/log.h>
-
-#define PATH_MAX 4096
-
-static int ReadSymLink(const char* path, char* link)
-{
- struct stat s;
- int length;
-
- if (lstat(path, &s) < 0)
- return 0;
- if ((s.st_mode & S_IFMT) != S_IFLNK)
- return 0;
-
- // we have a symlink
- length = readlink(path, link, PATH_MAX - 1);
- if (length <= 0)
- return 0;
- link[length] = 0;
- return 1;
-}
-
-static int 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 1;
- // 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 0;
-}
-
-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 int CheckFileDescriptorSymLinks(int pid, const char* mountPoint)
-{
- DIR* dir;
- struct dirent* de;
- int fileOpen = 0;
- 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 0;
-
- // 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);
- LOGE("Process %s (%d) has open file %s", name, pid, link);
- fileOpen = 1;
- }
- }
-
- closedir(dir);
- return fileOpen;
-}
-
-static int CheckFileMaps(int pid, const char* mountPoint)
-{
- FILE* file;
- char buffer[PATH_MAX + 100];
- int mapOpen = 0;
-
- sprintf(buffer, "/proc/%d/maps", pid);
- file = fopen(buffer, "r");
- if (!file)
- return 0;
-
- 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);
- LOGE("process %s (%d) has open file map for %s", name, pid, path);
- mapOpen = 1;
- }
- }
-
- fclose(file);
- return mapOpen;
-}
-
-static int 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);
- LOGW("Process %s (%d) has %s in %s", name, pid, message, mountPoint);
- return 1;
- }
- else
- return 0;
-}
-
-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 processes that have files open at the given mount point.
- * action = 0 to just warn,
- * action = 1 to SIGHUP,
- * action = 2 to SIGKILL
- */
-// hunt down and kill processes that have files open on the given mount point
-void KillProcessesWithOpenFiles(const char* mountPoint, int action)
-{
- DIR* dir;
- struct dirent* de;
-
- dir = opendir("/proc");
- if (!dir) return;
-
- while ((de = readdir(dir)) != 0)
- {
- int killed = 0;
- // 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
- )
- {
- if (action == 1) {
- LOGW("Sending SIGHUP to process %d", pid);
- kill(pid, SIGTERM);
- } else if (action == 2) {
- LOGE("Sending SIGKILL to process %d", pid);
- kill(pid, SIGKILL);
- }
- }
- }
-
- closedir(dir);
-}
diff --git a/ResponseCode.h b/ResponseCode.h
index 9d775f9..3508f81 100644
--- a/ResponseCode.h
+++ b/ResponseCode.h
@@ -23,8 +23,9 @@ public:
// before proceeding with a new command.
static const int ActionInitiated = 100;
- static const int VolumeListResult = 110;
- static const int AsecListResult = 111;
+ static const int VolumeListResult = 110;
+ static const int AsecListResult = 111;
+ static const int StorageUsersListResult = 112;
// 200 series - Requested action has been successfully completed
static const int CommandOkay = 200;
diff --git a/Volume.cpp b/Volume.cpp
index af69bc2..529975a 100644
--- a/Volume.cpp
+++ b/Volume.cpp
@@ -40,8 +40,8 @@
#include "VolumeManager.h"
#include "ResponseCode.h"
#include "Fat.h"
+#include "Process.h"
-extern "C" void KillProcessesWithOpenFiles(const char *, int);
extern "C" void dos_partition_dec(void const *pp, struct dos_partition *d);
extern "C" void dos_partition_enc(void *pp, struct dos_partition *d);
@@ -308,7 +308,7 @@ int Volume::unmountVol() {
} else
action = 0; // just complain
- KillProcessesWithOpenFiles(getMountpoint(), action);
+ Process::killProcessesWithOpenFiles(getMountpoint(), action);
usleep(1000*250);
}
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index d778ce2..b21a36e 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -37,8 +37,7 @@
#include "Loop.h"
#include "Fat.h"
#include "Devmapper.h"
-
-extern "C" void KillProcessesWithOpenFiles(const char *, int);
+#include "Process.h"
VolumeManager *VolumeManager::sInstance = NULL;
@@ -356,7 +355,7 @@ int VolumeManager::unmountAsec(const char *id) {
else
action = 0; // Just complain
- KillProcessesWithOpenFiles(mountPoint, action);
+ Process::killProcessesWithOpenFiles(mountPoint, action);
usleep(1000 * 1000);
}