Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(214)

Side by Side Diff: chrome/browser/renderer_host/render_crash_handler_host_linux.cc

Issue 312002: Move FileDescriptorGetInode() and FindProcessHoldingSocket() into base/linux_... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/linux_util.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/renderer_host/render_crash_handler_host_linux.h" 5 #include "chrome/browser/renderer_host/render_crash_handler_host_linux.h"
6 6
7 #include <dirent.h>
8 #include <stdint.h> 7 #include <stdint.h>
9 #include <string.h> 8 #include <stdlib.h>
10 #include <sys/socket.h> 9 #include <sys/socket.h>
11 #include <sys/types.h> 10 #include <sys/types.h>
12 #include <sys/uio.h>
13 #include <stdlib.h>
14 #include <unistd.h> 11 #include <unistd.h>
15 12
16 #include <string> 13 #include <string>
17 #include <vector> 14 #include <vector>
18 15
19 #include "base/eintr_wrapper.h" 16 #include "base/eintr_wrapper.h"
20 #include "base/file_path.h" 17 #include "base/file_path.h"
21 #include "base/format_macros.h" 18 #include "base/format_macros.h"
19 #include "base/linux_util.h"
22 #include "base/logging.h" 20 #include "base/logging.h"
23 #include "base/message_loop.h" 21 #include "base/message_loop.h"
24 #include "base/path_service.h" 22 #include "base/path_service.h"
25 #include "base/rand_util.h" 23 #include "base/rand_util.h"
26 #include "base/string_util.h" 24 #include "base/string_util.h"
27 #include "breakpad/linux/exception_handler.h" 25 #include "breakpad/linux/exception_handler.h"
28 #include "breakpad/linux/linux_dumper.h" 26 #include "breakpad/linux/linux_dumper.h"
29 #include "breakpad/linux/minidump_writer.h" 27 #include "breakpad/linux/minidump_writer.h"
30 #include "chrome/app/breakpad_linux.h" 28 #include "chrome/app/breakpad_linux.h"
31 #include "chrome/browser/chrome_thread.h" 29 #include "chrome/browser/chrome_thread.h"
32 #include "chrome/common/chrome_paths.h" 30 #include "chrome/common/chrome_paths.h"
33 31
34 // expected prefix of the target of the /proc/self/fd/%d link for a socket
35 static const char kSocketLinkPrefix[] = "socket:[";
36
37 // Parse a symlink in /proc/pid/fd/$x and return the inode number of the
38 // socket.
39 // inode_out: (output) set to the inode number on success
40 // path: e.g. /proc/1234/fd/5 (must be a UNIX domain socket descriptor)
41 // log: if true, log messages about failure details
42 static bool ProcPathGetInode(uint64_t* inode_out, const char* path,
43 bool log = false) {
44 char buf[256];
45 const ssize_t n = readlink(path, buf, sizeof(buf) - 1);
46 if (n == -1) {
47 if (log) {
48 LOG(WARNING) << "Failed to read the inode number for a socket from /proc"
49 "(" << errno << ")";
50 }
51 return false;
52 }
53 buf[n] = 0;
54
55 if (memcmp(kSocketLinkPrefix, buf, sizeof(kSocketLinkPrefix) - 1)) {
56 if (log) {
57 LOG(WARNING) << "The descriptor passed from the crashing process wasn't a"
58 " UNIX domain socket.";
59 }
60 return false;
61 }
62
63 char *endptr;
64 const unsigned long long int inode_ul =
65 strtoull(buf + sizeof(kSocketLinkPrefix) - 1, &endptr, 10);
66 if (*endptr != ']')
67 return false;
68
69 if (inode_ul == ULLONG_MAX) {
70 if (log) {
71 LOG(WARNING) << "Failed to parse a socket's inode number: the number was "
72 "too large. Please report this bug: " << buf;
73 }
74 return false;
75 }
76
77 *inode_out = inode_ul;
78 return true;
79 }
80
81 // Return the inode number for the UNIX domain socket |fd|.
82 static bool FileDescriptorGetInode(uint64_t* inode_out, int fd) {
83 char path[256];
84 if (snprintf(path, sizeof(path), "/proc/self/fd/%d", fd) < 0)
85 return false;
86
87 return ProcPathGetInode(inode_out, path, true);
88 }
89
90 // Find the process which holds the given socket, named by inode number. If
91 // multiple processes hold the socket, this function returns false.
92 static bool FindProcessHoldingSocket(pid_t* pid_out, uint64_t socket_inode) {
93 bool already_found = false;
94
95 DIR* proc = opendir("/proc");
96 if (!proc) {
97 LOG(WARNING) << "Cannot open /proc";
98 return false;
99 }
100
101 std::vector<pid_t> pids;
102
103 struct dirent* dent;
104 while ((dent = readdir(proc))) {
105 char *endptr;
106 const unsigned long int pid_ul = strtoul(dent->d_name, &endptr, 10);
107 if (pid_ul == ULONG_MAX || *endptr)
108 continue;
109 pids.push_back(pid_ul);
110 }
111 closedir(proc);
112
113 for (std::vector<pid_t>::const_iterator
114 i = pids.begin(); i != pids.end(); ++i) {
115 const pid_t current_pid = *i;
116 char buf[256];
117 if (snprintf(buf, sizeof(buf), "/proc/%d/fd", current_pid) < 0)
118 continue;
119 DIR* fd = opendir(buf);
120 if (!fd)
121 continue;
122
123 while ((dent = readdir(fd))) {
124 if (snprintf(buf, sizeof(buf), "/proc/%d/fd/%s", current_pid,
125 dent->d_name) < 0) {
126 continue;
127 }
128
129 uint64_t fd_inode;
130 if (ProcPathGetInode(&fd_inode, buf)) {
131 if (fd_inode == socket_inode) {
132 if (already_found) {
133 closedir(fd);
134 return false;
135 }
136
137 already_found = true;
138 *pid_out = current_pid;
139 break;
140 }
141 }
142 }
143
144 closedir(fd);
145 }
146
147 return already_found;
148 }
149
150 // Since RenderCrashHandlerHostLinux is a singleton, it's only destroyed at the 32 // Since RenderCrashHandlerHostLinux is a singleton, it's only destroyed at the
151 // end of the processes lifetime, which is greater in span then the lifetime of 33 // end of the processes lifetime, which is greater in span then the lifetime of
152 // the IO message loop. 34 // the IO message loop.
153 template<> struct RunnableMethodTraits<RenderCrashHandlerHostLinux> { 35 template<> struct RunnableMethodTraits<RenderCrashHandlerHostLinux> {
154 void RetainCallee(RenderCrashHandlerHostLinux*) { } 36 void RetainCallee(RenderCrashHandlerHostLinux*) { }
155 void ReleaseCallee(RenderCrashHandlerHostLinux*) { } 37 void ReleaseCallee(RenderCrashHandlerHostLinux*) { }
156 }; 38 };
157 39
158 RenderCrashHandlerHostLinux::RenderCrashHandlerHostLinux() 40 RenderCrashHandlerHostLinux::RenderCrashHandlerHostLinux()
159 : renderer_socket_(-1), 41 : renderer_socket_(-1),
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
293 return; 175 return;
294 } 176 }
295 177
296 // Kernel bug workaround (broken in 2.6.30 at least): 178 // Kernel bug workaround (broken in 2.6.30 at least):
297 // The kernel doesn't translate PIDs in SCM_CREDENTIALS across PID 179 // The kernel doesn't translate PIDs in SCM_CREDENTIALS across PID
298 // namespaces. Thus |crashing_pid| might be garbage from our point of view. 180 // namespaces. Thus |crashing_pid| might be garbage from our point of view.
299 // In the future we can remove this workaround, but we have to wait a couple 181 // In the future we can remove this workaround, but we have to wait a couple
300 // of years to be sure that it's worked its way out into the world. 182 // of years to be sure that it's worked its way out into the world.
301 183
302 uint64_t inode_number; 184 uint64_t inode_number;
303 if (!FileDescriptorGetInode(&inode_number, signal_fd)) { 185 if (!base::FileDescriptorGetInode(&inode_number, signal_fd)) {
304 LOG(WARNING) << "Failed to get inode number for passed socket"; 186 LOG(WARNING) << "Failed to get inode number for passed socket";
305 HANDLE_EINTR(close(signal_fd)); 187 HANDLE_EINTR(close(signal_fd));
306 return; 188 return;
307 } 189 }
308 190
309 if (!FindProcessHoldingSocket(&crashing_pid, inode_number - 1)) { 191 if (!base::FindProcessHoldingSocket(&crashing_pid, inode_number - 1)) {
310 LOG(WARNING) << "Failed to find process holding other end of crash reply " 192 LOG(WARNING) << "Failed to find process holding other end of crash reply "
311 "socket"; 193 "socket";
312 HANDLE_EINTR(close(signal_fd)); 194 HANDLE_EINTR(close(signal_fd));
313 return; 195 return;
314 } 196 }
315 197
316 bool upload = true; 198 bool upload = true;
317 FilePath dumps_path("/tmp"); 199 FilePath dumps_path("/tmp");
318 if (getenv("CHROME_HEADLESS")) { 200 if (getenv("CHROME_HEADLESS")) {
319 upload = false; 201 upload = false;
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
354 info.guid_length = strlen(guid); 236 info.guid_length = strlen(guid);
355 info.distro = distro; 237 info.distro = distro;
356 info.distro_length = strlen(distro); 238 info.distro_length = strlen(distro);
357 info.upload = upload; 239 info.upload = upload;
358 HandleCrashDump(info); 240 HandleCrashDump(info);
359 } 241 }
360 242
361 void RenderCrashHandlerHostLinux::WillDestroyCurrentMessageLoop() { 243 void RenderCrashHandlerHostLinux::WillDestroyCurrentMessageLoop() {
362 file_descriptor_watcher_.StopWatchingFileDescriptor(); 244 file_descriptor_watcher_.StopWatchingFileDescriptor();
363 } 245 }
OLDNEW
« no previous file with comments | « base/linux_util.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698