|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "nsProfileStringTypes.h" |
|
7 #include "nsProfileLock.h" |
|
8 #include "nsCOMPtr.h" |
|
9 |
|
10 #if defined(XP_MACOSX) |
|
11 #include <Carbon/Carbon.h> |
|
12 #include <CoreFoundation/CoreFoundation.h> |
|
13 #endif |
|
14 |
|
15 #ifdef XP_UNIX |
|
16 #include <unistd.h> |
|
17 #include <fcntl.h> |
|
18 #include <errno.h> |
|
19 #include <signal.h> |
|
20 #include <stdlib.h> |
|
21 #include "prnetdb.h" |
|
22 #include "prsystem.h" |
|
23 #include "prprf.h" |
|
24 #include "prenv.h" |
|
25 #endif |
|
26 |
|
27 #ifdef VMS |
|
28 #include <rmsdef.h> |
|
29 #endif |
|
30 |
|
31 // ********************************************************************** |
|
32 // class nsProfileLock |
|
33 // |
|
34 // This code was moved from profile/src/nsProfileAccess. |
|
35 // ********************************************************************** |
|
36 |
|
37 #if defined (XP_UNIX) |
|
38 static bool sDisableSignalHandling = false; |
|
39 #endif |
|
40 |
|
41 nsProfileLock::nsProfileLock() : |
|
42 mHaveLock(false), |
|
43 mReplacedLockTime(0) |
|
44 #if defined (XP_WIN) |
|
45 ,mLockFileHandle(INVALID_HANDLE_VALUE) |
|
46 #elif defined (XP_UNIX) |
|
47 ,mPidLockFileName(nullptr) |
|
48 ,mLockFileDesc(-1) |
|
49 #endif |
|
50 { |
|
51 #if defined (XP_UNIX) |
|
52 next = prev = this; |
|
53 sDisableSignalHandling = PR_GetEnv("MOZ_DISABLE_SIG_HANDLER") ? true : false; |
|
54 #endif |
|
55 } |
|
56 |
|
57 |
|
58 nsProfileLock::nsProfileLock(nsProfileLock& src) |
|
59 { |
|
60 *this = src; |
|
61 } |
|
62 |
|
63 |
|
64 nsProfileLock& nsProfileLock::operator=(nsProfileLock& rhs) |
|
65 { |
|
66 Unlock(); |
|
67 |
|
68 mHaveLock = rhs.mHaveLock; |
|
69 rhs.mHaveLock = false; |
|
70 |
|
71 #if defined (XP_WIN) |
|
72 mLockFileHandle = rhs.mLockFileHandle; |
|
73 rhs.mLockFileHandle = INVALID_HANDLE_VALUE; |
|
74 #elif defined (XP_UNIX) |
|
75 mLockFileDesc = rhs.mLockFileDesc; |
|
76 rhs.mLockFileDesc = -1; |
|
77 mPidLockFileName = rhs.mPidLockFileName; |
|
78 rhs.mPidLockFileName = nullptr; |
|
79 if (mPidLockFileName) |
|
80 { |
|
81 // rhs had a symlink lock, therefore it was on the list. |
|
82 PR_REMOVE_LINK(&rhs); |
|
83 PR_APPEND_LINK(this, &mPidLockList); |
|
84 } |
|
85 #endif |
|
86 |
|
87 return *this; |
|
88 } |
|
89 |
|
90 |
|
91 nsProfileLock::~nsProfileLock() |
|
92 { |
|
93 Unlock(); |
|
94 } |
|
95 |
|
96 |
|
97 #if defined (XP_UNIX) |
|
98 |
|
99 static int setupPidLockCleanup; |
|
100 |
|
101 PRCList nsProfileLock::mPidLockList = |
|
102 PR_INIT_STATIC_CLIST(&nsProfileLock::mPidLockList); |
|
103 |
|
104 void nsProfileLock::RemovePidLockFiles(bool aFatalSignal) |
|
105 { |
|
106 while (!PR_CLIST_IS_EMPTY(&mPidLockList)) |
|
107 { |
|
108 nsProfileLock *lock = static_cast<nsProfileLock*>(mPidLockList.next); |
|
109 lock->Unlock(aFatalSignal); |
|
110 } |
|
111 } |
|
112 |
|
113 static struct sigaction SIGHUP_oldact; |
|
114 static struct sigaction SIGINT_oldact; |
|
115 static struct sigaction SIGQUIT_oldact; |
|
116 static struct sigaction SIGILL_oldact; |
|
117 static struct sigaction SIGABRT_oldact; |
|
118 static struct sigaction SIGSEGV_oldact; |
|
119 static struct sigaction SIGTERM_oldact; |
|
120 |
|
121 void nsProfileLock::FatalSignalHandler(int signo |
|
122 #ifdef SA_SIGINFO |
|
123 , siginfo_t *info, void *context |
|
124 #endif |
|
125 ) |
|
126 { |
|
127 // Remove any locks still held. |
|
128 RemovePidLockFiles(true); |
|
129 |
|
130 // Chain to the old handler, which may exit. |
|
131 struct sigaction *oldact = nullptr; |
|
132 |
|
133 switch (signo) { |
|
134 case SIGHUP: |
|
135 oldact = &SIGHUP_oldact; |
|
136 break; |
|
137 case SIGINT: |
|
138 oldact = &SIGINT_oldact; |
|
139 break; |
|
140 case SIGQUIT: |
|
141 oldact = &SIGQUIT_oldact; |
|
142 break; |
|
143 case SIGILL: |
|
144 oldact = &SIGILL_oldact; |
|
145 break; |
|
146 case SIGABRT: |
|
147 oldact = &SIGABRT_oldact; |
|
148 break; |
|
149 case SIGSEGV: |
|
150 oldact = &SIGSEGV_oldact; |
|
151 break; |
|
152 case SIGTERM: |
|
153 oldact = &SIGTERM_oldact; |
|
154 break; |
|
155 default: |
|
156 NS_NOTREACHED("bad signo"); |
|
157 break; |
|
158 } |
|
159 |
|
160 if (oldact) { |
|
161 if (oldact->sa_handler == SIG_DFL) { |
|
162 // Make sure the default sig handler is executed |
|
163 // We need it to get Mozilla to dump core. |
|
164 sigaction(signo,oldact, nullptr); |
|
165 |
|
166 // Now that we've restored the default handler, unmask the |
|
167 // signal and invoke it. |
|
168 |
|
169 sigset_t unblock_sigs; |
|
170 sigemptyset(&unblock_sigs); |
|
171 sigaddset(&unblock_sigs, signo); |
|
172 |
|
173 sigprocmask(SIG_UNBLOCK, &unblock_sigs, nullptr); |
|
174 |
|
175 raise(signo); |
|
176 } |
|
177 #ifdef SA_SIGINFO |
|
178 else if (oldact->sa_sigaction && |
|
179 (oldact->sa_flags & SA_SIGINFO) == SA_SIGINFO) { |
|
180 oldact->sa_sigaction(signo, info, context); |
|
181 } |
|
182 #endif |
|
183 else if (oldact->sa_handler && oldact->sa_handler != SIG_IGN) |
|
184 { |
|
185 oldact->sa_handler(signo); |
|
186 } |
|
187 } |
|
188 |
|
189 // Backstop exit call, just in case. |
|
190 _exit(signo); |
|
191 } |
|
192 |
|
193 nsresult nsProfileLock::LockWithFcntl(nsIFile *aLockFile) |
|
194 { |
|
195 nsresult rv = NS_OK; |
|
196 |
|
197 nsAutoCString lockFilePath; |
|
198 rv = aLockFile->GetNativePath(lockFilePath); |
|
199 if (NS_FAILED(rv)) { |
|
200 NS_ERROR("Could not get native path"); |
|
201 return rv; |
|
202 } |
|
203 |
|
204 aLockFile->GetLastModifiedTime(&mReplacedLockTime); |
|
205 |
|
206 mLockFileDesc = open(lockFilePath.get(), O_WRONLY | O_CREAT | O_TRUNC, 0666); |
|
207 if (mLockFileDesc != -1) |
|
208 { |
|
209 struct flock lock; |
|
210 lock.l_start = 0; |
|
211 lock.l_len = 0; // len = 0 means entire file |
|
212 lock.l_type = F_WRLCK; |
|
213 lock.l_whence = SEEK_SET; |
|
214 |
|
215 // If fcntl(F_GETLK) fails then the server does not support/allow fcntl(), |
|
216 // return failure rather than access denied in this case so we fallback |
|
217 // to using a symlink lock, bug 303633. |
|
218 struct flock testlock = lock; |
|
219 if (fcntl(mLockFileDesc, F_GETLK, &testlock) == -1) |
|
220 { |
|
221 close(mLockFileDesc); |
|
222 mLockFileDesc = -1; |
|
223 rv = NS_ERROR_FAILURE; |
|
224 } |
|
225 else if (fcntl(mLockFileDesc, F_SETLK, &lock) == -1) |
|
226 { |
|
227 close(mLockFileDesc); |
|
228 mLockFileDesc = -1; |
|
229 |
|
230 // With OS X, on NFS, errno == ENOTSUP |
|
231 // XXX Check for that and return specific rv for it? |
|
232 #ifdef DEBUG |
|
233 printf("fcntl(F_SETLK) failed. errno = %d\n", errno); |
|
234 #endif |
|
235 if (errno == EAGAIN || errno == EACCES) |
|
236 rv = NS_ERROR_FILE_ACCESS_DENIED; |
|
237 else |
|
238 rv = NS_ERROR_FAILURE; |
|
239 } |
|
240 else |
|
241 mHaveLock = true; |
|
242 } |
|
243 else |
|
244 { |
|
245 NS_ERROR("Failed to open lock file."); |
|
246 rv = NS_ERROR_FAILURE; |
|
247 } |
|
248 return rv; |
|
249 } |
|
250 |
|
251 static bool IsSymlinkStaleLock(struct in_addr* aAddr, const char* aFileName, |
|
252 bool aHaveFcntlLock) |
|
253 { |
|
254 // the link exists; see if it's from this machine, and if |
|
255 // so if the process is still active |
|
256 char buf[1024]; |
|
257 int len = readlink(aFileName, buf, sizeof buf - 1); |
|
258 if (len > 0) |
|
259 { |
|
260 buf[len] = '\0'; |
|
261 char *colon = strchr(buf, ':'); |
|
262 if (colon) |
|
263 { |
|
264 *colon++ = '\0'; |
|
265 unsigned long addr = inet_addr(buf); |
|
266 if (addr != (unsigned long) -1) |
|
267 { |
|
268 if (colon[0] == '+' && aHaveFcntlLock) { |
|
269 // This lock was placed by a Firefox build which would have |
|
270 // taken the fnctl lock, and we've already taken the fcntl lock, |
|
271 // so the process that created this obsolete lock must be gone |
|
272 return true; |
|
273 } |
|
274 |
|
275 char *after = nullptr; |
|
276 pid_t pid = strtol(colon, &after, 0); |
|
277 if (pid != 0 && *after == '\0') |
|
278 { |
|
279 if (addr != aAddr->s_addr) |
|
280 { |
|
281 // Remote lock: give up even if stuck. |
|
282 return false; |
|
283 } |
|
284 |
|
285 // kill(pid,0) is a neat trick to check if a |
|
286 // process exists |
|
287 if (kill(pid, 0) == 0 || errno != ESRCH) |
|
288 { |
|
289 // Local process appears to be alive, ass-u-me it |
|
290 // is another Mozilla instance, or a compatible |
|
291 // derivative, that's currently using the profile. |
|
292 // XXX need an "are you Mozilla?" protocol |
|
293 return false; |
|
294 } |
|
295 } |
|
296 } |
|
297 } |
|
298 } |
|
299 return true; |
|
300 } |
|
301 |
|
302 nsresult nsProfileLock::LockWithSymlink(nsIFile *aLockFile, bool aHaveFcntlLock) |
|
303 { |
|
304 nsresult rv; |
|
305 nsAutoCString lockFilePath; |
|
306 rv = aLockFile->GetNativePath(lockFilePath); |
|
307 if (NS_FAILED(rv)) { |
|
308 NS_ERROR("Could not get native path"); |
|
309 return rv; |
|
310 } |
|
311 |
|
312 // don't replace an existing lock time if fcntl already got one |
|
313 if (!mReplacedLockTime) |
|
314 aLockFile->GetLastModifiedTimeOfLink(&mReplacedLockTime); |
|
315 |
|
316 struct in_addr inaddr; |
|
317 inaddr.s_addr = htonl(INADDR_LOOPBACK); |
|
318 |
|
319 char hostname[256]; |
|
320 PRStatus status = PR_GetSystemInfo(PR_SI_HOSTNAME, hostname, sizeof hostname); |
|
321 if (status == PR_SUCCESS) |
|
322 { |
|
323 char netdbbuf[PR_NETDB_BUF_SIZE]; |
|
324 PRHostEnt hostent; |
|
325 status = PR_GetHostByName(hostname, netdbbuf, sizeof netdbbuf, &hostent); |
|
326 if (status == PR_SUCCESS) |
|
327 memcpy(&inaddr, hostent.h_addr, sizeof inaddr); |
|
328 } |
|
329 |
|
330 char *signature = |
|
331 PR_smprintf("%s:%s%lu", inet_ntoa(inaddr), aHaveFcntlLock ? "+" : "", |
|
332 (unsigned long)getpid()); |
|
333 const char *fileName = lockFilePath.get(); |
|
334 int symlink_rv, symlink_errno = 0, tries = 0; |
|
335 |
|
336 // use ns4.x-compatible symlinks if the FS supports them |
|
337 while ((symlink_rv = symlink(signature, fileName)) < 0) |
|
338 { |
|
339 symlink_errno = errno; |
|
340 if (symlink_errno != EEXIST) |
|
341 break; |
|
342 |
|
343 if (!IsSymlinkStaleLock(&inaddr, fileName, aHaveFcntlLock)) |
|
344 break; |
|
345 |
|
346 // Lock seems to be bogus: try to claim it. Give up after a large |
|
347 // number of attempts (100 comes from the 4.x codebase). |
|
348 (void) unlink(fileName); |
|
349 if (++tries > 100) |
|
350 break; |
|
351 } |
|
352 |
|
353 PR_smprintf_free(signature); |
|
354 signature = nullptr; |
|
355 |
|
356 if (symlink_rv == 0) |
|
357 { |
|
358 // We exclusively created the symlink: record its name for eventual |
|
359 // unlock-via-unlink. |
|
360 rv = NS_OK; |
|
361 mHaveLock = true; |
|
362 mPidLockFileName = strdup(fileName); |
|
363 if (mPidLockFileName) |
|
364 { |
|
365 PR_APPEND_LINK(this, &mPidLockList); |
|
366 if (!setupPidLockCleanup++) |
|
367 { |
|
368 // Clean up on normal termination. |
|
369 // This instanciates a dummy class, and will trigger the class |
|
370 // destructor when libxul is unloaded. This is equivalent to atexit(), |
|
371 // but gracefully handles dlclose(). |
|
372 static RemovePidLockFilesExiting r; |
|
373 |
|
374 // Clean up on abnormal termination, using POSIX sigaction. |
|
375 // Don't arm a handler if the signal is being ignored, e.g., |
|
376 // because mozilla is run via nohup. |
|
377 if (!sDisableSignalHandling) { |
|
378 struct sigaction act, oldact; |
|
379 #ifdef SA_SIGINFO |
|
380 act.sa_sigaction = FatalSignalHandler; |
|
381 act.sa_flags = SA_SIGINFO; |
|
382 #else |
|
383 act.sa_handler = FatalSignalHandler; |
|
384 #endif |
|
385 sigfillset(&act.sa_mask); |
|
386 |
|
387 #define CATCH_SIGNAL(signame) \ |
|
388 PR_BEGIN_MACRO \ |
|
389 if (sigaction(signame, nullptr, &oldact) == 0 && \ |
|
390 oldact.sa_handler != SIG_IGN) \ |
|
391 { \ |
|
392 sigaction(signame, &act, &signame##_oldact); \ |
|
393 } \ |
|
394 PR_END_MACRO |
|
395 |
|
396 CATCH_SIGNAL(SIGHUP); |
|
397 CATCH_SIGNAL(SIGINT); |
|
398 CATCH_SIGNAL(SIGQUIT); |
|
399 CATCH_SIGNAL(SIGILL); |
|
400 CATCH_SIGNAL(SIGABRT); |
|
401 CATCH_SIGNAL(SIGSEGV); |
|
402 CATCH_SIGNAL(SIGTERM); |
|
403 |
|
404 #undef CATCH_SIGNAL |
|
405 } |
|
406 } |
|
407 } |
|
408 } |
|
409 else if (symlink_errno == EEXIST) |
|
410 rv = NS_ERROR_FILE_ACCESS_DENIED; |
|
411 else |
|
412 { |
|
413 #ifdef DEBUG |
|
414 printf("symlink() failed. errno = %d\n", errno); |
|
415 #endif |
|
416 rv = NS_ERROR_FAILURE; |
|
417 } |
|
418 return rv; |
|
419 } |
|
420 #endif /* XP_UNIX */ |
|
421 |
|
422 nsresult nsProfileLock::GetReplacedLockTime(PRTime *aResult) { |
|
423 *aResult = mReplacedLockTime; |
|
424 return NS_OK; |
|
425 } |
|
426 |
|
427 nsresult nsProfileLock::Lock(nsIFile* aProfileDir, |
|
428 nsIProfileUnlocker* *aUnlocker) |
|
429 { |
|
430 #if defined (XP_MACOSX) |
|
431 NS_NAMED_LITERAL_STRING(LOCKFILE_NAME, ".parentlock"); |
|
432 NS_NAMED_LITERAL_STRING(OLD_LOCKFILE_NAME, "parent.lock"); |
|
433 #elif defined (XP_UNIX) |
|
434 NS_NAMED_LITERAL_STRING(OLD_LOCKFILE_NAME, "lock"); |
|
435 NS_NAMED_LITERAL_STRING(LOCKFILE_NAME, ".parentlock"); |
|
436 #else |
|
437 NS_NAMED_LITERAL_STRING(LOCKFILE_NAME, "parent.lock"); |
|
438 #endif |
|
439 |
|
440 nsresult rv; |
|
441 if (aUnlocker) |
|
442 *aUnlocker = nullptr; |
|
443 |
|
444 NS_ENSURE_STATE(!mHaveLock); |
|
445 |
|
446 bool isDir; |
|
447 rv = aProfileDir->IsDirectory(&isDir); |
|
448 if (NS_FAILED(rv)) |
|
449 return rv; |
|
450 if (!isDir) |
|
451 return NS_ERROR_FILE_NOT_DIRECTORY; |
|
452 |
|
453 nsCOMPtr<nsIFile> lockFile; |
|
454 rv = aProfileDir->Clone(getter_AddRefs(lockFile)); |
|
455 if (NS_FAILED(rv)) |
|
456 return rv; |
|
457 |
|
458 rv = lockFile->Append(LOCKFILE_NAME); |
|
459 if (NS_FAILED(rv)) |
|
460 return rv; |
|
461 |
|
462 #if defined(XP_MACOSX) |
|
463 // First, try locking using fcntl. It is more reliable on |
|
464 // a local machine, but may not be supported by an NFS server. |
|
465 |
|
466 rv = LockWithFcntl(lockFile); |
|
467 if (NS_FAILED(rv) && (rv != NS_ERROR_FILE_ACCESS_DENIED)) |
|
468 { |
|
469 // If that failed for any reason other than NS_ERROR_FILE_ACCESS_DENIED, |
|
470 // assume we tried an NFS that does not support it. Now, try with symlink. |
|
471 rv = LockWithSymlink(lockFile, false); |
|
472 } |
|
473 |
|
474 if (NS_SUCCEEDED(rv)) |
|
475 { |
|
476 // Check for the old-style lock used by pre-mozilla 1.3 builds. |
|
477 // Those builds used an earlier check to prevent the application |
|
478 // from launching if another instance was already running. Because |
|
479 // of that, we don't need to create an old-style lock as well. |
|
480 struct LockProcessInfo |
|
481 { |
|
482 ProcessSerialNumber psn; |
|
483 unsigned long launchDate; |
|
484 }; |
|
485 |
|
486 PRFileDesc *fd = nullptr; |
|
487 int32_t ioBytes; |
|
488 ProcessInfoRec processInfo; |
|
489 LockProcessInfo lockProcessInfo; |
|
490 |
|
491 rv = lockFile->SetLeafName(OLD_LOCKFILE_NAME); |
|
492 if (NS_FAILED(rv)) |
|
493 return rv; |
|
494 rv = lockFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd); |
|
495 if (NS_SUCCEEDED(rv)) |
|
496 { |
|
497 ioBytes = PR_Read(fd, &lockProcessInfo, sizeof(LockProcessInfo)); |
|
498 PR_Close(fd); |
|
499 |
|
500 if (ioBytes == sizeof(LockProcessInfo)) |
|
501 { |
|
502 #ifdef __LP64__ |
|
503 processInfo.processAppRef = nullptr; |
|
504 #else |
|
505 processInfo.processAppSpec = nullptr; |
|
506 #endif |
|
507 processInfo.processName = nullptr; |
|
508 processInfo.processInfoLength = sizeof(ProcessInfoRec); |
|
509 if (::GetProcessInformation(&lockProcessInfo.psn, &processInfo) == noErr && |
|
510 processInfo.processLaunchDate == lockProcessInfo.launchDate) |
|
511 { |
|
512 return NS_ERROR_FILE_ACCESS_DENIED; |
|
513 } |
|
514 } |
|
515 else |
|
516 { |
|
517 NS_WARNING("Could not read lock file - ignoring lock"); |
|
518 } |
|
519 } |
|
520 rv = NS_OK; // Don't propagate error from OpenNSPRFileDesc. |
|
521 } |
|
522 #elif defined(XP_UNIX) |
|
523 // Get the old lockfile name |
|
524 nsCOMPtr<nsIFile> oldLockFile; |
|
525 rv = aProfileDir->Clone(getter_AddRefs(oldLockFile)); |
|
526 if (NS_FAILED(rv)) |
|
527 return rv; |
|
528 rv = oldLockFile->Append(OLD_LOCKFILE_NAME); |
|
529 if (NS_FAILED(rv)) |
|
530 return rv; |
|
531 |
|
532 // First, try locking using fcntl. It is more reliable on |
|
533 // a local machine, but may not be supported by an NFS server. |
|
534 rv = LockWithFcntl(lockFile); |
|
535 if (NS_SUCCEEDED(rv)) { |
|
536 // Check to see whether there is a symlink lock held by an older |
|
537 // Firefox build, and also place our own symlink lock --- but |
|
538 // mark it "obsolete" so that other newer builds can break the lock |
|
539 // if they obtain the fcntl lock |
|
540 rv = LockWithSymlink(oldLockFile, true); |
|
541 |
|
542 // If the symlink failed for some reason other than it already |
|
543 // exists, then something went wrong e.g. the file system |
|
544 // doesn't support symlinks, or we don't have permission to |
|
545 // create a symlink there. In such cases we should just |
|
546 // continue because it's unlikely there is an old build |
|
547 // running with a symlink there and we've already successfully |
|
548 // placed a fcntl lock. |
|
549 if (rv != NS_ERROR_FILE_ACCESS_DENIED) |
|
550 rv = NS_OK; |
|
551 } |
|
552 else if (rv != NS_ERROR_FILE_ACCESS_DENIED) |
|
553 { |
|
554 // If that failed for any reason other than NS_ERROR_FILE_ACCESS_DENIED, |
|
555 // assume we tried an NFS that does not support it. Now, try with symlink |
|
556 // using the old symlink path |
|
557 rv = LockWithSymlink(oldLockFile, false); |
|
558 } |
|
559 |
|
560 #elif defined(XP_WIN) |
|
561 nsAutoString filePath; |
|
562 rv = lockFile->GetPath(filePath); |
|
563 if (NS_FAILED(rv)) |
|
564 return rv; |
|
565 |
|
566 lockFile->GetLastModifiedTime(&mReplacedLockTime); |
|
567 |
|
568 // always create the profile lock and never delete it so we can use its |
|
569 // modification timestamp to detect startup crashes |
|
570 mLockFileHandle = CreateFileW(filePath.get(), |
|
571 GENERIC_READ | GENERIC_WRITE, |
|
572 0, // no sharing - of course |
|
573 nullptr, |
|
574 CREATE_ALWAYS, |
|
575 0, |
|
576 nullptr); |
|
577 if (mLockFileHandle == INVALID_HANDLE_VALUE) { |
|
578 // XXXbsmedberg: provide a profile-unlocker here! |
|
579 return NS_ERROR_FILE_ACCESS_DENIED; |
|
580 } |
|
581 #elif defined(VMS) |
|
582 nsAutoCString filePath; |
|
583 rv = lockFile->GetNativePath(filePath); |
|
584 if (NS_FAILED(rv)) |
|
585 return rv; |
|
586 |
|
587 lockFile->GetLastModifiedTime(&mReplacedLockTime); |
|
588 |
|
589 mLockFileDesc = open_noshr(filePath.get(), O_CREAT, 0666); |
|
590 if (mLockFileDesc == -1) |
|
591 { |
|
592 if ((errno == EVMSERR) && (vaxc$errno == RMS$_FLK)) |
|
593 { |
|
594 return NS_ERROR_FILE_ACCESS_DENIED; |
|
595 } |
|
596 else |
|
597 { |
|
598 NS_ERROR("Failed to open lock file."); |
|
599 return NS_ERROR_FAILURE; |
|
600 } |
|
601 } |
|
602 #endif |
|
603 |
|
604 mHaveLock = true; |
|
605 |
|
606 return rv; |
|
607 } |
|
608 |
|
609 |
|
610 nsresult nsProfileLock::Unlock(bool aFatalSignal) |
|
611 { |
|
612 nsresult rv = NS_OK; |
|
613 |
|
614 if (mHaveLock) |
|
615 { |
|
616 #if defined (XP_WIN) |
|
617 if (mLockFileHandle != INVALID_HANDLE_VALUE) |
|
618 { |
|
619 CloseHandle(mLockFileHandle); |
|
620 mLockFileHandle = INVALID_HANDLE_VALUE; |
|
621 } |
|
622 #elif defined (XP_UNIX) |
|
623 if (mPidLockFileName) |
|
624 { |
|
625 PR_REMOVE_LINK(this); |
|
626 (void) unlink(mPidLockFileName); |
|
627 |
|
628 // Only free mPidLockFileName if we're not in the fatal signal |
|
629 // handler. The problem is that a call to free() might be the |
|
630 // cause of this fatal signal. If so, calling free() might cause |
|
631 // us to wait on the malloc implementation's lock. We're already |
|
632 // holding this lock, so we'll deadlock. See bug 522332. |
|
633 if (!aFatalSignal) |
|
634 free(mPidLockFileName); |
|
635 mPidLockFileName = nullptr; |
|
636 } |
|
637 if (mLockFileDesc != -1) |
|
638 { |
|
639 close(mLockFileDesc); |
|
640 mLockFileDesc = -1; |
|
641 // Don't remove it |
|
642 } |
|
643 #endif |
|
644 |
|
645 mHaveLock = false; |
|
646 } |
|
647 |
|
648 return rv; |
|
649 } |