| | |
| | | char pidFile[PATH_SIZE]; |
| | | FILE *f; |
| | | char buf[BUF_SIZE]; |
| | | int read; |
| | | size_t nRead; |
| | | |
| | | debug("Attempting to get the PID for the server rooted at '%s'.", instanceDir); |
| | | if (getPidFile(instanceDir, pidFile, PATH_SIZE)) |
| | | { |
| | | if ((f = fopen(pidFile, "r")) != NULL) |
| | | { |
| | | read = fread(buf, 1, sizeof(buf),f); |
| | | debug("Read '%s' from the PID file '%s'.", buf, pidFile); |
| | | } |
| | | |
| | | if (f != NULL) |
| | | { |
| | | nRead = fread(buf, 1, sizeof(buf) - 1, f); |
| | | fclose(f); |
| | | buf[nRead] = '\0'; |
| | | if (nRead > 0) |
| | | { |
| | | debug("Read '%s' from the PID file '%s'.", buf, pidFile); |
| | | returnValue = (int)strtol(buf, (char **)NULL, 10); |
| | | } |
| | | else |
| | | { |
| | | debugError("The PID file '%s' is empty.", pidFile); |
| | | returnValue = 0; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | char * msg = "File %s could not be opened.\nMost likely the server has already stopped.\n\n"; |
| | | debug(msg, pidFile); |
| | | fprintf(stderr, msg, pidFile); |
| | |
| | | |
| | | if (procHandle == NULL) |
| | | { |
| | | DWORD lastError = GetLastError(); |
| | | if (lastError == ERROR_INVALID_PARAMETER) |
| | | { |
| | | // no process with this pid exists: it has already terminated |
| | | debug("The process with pid=%d has already terminated.", pid); |
| | | // process already dead |
| | | processDead = TRUE; |
| | | } |
| | | else |
| | | { |
| | | // Access denied or any other error: the process may well still be |
| | | // running, so it must not be reported as stopped. |
| | | debugError("Failed to open the process (pid=%d) lastError=%d.", pid, lastError); |
| | | processDead = FALSE; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | if (!TerminateProcess(procHandle, 0)) |
| | | { |
| | | debugError("Failed to terminate process (pid=%d) lastError=%d.", pid, GetLastError()); |
| | |
| | | // immediately. |
| | | if ((fopen_s(&f, pidFile, "w") == 0) && (f != NULL)) |
| | | { |
| | | fprintf(f, "%d", pid); |
| | | fprintf(f, "%d\n", pid); |
| | | fclose (f); |
| | | returnValue = TRUE; |
| | | debug("Successfully put pid=%d in the pid file '%s'.", pid, pidFile); |
| | |
| | | |
| | | |
| | | // ---------------------------------------------------- |
| | | // Waits until the exclusive lock that the server holds on |
| | | // locks\server.lock has been released, which is the definitive sign |
| | | // that the server process is gone (the pid in the pid file may be |
| | | // stale and belong to another process, so the outcome of killProcess |
| | | // alone is not proof that the server was stopped). |
| | | // Only a lock conflict (EACCES) is proof that the server still runs: |
| | | // like isServerRunning in service.c, a lock file that cannot be opened |
| | | // or an unexpected locking error is not treated as a running server. |
| | | // Returns TRUE if the server no longer holds the lock (or holding it |
| | | // cannot be proven) and FALSE if the lock conflict persists after the |
| | | // bounded retries. |
| | | // ---------------------------------------------------- |
| | | BOOL waitForLockRelease(const char* instanceDir) |
| | | { |
| | | char lockFile[PATH_SIZE]; |
| | | char* relativePath = "\\locks\\server.lock"; |
| | | int nTries = 30; |
| | | |
| | | if (!isSafePath(instanceDir) |
| | | || (strlen(relativePath) + strlen(instanceDir)) >= PATH_SIZE) |
| | | { |
| | | debugError("Unable to get the lock file name for instanceDir='%s'.", instanceDir); |
| | | return FALSE; |
| | | } |
| | | _snprintf(lockFile, PATH_SIZE, "%s%s", instanceDir, relativePath); |
| | | |
| | | while (nTries > 0) |
| | | { |
| | | int fd; |
| | | int lockingError; |
| | | if (!fileExists(lockFile)) |
| | | { |
| | | debug("Lock file '%s' does not exist, so the server is stopped.", lockFile); |
| | | return TRUE; |
| | | } |
| | | fd = _open(lockFile, _O_RDWR); |
| | | if (fd == -1) |
| | | { |
| | | debug("Could not open the lock file '%s' (errno=%d), so the server is considered stopped.", |
| | | lockFile, errno); |
| | | return TRUE; |
| | | } |
| | | if (_locking(fd, LK_NBLCK, 1) != -1) |
| | | { |
| | | _locking(fd, LK_UNLCK, 1); |
| | | _close(fd); |
| | | debug("Acquired the lock on '%s', so the server is stopped.", lockFile); |
| | | return TRUE; |
| | | } |
| | | lockingError = errno; |
| | | _close(fd); |
| | | if (lockingError != EACCES) |
| | | { |
| | | debugError("Unexpected error locking '%s': %d", lockFile, lockingError); |
| | | return TRUE; |
| | | } |
| | | nTries--; |
| | | debug("The server still holds the lock on '%s'. Sleeping for 1 second and will try %d more time(s).", |
| | | lockFile, nTries); |
| | | Sleep(1000); |
| | | } |
| | | |
| | | debugError("The server did not release the lock on '%s'.", lockFile); |
| | | return FALSE; |
| | | } // waitForLockRelease |
| | | |
| | | |
| | | // ---------------------------------------------------- |
| | | // Function called when we want to stop the server. |
| | | // This code is called by the stop-ds.bat batch file to stop the server |
| | | // in windows. |
| | |
| | | // sets the pid file to be deleted on the exit of the process |
| | | // the file is not always deleted. |
| | | // |
| | | // Returns 0 if the instance could be stopped using the |
| | | // pid stored in a file of the server installation and |
| | | // -1 otherwise. |
| | | // Returns 0 if the server no longer holds the server lock (the process |
| | | // found in the pid file, if any, was killed and the lock was released) |
| | | // and -1 otherwise. |
| | | // ---------------------------------------------------- |
| | | int stop(const char* instanceDir) |
| | | { |
| | | int returnCode = -1; |
| | | BOOL mayHaveStopped = FALSE; |
| | | |
| | | int childPid; |
| | | |
| | |
| | | |
| | | if (childPid != 0) |
| | | { |
| | | if (killProcess(childPid)) |
| | | mayHaveStopped = killProcess(childPid); |
| | | } |
| | | else |
| | | { |
| | | // The pid file is typically missing because the server has already |
| | | // stopped (or is stopping right now): the lock probe below gives the |
| | | // definitive answer. |
| | | debug("Could not locate the pid of the server running at root '%s': relying on the server lock alone.", instanceDir); |
| | | mayHaveStopped = TRUE; |
| | | } |
| | | |
| | | if (mayHaveStopped) |
| | | { |
| | | if (waitForLockRelease(instanceDir)) |
| | | { |
| | | returnCode = 0; |
| | | if (childPid != 0) |
| | | { |
| | | deletePidFile(instanceDir); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | debug("Could not stop the server running at root '%s' because the pid could not be located.", instanceDir); |
| | | char * msg = "The server at '%s' is still running: it did not release the server lock.\n"; |
| | | debugError(msg, instanceDir); |
| | | fprintf(stderr, msg, instanceDir); |
| | | } |
| | | } |
| | | |
| | | return returnCode; |