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

Side by Side Diff: chrome/browser/process_singleton_linux.cc

Issue 2838034: Move the SingletonSocket to a temporary directory (Closed)
Patch Set: Address mattm's comments Created 10 years, 4 months 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
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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 // On Linux, when the user tries to launch a second copy of chrome, we check 5 // On Linux, when the user tries to launch a second copy of chrome, we check
6 // for a socket in the user's profile directory. If the socket file is open we 6 // for a socket in the user's profile directory. If the socket file is open we
7 // send a message to the first chrome browser process with the current 7 // send a message to the first chrome browser process with the current
8 // directory and second process command line flags. The second process then 8 // directory and second process command line flags. The second process then
9 // exits. 9 // exits.
10 // 10 //
11 // Because many networked filesystem implementations do not support unix domain
12 // sockets, we create the socket in a temporary directory and create a symlink
13 // in the profile. This temporary directory is no longer bound to the profile,
14 // and may disappear across a reboot or login to a separate session. To bind
15 // them, we store a unique cookie in the profile directory, which must also be
16 // present in the remote directory to connect. The cookie is checked both before
17 // and after the connection. /tmp is sticky, and different Chrome sessions use
18 // different cookies. Thus, a matching cookie before and after means the
19 // connection was to a directory with a valid cookie.
20 //
11 // We also have a lock file, which is a symlink to a non-existent destination. 21 // We also have a lock file, which is a symlink to a non-existent destination.
12 // The destination is a string containing the hostname and process id of 22 // The destination is a string containing the hostname and process id of
13 // chrome's browser process, eg. "SingletonLock -> example.com-9156". When the 23 // chrome's browser process, eg. "SingletonLock -> example.com-9156". When the
14 // first copy of chrome exits it will delete the lock file on shutdown, so that 24 // first copy of chrome exits it will delete the lock file on shutdown, so that
15 // a different instance on a different host may then use the profile directory. 25 // a different instance on a different host may then use the profile directory.
16 // 26 //
17 // If writing to the socket fails, the hostname in the lock is checked to see if 27 // If writing to the socket fails, the hostname in the lock is checked to see if
18 // another instance is running a different host using a shared filesystem (nfs, 28 // another instance is running a different host using a shared filesystem (nfs,
19 // etc.) If the hostname differs an error is displayed and the second process 29 // etc.) If the hostname differs an error is displayed and the second process
20 // exits. Otherwise the first process (if any) is killed and the second process 30 // exits. Otherwise the first process (if any) is killed and the second process
(...skipping 27 matching lines...) Expand all
48 #include "base/base_paths.h" 58 #include "base/base_paths.h"
49 #include "base/basictypes.h" 59 #include "base/basictypes.h"
50 #include "base/command_line.h" 60 #include "base/command_line.h"
51 #include "base/eintr_wrapper.h" 61 #include "base/eintr_wrapper.h"
52 #include "base/file_path.h" 62 #include "base/file_path.h"
53 #include "base/logging.h" 63 #include "base/logging.h"
54 #include "base/message_loop.h" 64 #include "base/message_loop.h"
55 #include "base/path_service.h" 65 #include "base/path_service.h"
56 #include "base/platform_thread.h" 66 #include "base/platform_thread.h"
57 #include "base/process_util.h" 67 #include "base/process_util.h"
68 #include "base/rand_util.h"
58 #include "base/safe_strerror_posix.h" 69 #include "base/safe_strerror_posix.h"
59 #include "base/stl_util-inl.h" 70 #include "base/stl_util-inl.h"
60 #include "base/string_number_conversions.h" 71 #include "base/string_number_conversions.h"
61 #include "base/sys_string_conversions.h" 72 #include "base/sys_string_conversions.h"
62 #include "base/utf_string_conversions.h" 73 #include "base/utf_string_conversions.h"
63 #include "base/time.h" 74 #include "base/time.h"
64 #include "base/timer.h" 75 #include "base/timer.h"
65 #include "chrome/browser/browser_init.h" 76 #include "chrome/browser/browser_init.h"
66 #include "chrome/browser/browser_process.h" 77 #include "chrome/browser/browser_process.h"
67 #include "chrome/browser/chrome_thread.h" 78 #include "chrome/browser/chrome_thread.h"
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
183 // No more data to read. 194 // No more data to read.
184 return bytes_read; 195 return bytes_read;
185 } else { 196 } else {
186 bytes_read += rv; 197 bytes_read += rv;
187 } 198 }
188 } while (bytes_read < bufsize); 199 } while (bytes_read < bufsize);
189 200
190 return bytes_read; 201 return bytes_read;
191 } 202 }
192 203
193 // Set up a socket and sockaddr appropriate for messaging. 204 // Set up a sockaddr appropriate for messaging.
194 void SetupSocket(const std::string& path, int* sock, struct sockaddr_un* addr) { 205 void SetupSockAddr(const std::string& path, struct sockaddr_un* addr) {
195 *sock = socket(PF_UNIX, SOCK_STREAM, 0);
196 PCHECK(*sock >= 0) << "socket() failed";
197
198 int rv = SetNonBlocking(*sock);
199 DCHECK_EQ(0, rv) << "Failed to make non-blocking socket.";
200 rv = SetCloseOnExec(*sock);
201 DCHECK_EQ(0, rv) << "Failed to set CLOEXEC on socket.";
202
203 addr->sun_family = AF_UNIX; 206 addr->sun_family = AF_UNIX;
204 CHECK(path.length() < arraysize(addr->sun_path)) 207 CHECK(path.length() < arraysize(addr->sun_path))
205 << "Socket path too long: " << path; 208 << "Socket path too long: " << path;
206 base::strlcpy(addr->sun_path, path.c_str(), arraysize(addr->sun_path)); 209 base::strlcpy(addr->sun_path, path.c_str(), arraysize(addr->sun_path));
207 } 210 }
208 211
209 // Read a symbol link, return empty string if given path is not a symbol link. 212 // Set up a socket appropriate for messaging.
213 int SetupSocketOnly() {
214 int sock = socket(PF_UNIX, SOCK_STREAM, 0);
215 PCHECK(sock >= 0) << "socket() failed";
216
217 int rv = SetNonBlocking(sock);
218 DCHECK_EQ(0, rv) << "Failed to make non-blocking socket.";
219 rv = SetCloseOnExec(sock);
220 DCHECK_EQ(0, rv) << "Failed to set CLOEXEC on socket.";
221
222 return sock;
223 }
224
225 // Set up a socket and sockaddr appropriate for messaging.
226 void SetupSocket(const std::string& path, int* sock, struct sockaddr_un* addr) {
227 *sock = SetupSocketOnly();
228 SetupSockAddr(path, addr);
229 }
230
231 // Read a symbolic link, return empty string if given path is not a
232 // symbol link. This version does not interpret the errno, leaving
233 // the caller to do so.
234 bool ReadLinkSilent(const std::string& path, std::string* output) {
235 char buf[PATH_MAX];
236 ssize_t len = readlink(path.c_str(), buf, PATH_MAX);
237 if (len >= 0) {
238 output->assign(buf, len);
239 return true;
240 }
241 output->clear();
242 return false;
243 }
244
245 // Read a symbolic link, return empty string if given path is not a symbol link.
210 std::string ReadLink(const std::string& path) { 246 std::string ReadLink(const std::string& path) {
211 struct stat statbuf; 247 std::string target;
212 248 if (!ReadLinkSilent(path, &target)) {
213 if (lstat(path.c_str(), &statbuf) < 0) { 249 // The only errno that should occur is ENOENT.
214 DCHECK_EQ(errno, ENOENT); 250 if (errno != 0 && errno != ENOENT)
215 return std::string(); 251 PLOG(ERROR) << "readlink(" << path << ") failed";
216 } 252 }
217 253 return target;
218 if (S_ISLNK(statbuf.st_mode)) {
219 char buf[PATH_MAX + 1];
220 ssize_t len = readlink(path.c_str(), buf, PATH_MAX);
221 if (len > 0) {
222 buf[len] = '\0';
223 return std::string(buf);
224 } else {
225 PLOG(ERROR) << "readlink(" << path << ") failed";
226 }
227 }
228
229 return std::string();
230 } 254 }
231 255
232 // Unlink a path. Return true on success. 256 // Unlink a path. Return true on success.
233 bool UnlinkPath(const std::string& path) { 257 bool UnlinkPath(const std::string& path) {
234 int rv = unlink(path.c_str()); 258 int rv = unlink(path.c_str());
235 if (rv < 0 && errno != ENOENT) 259 if (rv < 0 && errno != ENOENT)
236 PLOG(ERROR) << "Failed to unlink " << path; 260 PLOG(ERROR) << "Failed to unlink " << path;
237 261
238 return rv == 0; 262 return rv == 0;
239 } 263 }
240 264
265 // Create a symlink. Returns true on success.
266 bool SymlinkPath(const std::string& target, const std::string& path) {
267 if (symlink(target.c_str(), path.c_str()) < 0) {
268 // Double check the value in case symlink suceeded but we got an incorrect
269 // failure due to NFS packet loss & retry.
270 int saved_errno = errno;
271 if (ReadLink(path) != target) {
272 // If we failed to create the lock, most likely another instance won the
273 // startup race.
274 errno = saved_errno;
275 PLOG(ERROR) << "Failed to create " << path;
276 return false;
277 }
278 }
279 return true;
280 }
281
241 // Extract the hostname and pid from the lock symlink. 282 // Extract the hostname and pid from the lock symlink.
242 // Returns true if the lock existed. 283 // Returns true if the lock existed.
243 bool ParseLockPath(const std::string& path, 284 bool ParseLockPath(const std::string& path,
244 std::string* hostname, 285 std::string* hostname,
245 int* pid) { 286 int* pid) {
246 std::string real_path = ReadLink(path); 287 std::string real_path = ReadLink(path);
247 if (real_path.empty()) 288 if (real_path.empty())
248 return false; 289 return false;
249 290
250 std::string::size_type pos = real_path.rfind('-'); 291 std::string::size_type pos = real_path.rfind(kLockDelimiter);
251 292
252 // If the path is not a symbolic link, or doesn't contain what we expect, 293 // If the path is not a symbolic link, or doesn't contain what we expect,
253 // bail. 294 // bail.
254 if (pos == std::string::npos) { 295 if (pos == std::string::npos) {
255 *hostname = ""; 296 *hostname = "";
256 *pid = -1; 297 *pid = -1;
257 return true; 298 return true;
258 } 299 }
259 300
260 *hostname = real_path.substr(0, pos); 301 *hostname = real_path.substr(0, pos);
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
329 // progress of shutting down and finishes before we try to kill it). 370 // progress of shutting down and finishes before we try to kill it).
330 DCHECK(rv == 0 || errno == ESRCH) << "Error killing process: " 371 DCHECK(rv == 0 || errno == ESRCH) << "Error killing process: "
331 << safe_strerror(errno); 372 << safe_strerror(errno);
332 return true; 373 return true;
333 } 374 }
334 375
335 LOG(ERROR) << "Failed to extract pid from path: " << path; 376 LOG(ERROR) << "Failed to extract pid from path: " << path;
336 return true; 377 return true;
337 } 378 }
338 379
339 // A helper class to close a socket automatically. 380 // A helper class to hold onto a socket.
340 class SocketCloser { 381 class ScopedSocket {
341 public: 382 public:
342 explicit SocketCloser(int fd) : fd_(fd) { } 383 ScopedSocket() : fd_(-1) { Reset(); }
343 ~SocketCloser() { CloseSocket(fd_); } 384 ~ScopedSocket() { Close(); }
385 int fd() { return fd_; }
386 void Reset() {
387 Close();
388 fd_ = SetupSocketOnly();
389 }
390 void Close() {
391 if (fd_ >= 0)
392 CloseSocket(fd_);
393 fd_ = -1;
394 }
344 private: 395 private:
345 int fd_; 396 int fd_;
346 }; 397 };
347 398
399 // Returns a random string for uniquifying profile connections.
400 std::string GenerateCookie() {
401 return base::Uint64ToString(base::RandUint64());
402 }
403
404 bool CheckCookie(const FilePath& path, const std::string& cookie) {
405 return (cookie == ReadLink(path.value()));
406 }
407
408 bool ConnectSocket(ScopedSocket* socket,
409 const FilePath& socket_path,
410 const FilePath& cookie_path) {
411 std::string socket_target;
412 if (ReadLinkSilent(socket_path.value(), &socket_target)) {
413 // It's a symlink. Read the cookie.
414 std::string cookie = ReadLink(cookie_path.value());
415 if (cookie.empty())
416 return false;
417 FilePath remote_cookie = FilePath(socket_target).DirName().
418 Append(chrome::kSingletonCookieFilename);
419 // Verify the cookie before connecting.
420 if (!CheckCookie(remote_cookie, cookie))
421 return false;
422 // Now we know the directory was (at that point) created by the profile
423 // owner. Try to connect.
424 sockaddr_un addr;
425 SetupSockAddr(socket_path.value(), &addr);
426 int ret = HANDLE_EINTR(connect(socket->fd(),
427 reinterpret_cast<sockaddr*>(&addr),
428 sizeof(addr)));
429 if (ret != 0)
430 return false;
431 // Check the cookie again. We only link in /tmp, which is sticky, so, if the
432 // directory is still correct, it must have been correct in-between when we
433 // connected. POSIX, sadly, lacks a connectat().
434 if (!CheckCookie(remote_cookie, cookie)) {
435 socket->Reset();
436 return false;
437 }
438 // Success!
439 return true;
440 } else if (errno == EINVAL) {
441 // It exists, but is not a symlink (or some other error we detect
442 // later). Just connect to it directly; this is an older version of Chrome.
443 sockaddr_un addr;
444 SetupSockAddr(socket_path.value(), &addr);
445 int ret = HANDLE_EINTR(connect(socket->fd(),
446 reinterpret_cast<sockaddr*>(&addr),
447 sizeof(addr)));
448 return (ret == 0);
449 } else {
450 // File is missing, or other error.
451 if (errno != ENOENT)
452 PLOG(ERROR) << "readlink failed";
453 return false;
454 }
455 }
456
348 } // namespace 457 } // namespace
349 458
350 /////////////////////////////////////////////////////////////////////////////// 459 ///////////////////////////////////////////////////////////////////////////////
351 // ProcessSingleton::LinuxWatcher 460 // ProcessSingleton::LinuxWatcher
352 // A helper class for a Linux specific implementation of the process singleton. 461 // A helper class for a Linux specific implementation of the process singleton.
353 // This class sets up a listener on the singleton socket and handles parsing 462 // This class sets up a listener on the singleton socket and handles parsing
354 // messages that come in on the singleton socket. 463 // messages that come in on the singleton socket.
355 class ProcessSingleton::LinuxWatcher 464 class ProcessSingleton::LinuxWatcher
356 : public MessageLoopForIO::Watcher, 465 : public MessageLoopForIO::Watcher,
357 public MessageLoop::DestructionObserver, 466 public MessageLoop::DestructionObserver,
(...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after
646 755
647 /////////////////////////////////////////////////////////////////////////////// 756 ///////////////////////////////////////////////////////////////////////////////
648 // ProcessSingleton 757 // ProcessSingleton
649 // 758 //
650 ProcessSingleton::ProcessSingleton(const FilePath& user_data_dir) 759 ProcessSingleton::ProcessSingleton(const FilePath& user_data_dir)
651 : locked_(false), 760 : locked_(false),
652 foreground_window_(NULL), 761 foreground_window_(NULL),
653 ALLOW_THIS_IN_INITIALIZER_LIST(watcher_(new LinuxWatcher(this))) { 762 ALLOW_THIS_IN_INITIALIZER_LIST(watcher_(new LinuxWatcher(this))) {
654 socket_path_ = user_data_dir.Append(chrome::kSingletonSocketFilename); 763 socket_path_ = user_data_dir.Append(chrome::kSingletonSocketFilename);
655 lock_path_ = user_data_dir.Append(chrome::kSingletonLockFilename); 764 lock_path_ = user_data_dir.Append(chrome::kSingletonLockFilename);
765 cookie_path_ = user_data_dir.Append(chrome::kSingletonCookieFilename);
656 } 766 }
657 767
658 ProcessSingleton::~ProcessSingleton() { 768 ProcessSingleton::~ProcessSingleton() {
659 } 769 }
660 770
661 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() { 771 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcess() {
662 return NotifyOtherProcessWithTimeout(*CommandLine::ForCurrentProcess(), 772 return NotifyOtherProcessWithTimeout(*CommandLine::ForCurrentProcess(),
663 kTimeoutInSeconds, 773 kTimeoutInSeconds,
664 true); 774 true);
665 } 775 }
666 776
667 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout( 777 ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
668 const CommandLine& cmd_line, 778 const CommandLine& cmd_line,
669 int timeout_seconds, 779 int timeout_seconds,
670 bool kill_unresponsive) { 780 bool kill_unresponsive) {
671 DCHECK_GE(timeout_seconds, 0); 781 DCHECK_GE(timeout_seconds, 0);
672 782
673 int socket; 783 ScopedSocket socket;
674 sockaddr_un addr;
675 SetupSocket(socket_path_.value(), &socket, &addr);
676
677 // It'll close the socket automatically when exiting this method.
678 SocketCloser socket_closer(socket);
679
680 for (int retries = 0; retries <= timeout_seconds; ++retries) { 784 for (int retries = 0; retries <= timeout_seconds; ++retries) {
681 // Connecting to the socket 785 // Try to connect to the socket.
682 int ret = HANDLE_EINTR(connect(socket, 786 if (ConnectSocket(&socket, socket_path_, cookie_path_))
683 reinterpret_cast<sockaddr*>(&addr),
684 sizeof(addr)));
685 if (ret == 0)
686 break; 787 break;
687 788
688 // If we're in a race with another process, they may be in Create() and have 789 // If we're in a race with another process, they may be in Create() and have
689 // created the lock but not attached to the socket. So we check if the 790 // created the lock but not attached to the socket. So we check if the
690 // process with the pid from the lockfile is currently running and is a 791 // process with the pid from the lockfile is currently running and is a
691 // chrome browser. If so, we loop and try again for |timeout_seconds|. 792 // chrome browser. If so, we loop and try again for |timeout_seconds|.
692 793
693 std::string hostname; 794 std::string hostname;
694 int pid; 795 int pid;
695 if (!ParseLockPath(lock_path_.value(), &hostname, &pid)) { 796 if (!ParseLockPath(lock_path_.value(), &hostname, &pid)) {
(...skipping 30 matching lines...) Expand all
726 // Retries failed. Kill the unresponsive chrome process and continue. 827 // Retries failed. Kill the unresponsive chrome process and continue.
727 if (!kill_unresponsive || !KillProcessByLockPath(lock_path_.value())) 828 if (!kill_unresponsive || !KillProcessByLockPath(lock_path_.value()))
728 return PROFILE_IN_USE; 829 return PROFILE_IN_USE;
729 return PROCESS_NONE; 830 return PROCESS_NONE;
730 } 831 }
731 832
732 PlatformThread::Sleep(1000 /* ms */); 833 PlatformThread::Sleep(1000 /* ms */);
733 } 834 }
734 835
735 timeval timeout = {timeout_seconds, 0}; 836 timeval timeout = {timeout_seconds, 0};
736 setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); 837 setsockopt(socket.fd(), SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
737 838
738 // Found another process, prepare our command line 839 // Found another process, prepare our command line
739 // format is "START\0<current dir>\0<argv[0]>\0...\0<argv[n]>". 840 // format is "START\0<current dir>\0<argv[0]>\0...\0<argv[n]>".
740 std::string to_send(kStartToken); 841 std::string to_send(kStartToken);
741 to_send.push_back(kTokenDelimiter); 842 to_send.push_back(kTokenDelimiter);
742 843
743 FilePath current_dir; 844 FilePath current_dir;
744 if (!PathService::Get(base::DIR_CURRENT, &current_dir)) 845 if (!PathService::Get(base::DIR_CURRENT, &current_dir))
745 return PROCESS_NONE; 846 return PROCESS_NONE;
746 to_send.append(current_dir.value()); 847 to_send.append(current_dir.value());
747 848
748 const std::vector<std::string>& argv = cmd_line.argv(); 849 const std::vector<std::string>& argv = cmd_line.argv();
749 for (std::vector<std::string>::const_iterator it = argv.begin(); 850 for (std::vector<std::string>::const_iterator it = argv.begin();
750 it != argv.end(); ++it) { 851 it != argv.end(); ++it) {
751 to_send.push_back(kTokenDelimiter); 852 to_send.push_back(kTokenDelimiter);
752 to_send.append(*it); 853 to_send.append(*it);
753 } 854 }
754 855
755 // Send the message 856 // Send the message
756 if (!WriteToSocket(socket, to_send.data(), to_send.length())) { 857 if (!WriteToSocket(socket.fd(), to_send.data(), to_send.length())) {
757 // Try to kill the other process, because it might have been dead. 858 // Try to kill the other process, because it might have been dead.
758 if (!kill_unresponsive || !KillProcessByLockPath(lock_path_.value())) 859 if (!kill_unresponsive || !KillProcessByLockPath(lock_path_.value()))
759 return PROFILE_IN_USE; 860 return PROFILE_IN_USE;
760 return PROCESS_NONE; 861 return PROCESS_NONE;
761 } 862 }
762 863
763 if (shutdown(socket, SHUT_WR) < 0) 864 if (shutdown(socket.fd(), SHUT_WR) < 0)
764 PLOG(ERROR) << "shutdown() failed"; 865 PLOG(ERROR) << "shutdown() failed";
765 866
766 // Read ACK message from the other process. It might be blocked for a certain 867 // Read ACK message from the other process. It might be blocked for a certain
767 // timeout, to make sure the other process has enough time to return ACK. 868 // timeout, to make sure the other process has enough time to return ACK.
768 char buf[kMaxACKMessageLength + 1]; 869 char buf[kMaxACKMessageLength + 1];
769 ssize_t len = 870 ssize_t len =
770 ReadFromSocket(socket, buf, kMaxACKMessageLength, timeout_seconds); 871 ReadFromSocket(socket.fd(), buf, kMaxACKMessageLength, timeout_seconds);
771 872
772 // Failed to read ACK, the other process might have been frozen. 873 // Failed to read ACK, the other process might have been frozen.
773 if (len <= 0) { 874 if (len <= 0) {
774 if (!kill_unresponsive || !KillProcessByLockPath(lock_path_.value())) 875 if (!kill_unresponsive || !KillProcessByLockPath(lock_path_.value()))
775 return PROFILE_IN_USE; 876 return PROFILE_IN_USE;
776 return PROCESS_NONE; 877 return PROCESS_NONE;
777 } 878 }
778 879
779 buf[len] = '\0'; 880 buf[len] = '\0';
780 if (strncmp(buf, kShutdownToken, arraysize(kShutdownToken) - 1) == 0) { 881 if (strncmp(buf, kShutdownToken, arraysize(kShutdownToken) - 1) == 0) {
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
827 // The symlink lock is pointed to the hostname and process id, so other 928 // The symlink lock is pointed to the hostname and process id, so other
828 // processes can find it out. 929 // processes can find it out.
829 std::string symlink_content = StringPrintf( 930 std::string symlink_content = StringPrintf(
830 "%s%c%u", 931 "%s%c%u",
831 net::GetHostName().c_str(), 932 net::GetHostName().c_str(),
832 kLockDelimiter, 933 kLockDelimiter,
833 base::GetCurrentProcId()); 934 base::GetCurrentProcId());
834 935
835 // Create symbol link before binding the socket, to ensure only one instance 936 // Create symbol link before binding the socket, to ensure only one instance
836 // can have the socket open. 937 // can have the socket open.
837 if (symlink(symlink_content.c_str(), lock_path_.value().c_str()) < 0) { 938 if (!SymlinkPath(symlink_content, lock_path_.value())) {
838 // Double check the value in case symlink suceeded but we got an incorrect
839 // failure due to NFS packet loss & retry.
840 int saved_errno = errno;
841 if (ReadLink(lock_path_.value()) != symlink_content) {
842 // If we failed to create the lock, most likely another instance won the 939 // If we failed to create the lock, most likely another instance won the
843 // startup race. 940 // startup race.
844 errno = saved_errno;
845 PLOG(ERROR) << "Failed to create " << lock_path_.value();
846 return false; 941 return false;
847 }
848 } 942 }
849 943
850 SetupSocket(socket_path_.value(), &sock, &addr); 944 // Create the socket file somewhere in /tmp which is usually mounted as a
945 // normal filesystem. Some network filesystems (notably AFS) are screwy and
946 // do not support Unix domain sockets.
947 if (!socket_dir_.CreateUniqueTempDir()) {
948 LOG(ERROR) << "Failed to create socket directory.";
949 return false;
950 }
951 // Setup the socket symlink and the two cookies.
952 FilePath socket_target_path =
953 socket_dir_.path().Append(chrome::kSingletonSocketFilename);
954 std::string cookie = GenerateCookie();
955 FilePath remote_cookie_path =
956 socket_dir_.path().Append(chrome::kSingletonCookieFilename);
957 UnlinkPath(socket_path_.value());
958 UnlinkPath(cookie_path_.value());
959 if (!SymlinkPath(socket_target_path.value(), socket_path_.value()) ||
960 !SymlinkPath(cookie, cookie_path_.value()) ||
961 !SymlinkPath(cookie, remote_cookie_path.value())) {
962 // We've already locked things, so we can't have lost the startup race,
963 // but something doesn't like us.
964 LOG(ERROR) << "Failed to create symlinks.";
965 socket_dir_.Delete();
966 return false;
967 }
851 968
852 UnlinkPath(socket_path_.value()); 969 SetupSocket(socket_target_path.value(), &sock, &addr);
853 970
854 if (bind(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) { 971 if (bind(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
855 PLOG(ERROR) << "Failed to bind() " << socket_path_.value(); 972 PLOG(ERROR) << "Failed to bind() " << socket_target_path.value();
856 CloseSocket(sock); 973 CloseSocket(sock);
857 return false; 974 return false;
858 } 975 }
859 976
860 if (listen(sock, 5) < 0) 977 if (listen(sock, 5) < 0)
861 NOTREACHED() << "listen failed: " << safe_strerror(errno); 978 NOTREACHED() << "listen failed: " << safe_strerror(errno);
862 979
863 // Normally we would use ChromeThread, but the IO thread hasn't started yet. 980 // Normally we would use ChromeThread, but the IO thread hasn't started yet.
864 // Using g_browser_process, we start the thread so we can listen on the 981 // Using g_browser_process, we start the thread so we can listen on the
865 // socket. 982 // socket.
866 MessageLoop* ml = g_browser_process->io_thread()->message_loop(); 983 MessageLoop* ml = g_browser_process->io_thread()->message_loop();
867 DCHECK(ml); 984 DCHECK(ml);
868 ml->PostTask(FROM_HERE, NewRunnableMethod( 985 ml->PostTask(FROM_HERE, NewRunnableMethod(
869 watcher_.get(), 986 watcher_.get(),
870 &ProcessSingleton::LinuxWatcher::StartListening, 987 &ProcessSingleton::LinuxWatcher::StartListening,
871 sock)); 988 sock));
872 989
873 return true; 990 return true;
874 } 991 }
875 992
876 void ProcessSingleton::Cleanup() { 993 void ProcessSingleton::Cleanup() {
994 UnlinkPath(socket_path_.value());
995 UnlinkPath(cookie_path_.value());
877 UnlinkPath(lock_path_.value()); 996 UnlinkPath(lock_path_.value());
878 } 997 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698