Fix crash on app list start page keyboard navigation with <4 apps.
[chromium-blink-merge.git] / sandbox / linux / services / proc_util.cc
blob13d8842f788b453393f7ca802e2f3c0b6d2110a1
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "sandbox/linux/services/proc_util.h"
7 #include <dirent.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <string.h>
11 #include <sys/stat.h>
12 #include <sys/types.h>
14 #include "base/logging.h"
15 #include "base/memory/scoped_ptr.h"
16 #include "base/posix/eintr_wrapper.h"
17 #include "base/strings/string_number_conversions.h"
19 namespace sandbox {
20 namespace {
22 struct DIRCloser {
23 void operator()(DIR* d) const {
24 DCHECK(d);
25 PCHECK(0 == closedir(d));
29 typedef scoped_ptr<DIR, DIRCloser> ScopedDIR;
31 } // namespace
33 int ProcUtil::CountOpenFds(int proc_fd) {
34 DCHECK_LE(0, proc_fd);
35 int proc_self_fd = HANDLE_EINTR(
36 openat(proc_fd, "self/fd", O_DIRECTORY | O_RDONLY | O_CLOEXEC));
37 PCHECK(0 <= proc_self_fd);
39 // Ownership of proc_self_fd is transferred here, it must not be closed
40 // or modified afterwards except via dir.
41 ScopedDIR dir(fdopendir(proc_self_fd));
42 CHECK(dir);
44 int count = 0;
45 struct dirent e;
46 struct dirent* de;
47 while (!readdir_r(dir.get(), &e, &de) && de) {
48 if (strcmp(e.d_name, ".") == 0 || strcmp(e.d_name, "..") == 0) {
49 continue;
52 int fd_num;
53 CHECK(base::StringToInt(e.d_name, &fd_num));
54 if (fd_num == proc_fd || fd_num == proc_self_fd) {
55 continue;
58 ++count;
60 return count;
63 bool ProcUtil::HasOpenDirectory(int proc_fd) {
64 int proc_self_fd = -1;
65 if (proc_fd >= 0) {
66 proc_self_fd = openat(proc_fd, "self/fd", O_DIRECTORY | O_RDONLY);
67 } else {
68 proc_self_fd = openat(AT_FDCWD, "/proc/self/fd", O_DIRECTORY | O_RDONLY);
69 if (proc_self_fd < 0) {
70 // If this process has been chrooted (eg into /proc/self/fdinfo) then
71 // the new root dir will not have directory listing permissions for us
72 // (hence EACCES). And if we do have this permission, then /proc won't
73 // exist anyway (hence ENOENT).
74 DPCHECK(errno == EACCES || errno == ENOENT)
75 << "Unexpected failure when trying to open /proc/self/fd: ("
76 << errno << ") " << strerror(errno);
78 // If not available, guess false.
79 return false;
82 PCHECK(0 <= proc_self_fd);
84 // Ownership of proc_self_fd is transferred here, it must not be closed
85 // or modified afterwards except via dir.
86 ScopedDIR dir(fdopendir(proc_self_fd));
87 CHECK(dir);
89 struct dirent e;
90 struct dirent* de;
91 while (!readdir_r(dir.get(), &e, &de) && de) {
92 if (strcmp(e.d_name, ".") == 0 || strcmp(e.d_name, "..") == 0) {
93 continue;
96 int fd_num;
97 CHECK(base::StringToInt(e.d_name, &fd_num));
98 if (fd_num == proc_fd || fd_num == proc_self_fd) {
99 continue;
102 struct stat s;
103 // It's OK to use proc_self_fd here, fstatat won't modify it.
104 CHECK(fstatat(proc_self_fd, e.d_name, &s, 0) == 0);
105 if (S_ISDIR(s.st_mode)) {
106 return true;
110 // No open unmanaged directories found.
111 return false;
114 //static
115 base::ScopedFD ProcUtil::OpenProcSelfTask() {
116 base::ScopedFD proc_self_task(
117 HANDLE_EINTR(
118 open("/proc/self/task/", O_RDONLY | O_DIRECTORY | O_CLOEXEC)));
119 PCHECK(proc_self_task.is_valid());
120 return proc_self_task.Pass();
123 } // namespace sandbox