2 * Copyright (C) 2008 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
30 #define LOG_TAG "ProcessKiller"
31 #include <cutils/log.h>
35 int Process::readSymLink(const char *path, char *link, size_t max) {
39 if (lstat(path, &s) < 0)
41 if ((s.st_mode & S_IFMT) != S_IFLNK)
45 length = readlink(path, link, max- 1);
52 int Process::pathMatchesMountPoint(const char* path, const char* mountPoint) {
53 int length = strlen(mountPoint);
54 if (length > 1 && strncmp(path, mountPoint, length) == 0) {
55 // we need to do extra checking if mountPoint does not end in a '/'
56 if (mountPoint[length - 1] == '/')
58 // if mountPoint does not have a trailing slash, we need to make sure
59 // there is one in the path to avoid partial matches.
60 return (path[length] == 0 || path[length] == '/');
66 void Process::getProcessName(int pid, char *buffer, size_t max) {
68 snprintf(buffer, max, "/proc/%d/cmdline", pid);
69 fd = open(buffer, O_RDONLY | O_CLOEXEC);
71 strcpy(buffer, "???");
73 int length = read(fd, buffer, max - 1);
79 int Process::checkFileDescriptorSymLinks(int pid, const char *mountPoint) {
80 return checkFileDescriptorSymLinks(pid, mountPoint, NULL, 0);
83 int Process::checkFileDescriptorSymLinks(int pid, const char *mountPoint, char *openFilename, size_t max) {
86 // compute path to process's directory of open files
88 sprintf(path, "/proc/%d/fd", pid);
89 DIR *dir = opendir(path);
93 // remember length of the path
94 int parent_length = strlen(path);
95 // append a trailing '/'
96 path[parent_length++] = '/';
99 while ((de = readdir(dir))) {
100 if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")
101 || strlen(de->d_name) + parent_length + 1 >= PATH_MAX)
104 // append the file name, after truncating to parent directory
105 path[parent_length] = 0;
106 strcat(path, de->d_name);
110 if (readSymLink(path, link, sizeof(link)) && pathMatchesMountPoint(link, mountPoint)) {
112 memset(openFilename, 0, max);
113 strlcpy(openFilename, link, max);
124 int Process::checkFileMaps(int pid, const char *mountPoint) {
125 return checkFileMaps(pid, mountPoint, NULL, 0);
128 int Process::checkFileMaps(int pid, const char *mountPoint, char *openFilename, size_t max) {
130 char buffer[PATH_MAX + 100];
132 sprintf(buffer, "/proc/%d/maps", pid);
133 file = fopen(buffer, "r");
137 while (fgets(buffer, sizeof(buffer), file)) {
139 const char* path = strchr(buffer, '/');
140 if (path && pathMatchesMountPoint(path, mountPoint)) {
142 memset(openFilename, 0, max);
143 strlcpy(openFilename, path, max);
154 int Process::checkSymLink(int pid, const char *mountPoint, const char *name) {
158 sprintf(path, "/proc/%d/%s", pid, name);
159 if (readSymLink(path, link, sizeof(link)) && pathMatchesMountPoint(link, mountPoint))
164 int Process::getPid(const char *s) {
167 if (!isdigit(*s)) return -1;
168 result = 10 * result + (*s++ - '0');
173 extern "C" void vold_killProcessesWithOpenFiles(const char *path, int signal) {
174 Process::killProcessesWithOpenFiles(path, signal);
178 * Hunt down processes that have files open at the given mount point.
180 void Process::killProcessesWithOpenFiles(const char *path, int signal) {
184 if (!(dir = opendir("/proc"))) {
185 SLOGE("opendir failed (%s)", strerror(errno));
189 while ((de = readdir(dir))) {
190 int pid = getPid(de->d_name);
195 getProcessName(pid, name, sizeof(name));
197 char openfile[PATH_MAX];
199 if (checkFileDescriptorSymLinks(pid, path, openfile, sizeof(openfile))) {
200 SLOGE("Process %s (%d) has open file %s", name, pid, openfile);
201 } else if (checkFileMaps(pid, path, openfile, sizeof(openfile))) {
202 SLOGE("Process %s (%d) has open filemap for %s", name, pid, openfile);
203 } else if (checkSymLink(pid, path, "cwd")) {
204 SLOGE("Process %s (%d) has cwd within %s", name, pid, path);
205 } else if (checkSymLink(pid, path, "root")) {
206 SLOGE("Process %s (%d) has chroot within %s", name, pid, path);
207 } else if (checkSymLink(pid, path, "exe")) {
208 SLOGE("Process %s (%d) has executable path within %s", name, pid, path);
214 SLOGW("Sending %s to process %d", strsignal(signal), pid);