#include "logging.h"
#include "virterror_internal.h"
#include "c-ctype.h"
+#include "areadlink.h"
#define VIR_FROM_THIS VIR_FROM_NONE
*/
int virPidFileReadPathIfAlive(const char *path,
pid_t *pid,
- const char *binpath)
+ const char *binPath)
{
- int rc;
- char *procpath = NULL;
+ int ret, retPid;
+ bool isLink;
+ char *procPath = NULL;
+ char *procLink = NULL;
+ size_t procLinkLen;
+ char *resolvedBinPath = NULL;
+ char *resolvedProcLink = NULL;
+ const char deletedText[] = " (deleted)";
+ size_t deletedTextLen = strlen(deletedText);
+
- rc = virPidFileReadPath(path, pid);
- if (rc < 0)
- return rc;
+ /* only set this at the very end on success */
+ *pid = -1;
+
+ if ((ret = virPidFileReadPath(path, &retPid)) < 0)
+ goto cleanup;
#ifndef WIN32
/* Check that it's still alive. Safe to skip this sanity check on
* mingw, which lacks kill(). */
- if (kill(*pid, 0) < 0) {
- *pid = -1;
- return 0;
+ if (kill(retPid, 0) < 0) {
+ ret = 0;
+ retPid = -1;
+ goto cleanup;
}
#endif
- if (binpath) {
- if (virAsprintf(&procpath, "/proc/%lld/exe", (long long)*pid) < 0) {
- *pid = -1;
- return -1;
- }
+ if (!binPath) {
+ /* we only knew the pid, and that pid is alive, so we can
+ * return it.
+ */
+ ret = 0;
+ goto cleanup;
+ }
+
+ if (virAsprintf(&procPath, "/proc/%lld/exe", (long long)retPid) < 0) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
- if (virFileIsLink(procpath) &&
- virFileLinkPointsTo(procpath, binpath) == 0)
- *pid = -1;
+ if ((ret = virFileIsLink(procPath)) < 0)
+ goto cleanup;
+ isLink = ret;
- VIR_FREE(procpath);
+ if (isLink && virFileLinkPointsTo(procPath, binPath)) {
+ /* the link in /proc/$pid/exe is a symlink to a file
+ * that has the same inode as the file at binpath.
+ */
+ ret = 0;
+ goto cleanup;
}
- return 0;
+ /* Even if virFileLinkPointsTo returns a mismatch, it could be
+ * that the binary was deleted/replaced after it was executed. In
+ * that case the link in /proc/$pid/exe will contain
+ * "$procpath (deleted)". Read that link, remove the " (deleted)"
+ * part, and see if it has the same canonicalized name as binpath.
+ */
+ if (!(procLink = areadlink(procPath))) {
+ ret = -errno;
+ goto cleanup;
+ }
+ procLinkLen = strlen(procLink);
+ if (procLinkLen > deletedTextLen)
+ procLink[procLinkLen - deletedTextLen] = 0;
+
+ if ((ret = virFileResolveAllLinks(binPath, &resolvedBinPath)) < 0)
+ goto cleanup;
+ if ((ret = virFileResolveAllLinks(procLink, &resolvedProcLink)) < 0)
+ goto cleanup;
+
+ ret = STREQ(resolvedBinPath, resolvedProcLink) ? 0 : -1;
+
+cleanup:
+ VIR_FREE(procPath);
+ VIR_FREE(procLink);
+ VIR_FREE(resolvedProcLink);
+ VIR_FREE(resolvedBinPath);
+
+ /* return the originally set pid of -1 unless we proclaim success */
+ if (ret == 0)
+ *pid = retPid;
+ return ret;
}