Changeset 33602 in vbox for trunk/src/VBox/Runtime/r3/posix
- Timestamp:
- Oct 29, 2010 12:39:54 PM (14 years ago)
- svn:sync-xref-src-repo-rev:
- 67213
- Location:
- trunk/src/VBox/Runtime/r3/posix
- Files:
-
- 2 edited
- 2 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r3/posix/RTPathUserHome-posix.cpp
r33593 r33602 47 47 #include <iprt/log.h> 48 48 #include "internal/path.h" 49 #include "internal/process.h"50 49 #include "internal/fs.h" 51 52 #ifdef RT_OS_L453 # include <l4/vboxserver/vboxserver.h>54 #endif55 56 57 58 59 RTDECL(int) RTPathReal(const char *pszPath, char *pszRealPath, size_t cchRealPath)60 {61 /*62 * Convert input.63 */64 char const *pszNativePath;65 int rc = rtPathToNative(&pszNativePath, pszPath, NULL);66 if (RT_SUCCESS(rc))67 {68 /*69 * On POSIX platforms the API doesn't take a length parameter, which makes it70 * a little bit more work.71 */72 char szTmpPath[PATH_MAX + 1];73 const char *psz = realpath(pszNativePath, szTmpPath);74 if (psz)75 rc = rtPathFromNativeCopy(pszRealPath, cchRealPath, szTmpPath, NULL);76 else77 rc = RTErrConvertFromErrno(errno);78 rtPathFreeNative(pszNativePath, pszPath);79 }80 81 LogFlow(("RTPathReal(%p:{%s}, %p:{%s}, %u): returns %Rrc\n", pszPath, pszPath,82 pszRealPath, RT_SUCCESS(rc) ? pszRealPath : "<failed>", cchRealPath));83 return rc;84 }85 86 87 /**88 * Cleans up a path specifier a little bit.89 * This includes removing duplicate slashes, unnecessary single dots, and90 * trailing slashes. Also, replaces all RTPATH_SLASH characters with '/'.91 *92 * @returns Number of bytes in the clean path.93 * @param pszPath The path to cleanup.94 */95 static int fsCleanPath(char *pszPath)96 {97 /*98 * Change to '/' and remove duplicates.99 */100 char *pszSrc = pszPath;101 char *pszTrg = pszPath;102 #ifdef HAVE_UNC103 int fUnc = 0;104 if ( RTPATH_IS_SLASH(pszPath[0])105 && RTPATH_IS_SLASH(pszPath[1]))106 { /* Skip first slash in a unc path. */107 pszSrc++;108 *pszTrg++ = '/';109 fUnc = 1;110 }111 #endif112 113 for (;;)114 {115 char ch = *pszSrc++;116 if (RTPATH_IS_SLASH(ch))117 {118 *pszTrg++ = '/';119 for (;;)120 {121 do ch = *pszSrc++;122 while (RTPATH_IS_SLASH(ch));123 124 /* Remove '/./' and '/.'. */125 if (ch != '.' || (*pszSrc && !RTPATH_IS_SLASH(*pszSrc)))126 break;127 }128 }129 *pszTrg = ch;130 if (!ch)131 break;132 pszTrg++;133 }134 135 /*136 * Remove trailing slash if the path may be pointing to a directory.137 */138 int cch = pszTrg - pszPath;139 if ( cch > 1140 && RTPATH_IS_SLASH(pszTrg[-1])141 #ifdef HAVE_DRIVE142 && !RTPATH_IS_VOLSEP(pszTrg[-2])143 #endif144 && !RTPATH_IS_SLASH(pszTrg[-2]))145 pszPath[--cch] = '\0';146 147 return cch;148 }149 150 151 RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath)152 {153 int rc;154 155 /*156 * Validation.157 */158 AssertPtr(pszAbsPath);159 AssertPtr(pszPath);160 if (RT_UNLIKELY(!*pszPath))161 return VERR_INVALID_PARAMETER;162 163 /*164 * Make a clean working copy of the input.165 */166 size_t cchPath = strlen(pszPath);167 if (cchPath > PATH_MAX)168 {169 LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));170 return VERR_FILENAME_TOO_LONG;171 }172 173 char szTmpPath[PATH_MAX + 1];174 memcpy(szTmpPath, pszPath, cchPath + 1);175 size_t cchTmpPath = fsCleanPath(szTmpPath);176 177 /*178 * Handle "." specially (fsCleanPath does).179 */180 if (szTmpPath[0] == '.' && !szTmpPath[1])181 return RTPathGetCurrent(pszAbsPath, cchAbsPath);182 183 /*184 * Do we have a root slash?185 */186 char *pszCur = szTmpPath;187 #ifdef HAVE_DRIVE188 if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == '/')189 pszCur += 3;190 # ifdef HAVE_UNC191 else if (pszCur[0] == '/' && pszCur[1] == '/')192 pszCur += 2;193 # endif194 #else /* !HAVE_DRIVE */195 if (pszCur[0] == '/')196 pszCur += 1;197 #endif /* !HAVE_DRIVE */198 else199 {200 /*201 * No, prepend the current directory to the relative path.202 */203 char szCurDir[RTPATH_MAX];204 rc = RTPathGetCurrent(szCurDir, sizeof(szCurDir));205 AssertRCReturn(rc, rc);206 207 size_t cchCurDir = fsCleanPath(szCurDir); /* paranoia */208 if (cchCurDir + cchTmpPath + 1 > PATH_MAX)209 {210 LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));211 return VERR_FILENAME_TOO_LONG;212 }213 214 memmove(szTmpPath + cchCurDir + 1, szTmpPath, cchTmpPath + 1);215 memcpy(szTmpPath, szCurDir, cchCurDir);216 szTmpPath[cchCurDir] = '/';217 218 219 #ifdef HAVE_DRIVE220 if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == '/')221 pszCur += 3;222 # ifdef HAVE_UNC223 else if (pszCur[0] == '/' && pszCur[1] == '/')224 pszCur += 2;225 # endif226 #else227 if (pszCur[0] == '/')228 pszCur += 1;229 #endif230 else231 AssertMsgFailedReturn(("pszCur=%s\n", pszCur), VERR_INTERNAL_ERROR);232 }233 234 char *pszTop = pszCur;235 236 /*237 * Get rid of double dot path components by evaluating them.238 */239 for (;;)240 {241 if ( pszCur[0] == '.'242 && pszCur[1] == '.'243 && (!pszCur[2] || pszCur[2] == '/'))244 {245 /* rewind to the previous component if any */246 char *pszPrev = pszCur - 1;247 if (pszPrev > pszTop)248 while (*--pszPrev != '/')249 ;250 251 AssertMsg(*pszPrev == '/', ("szTmpPath={%s}, pszPrev=+%u\n", szTmpPath, pszPrev - szTmpPath));252 memmove(pszPrev, pszCur + 2, strlen(pszCur + 2) + 1);253 254 pszCur = pszPrev;255 }256 else257 {258 /* advance to end of component. */259 while (*pszCur && *pszCur != '/')260 pszCur++;261 }262 263 if (!*pszCur)264 break;265 266 /* skip the slash */267 ++pszCur;268 }269 270 if (pszCur < pszTop)271 {272 /*273 * We overwrote the root slash with '\0', restore it.274 */275 *pszCur++ = '/';276 *pszCur = '\0';277 }278 else if (pszCur > pszTop && pszCur[-1] == '/')279 {280 /*281 * Extra trailing slash in a non-root path, remove it.282 * (A bit questionable...)283 */284 *--pszCur = '\0';285 }286 287 /*288 * Copy the result to the user buffer.289 */290 cchTmpPath = pszCur - szTmpPath;291 if (cchTmpPath < cchAbsPath)292 {293 memcpy(pszAbsPath, szTmpPath, cchTmpPath + 1);294 rc = VINF_SUCCESS;295 }296 else297 rc = VERR_BUFFER_OVERFLOW;298 299 LogFlow(("RTPathAbs(%p:{%s}, %p:{%s}, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath,300 RT_SUCCESS(rc) ? pszAbsPath : "<failed>", cchAbsPath, rc));301 return rc;302 }303 50 304 51 … … 415 162 } 416 163 417 418 RTR3DECL(int) RTPathQueryInfo(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)419 {420 return RTPathQueryInfoEx(pszPath, pObjInfo, enmAdditionalAttribs, RTPATH_F_ON_LINK);421 }422 423 424 RTR3DECL(int) RTPathQueryInfoEx(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags)425 {426 /*427 * Validate input.428 */429 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);430 AssertReturn(*pszPath, VERR_INVALID_PARAMETER);431 AssertPtrReturn(pObjInfo, VERR_INVALID_POINTER);432 AssertMsgReturn( enmAdditionalAttribs >= RTFSOBJATTRADD_NOTHING433 && enmAdditionalAttribs <= RTFSOBJATTRADD_LAST,434 ("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs),435 VERR_INVALID_PARAMETER);436 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);437 438 /*439 * Convert the filename.440 */441 char const *pszNativePath;442 int rc = rtPathToNative(&pszNativePath, pszPath, NULL);443 if (RT_SUCCESS(rc))444 {445 struct stat Stat;446 if (fFlags & RTPATH_F_FOLLOW_LINK)447 rc = stat(pszNativePath, &Stat);448 else449 rc = lstat(pszNativePath, &Stat); /** @todo how doesn't have lstat again? */450 if (!rc)451 {452 rtFsConvertStatToObjInfo(pObjInfo, &Stat, pszPath, 0);453 switch (enmAdditionalAttribs)454 {455 case RTFSOBJATTRADD_EASIZE:456 /** @todo Use SGI extended attribute interface to query EA info. */457 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;458 pObjInfo->Attr.u.EASize.cb = 0;459 break;460 461 case RTFSOBJATTRADD_NOTHING:462 case RTFSOBJATTRADD_UNIX:463 Assert(pObjInfo->Attr.enmAdditional == RTFSOBJATTRADD_UNIX);464 break;465 466 default:467 AssertMsgFailed(("Impossible!\n"));468 return VERR_INTERNAL_ERROR;469 }470 }471 else472 rc = RTErrConvertFromErrno(errno);473 rtPathFreeNative(pszNativePath, pszPath);474 }475 476 LogFlow(("RTPathQueryInfo(%p:{%s}, pObjInfo=%p, %d): returns %Rrc\n",477 pszPath, pszPath, pObjInfo, enmAdditionalAttribs, rc));478 return rc;479 }480 481 482 RTR3DECL(int) RTPathSetTimes(const char *pszPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,483 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)484 {485 return RTPathSetTimesEx(pszPath, pAccessTime, pModificationTime, pChangeTime, pBirthTime, RTPATH_F_ON_LINK);486 }487 488 489 RTR3DECL(int) RTPathSetTimesEx(const char *pszPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,490 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime, uint32_t fFlags)491 {492 /*493 * Validate input.494 */495 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);496 AssertReturn(*pszPath, VERR_INVALID_PARAMETER);497 AssertPtrNullReturn(pAccessTime, VERR_INVALID_POINTER);498 AssertPtrNullReturn(pModificationTime, VERR_INVALID_POINTER);499 AssertPtrNullReturn(pChangeTime, VERR_INVALID_POINTER);500 AssertPtrNullReturn(pBirthTime, VERR_INVALID_POINTER);501 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);502 503 /*504 * Convert the paths.505 */506 char const *pszNativePath;507 int rc = rtPathToNative(&pszNativePath, pszPath, NULL);508 if (RT_SUCCESS(rc))509 {510 RTFSOBJINFO ObjInfo;511 512 /*513 * If it's a no-op, we'll only verify the existance of the file.514 */515 if (!pAccessTime && !pModificationTime)516 rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, fFlags);517 else518 {519 /*520 * Convert the input to timeval, getting the missing one if necessary,521 * and call the API which does the change.522 */523 struct timeval aTimevals[2];524 if (pAccessTime && pModificationTime)525 {526 RTTimeSpecGetTimeval(pAccessTime, &aTimevals[0]);527 RTTimeSpecGetTimeval(pModificationTime, &aTimevals[1]);528 }529 else530 {531 rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_UNIX, fFlags);532 if (RT_SUCCESS(rc))533 {534 RTTimeSpecGetTimeval(pAccessTime ? pAccessTime : &ObjInfo.AccessTime, &aTimevals[0]);535 RTTimeSpecGetTimeval(pModificationTime ? pModificationTime : &ObjInfo.ModificationTime, &aTimevals[1]);536 }537 else538 Log(("RTPathSetTimes('%s',%p,%p,,): RTPathQueryInfo failed with %Rrc\n",539 pszPath, pAccessTime, pModificationTime, rc));540 }541 if (RT_SUCCESS(rc))542 {543 if (fFlags & RTPATH_F_FOLLOW_LINK)544 {545 if (utimes(pszNativePath, aTimevals))546 rc = RTErrConvertFromErrno(errno);547 }548 #if (defined(RT_OS_DARWIN) && MAC_OS_X_VERSION_MIN_REQUIRED >= 1050) \549 || defined(RT_OS_FREEBSD) \550 || defined(RT_OS_LINUX) \551 || defined(RT_OS_OS2) /** @todo who really has lutimes? */552 else553 {554 if (lutimes(pszNativePath, aTimevals))555 rc = RTErrConvertFromErrno(errno);556 }557 #else558 else559 {560 if (pAccessTime && pModificationTime)561 rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_UNIX, fFlags);562 if (RT_SUCCESS(rc) && RTFS_IS_SYMLINK(ObjInfo.Attr.fMode))563 rc = VERR_NS_SYMLINK_SET_TIME;564 else if (RT_SUCCESS(rc))565 {566 if (utimes(pszNativePath, aTimevals))567 rc = RTErrConvertFromErrno(errno);568 }569 }570 #endif571 if (RT_FAILURE(rc))572 Log(("RTPathSetTimes('%s',%p,%p,,): failed with %Rrc and errno=%d\n",573 pszPath, pAccessTime, pModificationTime, rc, errno));574 }575 }576 rtPathFreeNative(pszNativePath, pszPath);577 }578 579 LogFlow(("RTPathSetTimes(%p:{%s}, %p:{%RDtimespec}, %p:{%RDtimespec}, %p:{%RDtimespec}, %p:{%RDtimespec}): return %Rrc\n",580 pszPath, pszPath, pAccessTime, pAccessTime, pModificationTime, pModificationTime,581 pChangeTime, pChangeTime, pBirthTime, pBirthTime, rc));582 return rc;583 }584 585 586 RTR3DECL(int) RTPathSetOwner(const char *pszPath, uint32_t uid, uint32_t gid)587 {588 return RTPathSetOwnerEx(pszPath, uid, gid, RTPATH_F_ON_LINK);589 }590 591 592 RTR3DECL(int) RTPathSetOwnerEx(const char *pszPath, uint32_t uid, uint32_t gid, uint32_t fFlags)593 {594 /*595 * Validate input.596 */597 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);598 AssertReturn(*pszPath, VERR_INVALID_PARAMETER);599 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);600 uid_t uidNative = uid != UINT32_MAX ? (uid_t)uid : (uid_t)-1;601 AssertReturn(uid == uidNative, VERR_INVALID_PARAMETER);602 gid_t gidNative = gid != UINT32_MAX ? (gid_t)gid : (uid_t)-1;603 AssertReturn(gid == gidNative, VERR_INVALID_PARAMETER);604 605 /*606 * Convert the path.607 */608 char const *pszNativePath;609 int rc = rtPathToNative(&pszNativePath, pszPath, NULL);610 if (RT_SUCCESS(rc))611 {612 if (fFlags & RTPATH_F_FOLLOW_LINK)613 {614 if (chown(pszNativePath, uidNative, gidNative))615 rc = RTErrConvertFromErrno(errno);616 }617 #if 1618 else619 {620 if (lchown(pszNativePath, uidNative, gidNative))621 rc = RTErrConvertFromErrno(errno);622 }623 #else624 else625 {626 RTFSOBJINFO ObjInfo;627 rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_UNIX, fFlags);628 if (RT_SUCCESS(rc) && RTFS_IS_SYMLINK(ObjInfo.Attr.fMode))629 rc = VERR_NS_SYMLINK_CHANGE_OWNER;630 else if (RT_SUCCESS(rc))631 {632 if (lchown(pszNativePath, uidNative, gidNative))633 rc = RTErrConvertFromErrno(errno);634 }635 }636 #endif637 if (RT_FAILURE(rc))638 Log(("RTPathSetOwnerEx('%s',%d,%d): failed with %Rrc and errno=%d\n",639 pszPath, uid, gid, rc, errno));640 641 rtPathFreeNative(pszNativePath, pszPath);642 }643 644 LogFlow(("RTPathSetOwnerEx(%p:{%s}, uid, gid): return %Rrc\n",645 pszPath, pszPath, uid, gid, rc));646 return rc;647 }648 649 650 RTR3DECL(int) RTPathSetMode(const char *pszPath, RTFMODE fMode)651 {652 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);653 AssertReturn(*pszPath, VERR_INVALID_PARAMETER);654 655 int rc;656 fMode = rtFsModeNormalize(fMode, pszPath, 0);657 if (rtFsModeIsValidPermissions(fMode))658 {659 char const *pszNativePath;660 rc = rtPathToNative(&pszNativePath, pszPath, NULL);661 if (RT_SUCCESS(rc))662 {663 if (chmod(pszNativePath, fMode & RTFS_UNIX_MASK) != 0)664 rc = RTErrConvertFromErrno(errno);665 rtPathFreeNative(pszNativePath, pszPath);666 }667 }668 else669 {670 AssertMsgFailed(("Invalid file mode! %RTfmode\n", fMode));671 rc = VERR_INVALID_FMODE;672 }673 return rc;674 }675 676 677 /**678 * Checks if two files are the one and same file.679 */680 static bool rtPathSame(const char *pszNativeSrc, const char *pszNativeDst)681 {682 struct stat SrcStat;683 if (stat(pszNativeSrc, &SrcStat))684 return false;685 struct stat DstStat;686 if (stat(pszNativeDst, &DstStat))687 return false;688 Assert(SrcStat.st_dev && DstStat.st_dev);689 Assert(SrcStat.st_ino && DstStat.st_ino);690 if ( SrcStat.st_dev == DstStat.st_dev691 && SrcStat.st_ino == DstStat.st_ino692 && (SrcStat.st_mode & S_IFMT) == (DstStat.st_mode & S_IFMT))693 return true;694 return false;695 }696 697 698 /**699 * Worker for RTPathRename, RTDirRename, RTFileRename.700 *701 * @returns IPRT status code.702 * @param pszSrc The source path.703 * @param pszDst The destination path.704 * @param fRename The rename flags.705 * @param fFileType The filetype. We use the RTFMODE filetypes here. If it's 0,706 * anything goes. If it's RTFS_TYPE_DIRECTORY we'll check that the707 * source is a directory. If Its RTFS_TYPE_FILE we'll check that it's708 * not a directory (we are NOT checking whether it's a file).709 */710 DECLHIDDEN(int) rtPathPosixRename(const char *pszSrc, const char *pszDst, unsigned fRename, RTFMODE fFileType)711 {712 /*713 * Convert the paths.714 */715 char const *pszNativeSrc;716 int rc = rtPathToNative(&pszNativeSrc, pszSrc, NULL);717 if (RT_SUCCESS(rc))718 {719 char const *pszNativeDst;720 rc = rtPathToNative(&pszNativeDst, pszDst, NULL);721 if (RT_SUCCESS(rc))722 {723 /*724 * Check that the source exists and that any types that's specified matches.725 * We have to check this first to avoid getting errnous VERR_ALREADY_EXISTS726 * errors from the next step.727 *728 * There are race conditions here (perhaps unlikely ones but still), but I'm729 * afraid there is little with can do to fix that.730 */731 struct stat SrcStat;732 if (stat(pszNativeSrc, &SrcStat))733 rc = RTErrConvertFromErrno(errno);734 else if (!fFileType)735 rc = VINF_SUCCESS;736 else if (RTFS_IS_DIRECTORY(fFileType))737 rc = S_ISDIR(SrcStat.st_mode) ? VINF_SUCCESS : VERR_NOT_A_DIRECTORY;738 else739 rc = S_ISDIR(SrcStat.st_mode) ? VERR_IS_A_DIRECTORY : VINF_SUCCESS;740 if (RT_SUCCESS(rc))741 {742 bool fSameFile = false;743 744 /*745 * Check if the target exists, rename is rather destructive.746 * We'll have to make sure we don't overwrite the source!747 * Another race condition btw.748 */749 struct stat DstStat;750 if (stat(pszNativeDst, &DstStat))751 rc = errno == ENOENT ? VINF_SUCCESS : RTErrConvertFromErrno(errno);752 else753 {754 Assert(SrcStat.st_dev && DstStat.st_dev);755 Assert(SrcStat.st_ino && DstStat.st_ino);756 if ( SrcStat.st_dev == DstStat.st_dev757 && SrcStat.st_ino == DstStat.st_ino758 && (SrcStat.st_mode & S_IFMT) == (DstStat.st_mode & S_IFMT))759 {760 /*761 * It's likely that we're talking about the same file here.762 * We should probably check paths or whatever, but for now this'll have to be enough.763 */764 fSameFile = true;765 }766 if (fSameFile)767 rc = VINF_SUCCESS;768 else if (S_ISDIR(DstStat.st_mode) || !(fRename & RTPATHRENAME_FLAGS_REPLACE))769 rc = VERR_ALREADY_EXISTS;770 else771 rc = VINF_SUCCESS;772 773 }774 if (RT_SUCCESS(rc))775 {776 if (!rename(pszNativeSrc, pszNativeDst))777 rc = VINF_SUCCESS;778 else if ( (fRename & RTPATHRENAME_FLAGS_REPLACE)779 && (errno == ENOTDIR || errno == EEXIST))780 {781 /*782 * Check that the destination isn't a directory.783 * Yet another race condition.784 */785 if (rtPathSame(pszNativeSrc, pszNativeDst))786 {787 rc = VINF_SUCCESS;788 Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): appears to be the same file... (errno=%d)\n",789 pszSrc, pszDst, fRename, fFileType, errno));790 }791 else792 {793 if (stat(pszNativeDst, &DstStat))794 rc = errno != ENOENT ? RTErrConvertFromErrno(errno) : VINF_SUCCESS;795 else if (S_ISDIR(DstStat.st_mode))796 rc = VERR_ALREADY_EXISTS;797 else798 rc = VINF_SUCCESS;799 if (RT_SUCCESS(rc))800 {801 if (!unlink(pszNativeDst))802 {803 if (!rename(pszNativeSrc, pszNativeDst))804 rc = VINF_SUCCESS;805 else806 {807 rc = RTErrConvertFromErrno(errno);808 Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): rename failed rc=%Rrc errno=%d\n",809 pszSrc, pszDst, fRename, fFileType, rc, errno));810 }811 }812 else813 {814 rc = RTErrConvertFromErrno(errno);815 Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): failed to unlink dst rc=%Rrc errno=%d\n",816 pszSrc, pszDst, fRename, fFileType, rc, errno));817 }818 }819 else820 Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): dst !dir check failed rc=%Rrc\n",821 pszSrc, pszDst, fRename, fFileType, rc));822 }823 }824 else825 {826 rc = RTErrConvertFromErrno(errno);827 if (errno == ENOTDIR)828 rc = VERR_ALREADY_EXISTS; /* unless somebody is racing us, this is the right interpretation */829 Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): rename failed rc=%Rrc errno=%d\n",830 pszSrc, pszDst, fRename, fFileType, rc, errno));831 }832 }833 else834 Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): destination check failed rc=%Rrc errno=%d\n",835 pszSrc, pszDst, fRename, fFileType, rc, errno));836 }837 else838 Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): source type check failed rc=%Rrc errno=%d\n",839 pszSrc, pszDst, fRename, fFileType, rc, errno));840 841 rtPathFreeNative(pszNativeDst, pszDst);842 }843 rtPathFreeNative(pszNativeSrc, pszSrc);844 }845 return rc;846 }847 848 849 RTR3DECL(int) RTPathRename(const char *pszSrc, const char *pszDst, unsigned fRename)850 {851 /*852 * Validate input.853 */854 AssertMsgReturn(VALID_PTR(pszSrc), ("%p\n", pszSrc), VERR_INVALID_POINTER);855 AssertMsgReturn(VALID_PTR(pszDst), ("%p\n", pszDst), VERR_INVALID_POINTER);856 AssertMsgReturn(*pszSrc, ("%p\n", pszSrc), VERR_INVALID_PARAMETER);857 AssertMsgReturn(*pszDst, ("%p\n", pszDst), VERR_INVALID_PARAMETER);858 AssertMsgReturn(!(fRename & ~RTPATHRENAME_FLAGS_REPLACE), ("%#x\n", fRename), VERR_INVALID_PARAMETER);859 860 /*861 * Hand it to the worker.862 */863 int rc = rtPathPosixRename(pszSrc, pszDst, fRename, 0);864 865 Log(("RTPathRename(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n", pszSrc, pszSrc, pszDst, pszDst, fRename, rc));866 return rc;867 }868 869 870 RTDECL(bool) RTPathExists(const char *pszPath)871 {872 return RTPathExistsEx(pszPath, RTPATH_F_FOLLOW_LINK);873 }874 875 876 RTDECL(bool) RTPathExistsEx(const char *pszPath, uint32_t fFlags)877 {878 /*879 * Validate input.880 */881 AssertPtrReturn(pszPath, false);882 AssertReturn(*pszPath, false);883 Assert(RTPATH_F_IS_VALID(fFlags, 0));884 885 /*886 * Convert the path and check if it exists using stat().887 */888 char const *pszNativePath;889 int rc = rtPathToNative(&pszNativePath, pszPath, NULL);890 if (RT_SUCCESS(rc))891 {892 struct stat Stat;893 if (fFlags & RTPATH_F_FOLLOW_LINK)894 rc = stat(pszNativePath, &Stat);895 else896 rc = lstat(pszNativePath, &Stat);897 if (!rc)898 rc = VINF_SUCCESS;899 else900 rc = VERR_GENERAL_FAILURE;901 rtPathFreeNative(pszNativePath, pszPath);902 }903 return RT_SUCCESS(rc);904 }905 906 907 RTDECL(int) RTPathGetCurrent(char *pszPath, size_t cchPath)908 {909 int rc;910 char szNativeCurDir[RTPATH_MAX];911 if (getcwd(szNativeCurDir, sizeof(szNativeCurDir)) != NULL)912 rc = rtPathFromNativeCopy(pszPath, cchPath, szNativeCurDir, NULL);913 else914 rc = RTErrConvertFromErrno(errno);915 return rc;916 }917 918 919 RTDECL(int) RTPathSetCurrent(const char *pszPath)920 {921 /*922 * Validate input.923 */924 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);925 AssertReturn(*pszPath, VERR_INVALID_PARAMETER);926 927 /*928 * Change the directory.929 */930 char const *pszNativePath;931 int rc = rtPathToNative(&pszNativePath, pszPath, NULL);932 if (RT_SUCCESS(rc))933 {934 if (chdir(pszNativePath))935 rc = RTErrConvertFromErrno(errno);936 rtPathFreeNative(pszNativePath, pszPath);937 }938 return rc;939 }940 -
trunk/src/VBox/Runtime/r3/posix/path-posix.cpp
r33540 r33602 299 299 LogFlow(("RTPathAbs(%p:{%s}, %p:{%s}, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, 300 300 RT_SUCCESS(rc) ? pszAbsPath : "<failed>", cchAbsPath, rc)); 301 return rc;302 }303 304 305 #ifndef RT_OS_L4306 /**307 * Worker for RTPathUserHome that looks up the home directory308 * using the getpwuid_r api.309 *310 * @returns IPRT status code.311 * @param pszPath The path buffer.312 * @param cchPath The size of the buffer.313 * @param uid The User ID to query the home directory of.314 */315 static int rtPathUserHomeByPasswd(char *pszPath, size_t cchPath, uid_t uid)316 {317 /*318 * The getpwuid_r function uses the passed in buffer to "allocate" any319 * extra memory it needs. On some systems we should probably use the320 * sysconf function to find the appropriate buffer size, but since it won't321 * work everywhere we'll settle with a 5KB buffer and ASSUME that it'll322 * suffice for even the lengthiest user descriptions...323 */324 char achBuffer[5120];325 struct passwd Passwd;326 struct passwd *pPasswd;327 memset(&Passwd, 0, sizeof(Passwd));328 int rc = getpwuid_r(uid, &Passwd, &achBuffer[0], sizeof(achBuffer), &pPasswd);329 if (rc != 0)330 return RTErrConvertFromErrno(rc);331 if (!pPasswd) /* uid not found in /etc/passwd */332 return VERR_PATH_NOT_FOUND;333 334 /*335 * Check that it isn't empty and that it exists.336 */337 struct stat st;338 if ( !pPasswd->pw_dir339 || !*pPasswd->pw_dir340 || stat(pPasswd->pw_dir, &st)341 || !S_ISDIR(st.st_mode))342 return VERR_PATH_NOT_FOUND;343 344 /*345 * Convert it to UTF-8 and copy it to the return buffer.346 */347 return rtPathFromNativeCopy(pszPath, cchPath, pPasswd->pw_dir, NULL);348 }349 #endif350 351 352 /**353 * Worker for RTPathUserHome that looks up the home directory354 * using the HOME environment variable.355 *356 * @returns IPRT status code.357 * @param pszPath The path buffer.358 * @param cchPath The size of the buffer.359 */360 static int rtPathUserHomeByEnv(char *pszPath, size_t cchPath)361 {362 /*363 * Get HOME env. var it and validate it's existance.364 */365 int rc = VERR_PATH_NOT_FOUND;366 const char *pszHome = RTEnvGet("HOME"); /** @todo Codeset confusion in RTEnv. */367 if (pszHome)368 369 {370 struct stat st;371 if ( !stat(pszHome, &st)372 && S_ISDIR(st.st_mode))373 rc = rtPathFromNativeCopy(pszPath, cchPath, pszHome, NULL);374 }375 return rc;376 }377 378 379 RTDECL(int) RTPathUserHome(char *pszPath, size_t cchPath)380 {381 int rc;382 #ifndef RT_OS_L4383 /*384 * We make an exception for the root user and use the system call385 * getpwuid_r to determine their initial home path instead of386 * reading it from the $HOME variable. This is because the $HOME387 * variable does not get changed by sudo (and possibly su and others)388 * which can cause root-owned files to appear in user's home folders.389 */390 uid_t uid = geteuid();391 if (!uid)392 rc = rtPathUserHomeByPasswd(pszPath, cchPath, uid);393 else394 rc = rtPathUserHomeByEnv(pszPath, cchPath);395 396 /*397 * On failure, retry using the alternative method.398 * (Should perhaps restrict the retry cases a bit more here...)399 */400 if ( RT_FAILURE(rc)401 && rc != VERR_BUFFER_OVERFLOW)402 {403 if (!uid)404 rc = rtPathUserHomeByEnv(pszPath, cchPath);405 else406 rc = rtPathUserHomeByPasswd(pszPath, cchPath, uid);407 }408 #else /* RT_OS_L4 */409 rc = rtPathUserHomeByEnv(pszPath, cchPath);410 #endif /* RT_OS_L4 */411 412 LogFlow(("RTPathUserHome(%p:{%s}, %u): returns %Rrc\n", pszPath,413 RT_SUCCESS(rc) ? pszPath : "<failed>", cchPath, rc));414 301 return rc; 415 302 } -
trunk/src/VBox/Runtime/r3/posix/process-creation-posix.cpp
r33593 r33602 1 1 /* $Id$ */ 2 2 /** @file 3 * IPRT - Process , POSIX.3 * IPRT - Process Creation, POSIX. 4 4 */ 5 5 … … 24 24 * terms and conditions of either the GPL or the CDDL or both. 25 25 */ 26 27 26 28 27 … … 614 613 615 614 616 RTR3DECL(int) RTProcWait(RTPROCESS Process, unsigned fFlags, PRTPROCSTATUS pProcStatus)617 {618 int rc;619 do rc = RTProcWaitNoResume(Process, fFlags, pProcStatus);620 while (rc == VERR_INTERRUPTED);621 return rc;622 }623 624 RTR3DECL(int) RTProcWaitNoResume(RTPROCESS Process, unsigned fFlags, PRTPROCSTATUS pProcStatus)625 {626 /*627 * Validate input.628 */629 if (Process <= 0)630 {631 AssertMsgFailed(("Invalid Process=%d\n", Process));632 return VERR_INVALID_PARAMETER;633 }634 if (fFlags & ~(RTPROCWAIT_FLAGS_NOBLOCK | RTPROCWAIT_FLAGS_BLOCK))635 {636 AssertMsgFailed(("Invalid flags %#x\n", fFlags));637 return VERR_INVALID_PARAMETER;638 }639 640 /*641 * Perform the wait.642 */643 int iStatus = 0;644 int rc = waitpid(Process, &iStatus, fFlags & RTPROCWAIT_FLAGS_NOBLOCK ? WNOHANG : 0);645 if (rc > 0)646 {647 /*648 * Fill in the status structure.649 */650 if (pProcStatus)651 {652 if (WIFEXITED(iStatus))653 {654 pProcStatus->enmReason = RTPROCEXITREASON_NORMAL;655 pProcStatus->iStatus = WEXITSTATUS(iStatus);656 }657 else if (WIFSIGNALED(iStatus))658 {659 pProcStatus->enmReason = RTPROCEXITREASON_SIGNAL;660 pProcStatus->iStatus = WTERMSIG(iStatus);661 }662 else663 {664 Assert(!WIFSTOPPED(iStatus));665 pProcStatus->enmReason = RTPROCEXITREASON_ABEND;666 pProcStatus->iStatus = iStatus;667 }668 }669 return VINF_SUCCESS;670 }671 672 /*673 * Child running?674 */675 if (!rc)676 {677 Assert(fFlags & RTPROCWAIT_FLAGS_NOBLOCK);678 return VERR_PROCESS_RUNNING;679 }680 681 /*682 * Figure out which error to return.683 */684 int iErr = errno;685 if (iErr == ECHILD)686 return VERR_PROCESS_NOT_FOUND;687 return RTErrConvertFromErrno(iErr);688 }689 690 691 RTR3DECL(int) RTProcTerminate(RTPROCESS Process)692 {693 if (!kill(Process, SIGKILL))694 return VINF_SUCCESS;695 return RTErrConvertFromErrno(errno);696 }697 698 699 RTR3DECL(uint64_t) RTProcGetAffinityMask()700 {701 // @todo702 return 1;703 }704 705 706 615 RTR3DECL(int) RTProcDaemonizeUsingFork(bool fNoChDir, bool fNoClose, const char *pszPidfile) 707 616 { -
trunk/src/VBox/Runtime/r3/posix/process-posix.cpp
r33135 r33602 37 37 #include <sys/stat.h> 38 38 #include <sys/wait.h> 39 #include <fcntl.h>40 39 #include <signal.h> 41 #if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)42 # include <crypt.h>43 # include <pwd.h>44 # include <shadow.h>45 #endif46 #if defined(RT_OS_LINUX) || defined(RT_OS_OS2)47 /* While Solaris has posix_spawn() of course we don't want to use it as48 * we need to have the child in a different process contract, no matter49 * whether it is started detached or not. */50 # define HAVE_POSIX_SPAWN 151 #endif52 #ifdef HAVE_POSIX_SPAWN53 # include <spawn.h>54 #endif55 #ifdef RT_OS_DARWIN56 # include <mach-o/dyld.h>57 #endif58 #ifdef RT_OS_SOLARIS59 # include <limits.h>60 # include <sys/ctfs.h>61 # include <sys/contract/process.h>62 # include <libcontract.h>63 #endif64 40 65 41 #include <iprt/process.h> … … 77 53 78 54 79 /**80 * Check the credentials and return the gid/uid of user.81 *82 * @param pszUser username83 * @param pszPasswd password84 * @param gid where to store the GID of the user85 * @param uid where to store the UID of the user86 * @returns IPRT status code87 */88 static int rtCheckCredentials(const char *pszUser, const char *pszPasswd, gid_t *gid, uid_t *uid)89 {90 #if defined(RT_OS_LINUX)91 struct passwd *pw;92 93 pw = getpwnam(pszUser);94 if (!pw)95 return VERR_PERMISSION_DENIED;96 97 if (!pszPasswd)98 pszPasswd = "";99 100 struct spwd *spwd;101 /* works only if /etc/shadow is accessible */102 spwd = getspnam(pszUser);103 if (spwd)104 pw->pw_passwd = spwd->sp_pwdp;105 106 /* be reentrant */107 struct crypt_data *data = (struct crypt_data*)RTMemTmpAllocZ(sizeof(*data));108 char *pszEncPasswd = crypt_r(pszPasswd, pw->pw_passwd, data);109 if (strcmp(pszEncPasswd, pw->pw_passwd))110 return VERR_PERMISSION_DENIED;111 RTMemTmpFree(data);112 113 *gid = pw->pw_gid;114 *uid = pw->pw_uid;115 return VINF_SUCCESS;116 117 #elif defined(RT_OS_SOLARIS)118 struct passwd *ppw, pw;119 char szBuf[1024];120 121 if (getpwnam_r(pszUser, &pw, szBuf, sizeof(szBuf), &ppw) != 0 || ppw == NULL)122 return VERR_PERMISSION_DENIED;123 124 if (!pszPasswd)125 pszPasswd = "";126 127 struct spwd spwd;128 char szPwdBuf[1024];129 /* works only if /etc/shadow is accessible */130 if (getspnam_r(pszUser, &spwd, szPwdBuf, sizeof(szPwdBuf)) != NULL)131 ppw->pw_passwd = spwd.sp_pwdp;132 133 char *pszEncPasswd = crypt(pszPasswd, ppw->pw_passwd);134 if (strcmp(pszEncPasswd, ppw->pw_passwd))135 return VERR_PERMISSION_DENIED;136 137 *gid = ppw->pw_gid;138 *uid = ppw->pw_uid;139 return VINF_SUCCESS;140 141 #else142 return VERR_PERMISSION_DENIED;143 #endif144 }145 146 147 #ifdef RT_OS_SOLARIS148 /** @todo the error reporting of the Solaris process contract code could be149 * a lot better, but essentially it is not meant to run into errors after150 * the debugging phase. */151 static int rtSolarisContractPreFork(void)152 {153 int templateFd = open64(CTFS_ROOT "/process/template", O_RDWR);154 if (templateFd < 0)155 return -1;156 157 /* Set template parameters and event sets. */158 if (ct_pr_tmpl_set_param(templateFd, CT_PR_PGRPONLY))159 {160 close(templateFd);161 return -1;162 }163 if (ct_pr_tmpl_set_fatal(templateFd, CT_PR_EV_HWERR))164 {165 close(templateFd);166 return -1;167 }168 if (ct_tmpl_set_critical(templateFd, 0))169 {170 close(templateFd);171 return -1;172 }173 if (ct_tmpl_set_informative(templateFd, CT_PR_EV_HWERR))174 {175 close(templateFd);176 return -1;177 }178 179 /* Make this the active template for the process. */180 if (ct_tmpl_activate(templateFd))181 {182 close(templateFd);183 return -1;184 }185 186 return templateFd;187 }188 189 static void rtSolarisContractPostForkChild(int templateFd)190 {191 if (templateFd == -1)192 return;193 194 /* Clear the active template. */195 ct_tmpl_clear(templateFd);196 close(templateFd);197 }198 199 static void rtSolarisContractPostForkParent(int templateFd, pid_t pid)200 {201 if (templateFd == -1)202 return;203 204 /* Clear the active template. */205 int cleared = ct_tmpl_clear(templateFd);206 close(templateFd);207 208 /* If the clearing failed or the fork failed there's nothing more to do. */209 if (cleared || pid <= 0)210 return;211 212 /* Look up the contract which was created by this thread. */213 int statFd = open64(CTFS_ROOT "/process/latest", O_RDONLY);214 if (statFd == -1)215 return;216 ct_stathdl_t statHdl;217 if (ct_status_read(statFd, CTD_COMMON, &statHdl))218 {219 close(statFd);220 return;221 }222 ctid_t ctId = ct_status_get_id(statHdl);223 ct_status_free(statHdl);224 close(statFd);225 if (ctId < 0)226 return;227 228 /* Abandon this contract we just created. */229 char ctlPath[PATH_MAX];230 size_t len = snprintf(ctlPath, sizeof(ctlPath),231 CTFS_ROOT "/process/%d/ctl", ctId);232 if (len >= sizeof(ctlPath))233 return;234 int ctlFd = open64(ctlPath, O_WRONLY);235 if (statFd == -1)236 return;237 if (ct_ctl_abandon(ctlFd) < 0)238 {239 close(ctlFd);240 return;241 }242 close(ctlFd);243 }244 245 #endif /* RT_OS_SOLARIS */246 247 248 RTR3DECL(int) RTProcCreate(const char *pszExec, const char * const *papszArgs, RTENV Env, unsigned fFlags, PRTPROCESS pProcess)249 {250 return RTProcCreateEx(pszExec, papszArgs, Env, fFlags,251 NULL, NULL, NULL, /* standard handles */252 NULL /*pszAsUser*/, NULL /* pszPassword*/,253 pProcess);254 }255 256 257 RTR3DECL(int) RTProcCreateEx(const char *pszExec, const char * const *papszArgs, RTENV hEnv, uint32_t fFlags,258 PCRTHANDLE phStdIn, PCRTHANDLE phStdOut, PCRTHANDLE phStdErr, const char *pszAsUser,259 const char *pszPassword, PRTPROCESS phProcess)260 {261 int rc;262 263 /*264 * Input validation265 */266 AssertPtrReturn(pszExec, VERR_INVALID_POINTER);267 AssertReturn(*pszExec, VERR_INVALID_PARAMETER);268 AssertReturn(!(fFlags & ~(RTPROC_FLAGS_DETACHED | RTPROC_FLAGS_SERVICE)), VERR_INVALID_PARAMETER);269 AssertReturn(!(fFlags & RTPROC_FLAGS_DETACHED) || !phProcess, VERR_INVALID_PARAMETER);270 AssertReturn(hEnv != NIL_RTENV, VERR_INVALID_PARAMETER);271 const char * const *papszEnv = RTEnvGetExecEnvP(hEnv);272 AssertPtrReturn(papszEnv, VERR_INVALID_HANDLE);273 AssertPtrReturn(papszArgs, VERR_INVALID_PARAMETER);274 /** @todo search the PATH (add flag for this). */275 AssertPtrNullReturn(pszAsUser, VERR_INVALID_POINTER);276 AssertReturn(!pszAsUser || *pszAsUser, VERR_INVALID_PARAMETER);277 AssertReturn(!pszPassword || pszAsUser, VERR_INVALID_PARAMETER);278 AssertPtrNullReturn(pszPassword, VERR_INVALID_POINTER);279 280 /*281 * Get the file descriptors for the handles we've been passed.282 */283 PCRTHANDLE paHandles[3] = { phStdIn, phStdOut, phStdErr };284 int aStdFds[3] = { -1, -1, -1 };285 for (int i = 0; i < 3; i++)286 {287 if (paHandles[i])288 {289 AssertPtrReturn(paHandles[i], VERR_INVALID_POINTER);290 switch (paHandles[i]->enmType)291 {292 case RTHANDLETYPE_FILE:293 aStdFds[i] = paHandles[i]->u.hFile != NIL_RTFILE294 ? (int)RTFileToNative(paHandles[i]->u.hFile)295 : -2 /* close it */;296 break;297 298 case RTHANDLETYPE_PIPE:299 aStdFds[i] = paHandles[i]->u.hPipe != NIL_RTPIPE300 ? (int)RTPipeToNative(paHandles[i]->u.hPipe)301 : -2 /* close it */;302 break;303 304 case RTHANDLETYPE_SOCKET:305 aStdFds[i] = paHandles[i]->u.hSocket != NIL_RTSOCKET306 ? (int)RTSocketToNative(paHandles[i]->u.hSocket)307 : -2 /* close it */;308 break;309 310 default:311 AssertMsgFailedReturn(("%d: %d\n", i, paHandles[i]->enmType), VERR_INVALID_PARAMETER);312 }313 /** @todo check the close-on-execness of these handles? */314 }315 }316 317 for (int i = 0; i < 3; i++)318 if (aStdFds[i] == i)319 aStdFds[i] = -1;320 321 for (int i = 0; i < 3; i++)322 AssertMsgReturn(aStdFds[i] < 0 || aStdFds[i] > i,323 ("%i := %i not possible because we're lazy\n", i, aStdFds[i]),324 VERR_NOT_SUPPORTED);325 326 /*327 * Resolve the user id if specified.328 */329 uid_t uid = ~(uid_t)0;330 gid_t gid = ~(gid_t)0;331 if (pszAsUser)332 {333 rc = rtCheckCredentials(pszAsUser, pszPassword, &gid, &uid);334 if (RT_FAILURE(rc))335 return rc;336 }337 338 /*339 * Check for execute access to the file.340 */341 if (access(pszExec, X_OK))342 {343 rc = RTErrConvertFromErrno(errno);344 AssertMsgFailed(("'%s' %Rrc!\n", pszExec, rc));345 return rc;346 }347 348 pid_t pid = -1;349 350 /*351 * Take care of detaching the process.352 *353 * HACK ALERT! Put the process into a new process group with pgid = pid354 * to make sure it differs from that of the parent process to ensure that355 * the IPRT waitpid call doesn't race anyone (read XPCOM) doing group wide356 * waits. setsid() includes the setpgid() functionality.357 * 2010-10-11 XPCOM no longer waits for anything, but it cannot hurt.358 */359 #ifndef RT_OS_OS2360 if (fFlags & RTPROC_FLAGS_DETACHED)361 {362 # ifdef RT_OS_SOLARIS363 int templateFd = rtSolarisContractPreFork();364 if (templateFd == -1)365 return VERR_OPEN_FAILED;366 # endif /* RT_OS_SOLARIS */367 pid = fork();368 if (!pid)369 {370 # ifdef RT_OS_SOLARIS371 rtSolarisContractPostForkChild(templateFd);372 # endif /* RT_OS_SOLARIS */373 setsid(); /* see comment above */374 375 pid = -1;376 /* Child falls through to the actual spawn code below. */377 }378 else379 {380 #ifdef RT_OS_SOLARIS381 rtSolarisContractPostForkParent(templateFd, pid);382 #endif /* RT_OS_SOLARIS */383 if (pid > 0)384 {385 /* Must wait for the temporary process to avoid a zombie. */386 int status = 0;387 pid_t pidChild = 0;388 389 /* Restart if we get interrupted. */390 do391 {392 pidChild = waitpid(pid, &status, 0);393 } while ( pidChild == -1394 && errno == EINTR);395 396 /* Assume that something wasn't found. No detailed info. */397 if (status)398 return VERR_PROCESS_NOT_FOUND;399 if (phProcess)400 *phProcess = 0;401 return VINF_SUCCESS;402 }403 return RTErrConvertFromErrno(errno);404 }405 }406 #endif407 408 /*409 * Spawn the child.410 *411 * Any spawn code MUST not execute any atexit functions if it is for a412 * detached process. It would lead to running the atexit functions which413 * make only sense for the parent. libORBit e.g. gets confused by multiple414 * execution. Remember, there was only a fork() so far, and until exec()415 * is successfully run there is nothing which would prevent doing anything416 * silly with the (duplicated) file descriptors.417 */418 #ifdef HAVE_POSIX_SPAWN419 /** @todo OS/2: implement DETACHED (BACKGROUND stuff), see VbglR3Daemonize. */420 if ( uid == ~(uid_t)0421 && gid == ~(gid_t)0)422 {423 /* Spawn attributes. */424 posix_spawnattr_t Attr;425 rc = posix_spawnattr_init(&Attr);426 if (!rc)427 {428 # ifndef RT_OS_OS2 /* We don't need this on OS/2 and I don't recall if it's actually implemented. */429 rc = posix_spawnattr_setflags(&Attr, POSIX_SPAWN_SETPGROUP);430 Assert(rc == 0);431 if (!rc)432 {433 rc = posix_spawnattr_setpgroup(&Attr, 0 /* pg == child pid */);434 Assert(rc == 0);435 }436 # endif437 438 /* File changes. */439 posix_spawn_file_actions_t FileActions;440 posix_spawn_file_actions_t *pFileActions = NULL;441 if (aStdFds[0] != -1 || aStdFds[1] != -1 || aStdFds[2] != -1)442 {443 rc = posix_spawn_file_actions_init(&FileActions);444 if (!rc)445 {446 pFileActions = &FileActions;447 for (int i = 0; i < 3; i++)448 {449 int fd = aStdFds[i];450 if (fd == -2)451 rc = posix_spawn_file_actions_addclose(&FileActions, i);452 else if (fd >= 0 && fd != i)453 {454 rc = posix_spawn_file_actions_adddup2(&FileActions, fd, i);455 if (!rc)456 {457 for (int j = i + 1; j < 3; j++)458 if (aStdFds[j] == fd)459 {460 fd = -1;461 break;462 }463 if (fd >= 0)464 rc = posix_spawn_file_actions_addclose(&FileActions, fd);465 }466 }467 if (rc)468 break;469 }470 }471 }472 473 if (!rc)474 rc = posix_spawn(&pid, pszExec, pFileActions, &Attr, (char * const *)papszArgs,475 (char * const *)papszEnv);476 477 /* cleanup */478 int rc2 = posix_spawnattr_destroy(&Attr); Assert(rc2 == 0); NOREF(rc2);479 if (pFileActions)480 {481 rc2 = posix_spawn_file_actions_destroy(pFileActions);482 Assert(rc2 == 0);483 }484 485 /* return on success.*/486 if (!rc)487 {488 /* For a detached process this happens in the temp process, so489 * it's not worth doing anything as this process must exit. */490 if (fFlags & RTPROC_FLAGS_DETACHED)491 _Exit(0);492 if (phProcess)493 *phProcess = pid;494 return VINF_SUCCESS;495 }496 }497 /* For a detached process this happens in the temp process, so498 * it's not worth doing anything as this process must exit. */499 if (fFlags & RTPROC_FLAGS_DETACHED)500 _Exit(124);501 }502 else503 #endif504 {505 #ifdef RT_OS_SOLARIS506 int templateFd = rtSolarisContractPreFork();507 if (templateFd == -1)508 return VERR_OPEN_FAILED;509 #endif /* RT_OS_SOLARIS */510 pid = fork();511 if (!pid)512 {513 #ifdef RT_OS_SOLARIS514 rtSolarisContractPostForkChild(templateFd);515 #endif /* RT_OS_SOLARIS */516 if (!(fFlags & RTPROC_FLAGS_DETACHED))517 setpgid(0, 0); /* see comment above */518 519 /*520 * Change group and user if requested.521 */522 #if 1 /** @todo This needs more work, see suplib/hardening. */523 if (gid != ~(gid_t)0)524 {525 if (setgid(gid))526 {527 if (fFlags & RTPROC_FLAGS_DETACHED)528 _Exit(126);529 else530 exit(126);531 }532 }533 534 if (uid != ~(uid_t)0)535 {536 if (setuid(uid))537 {538 if (fFlags & RTPROC_FLAGS_DETACHED)539 _Exit(126);540 else541 exit(126);542 }543 }544 #endif545 546 /*547 * Apply changes to the standard file descriptor and stuff.548 */549 for (int i = 0; i < 3; i++)550 {551 int fd = aStdFds[i];552 if (fd == -2)553 close(i);554 else if (fd >= 0)555 {556 int rc2 = dup2(fd, i);557 if (rc2 != i)558 {559 if (fFlags & RTPROC_FLAGS_DETACHED)560 _Exit(125);561 else562 exit(125);563 }564 for (int j = i + 1; j < 3; j++)565 if (aStdFds[j] == fd)566 {567 fd = -1;568 break;569 }570 if (fd >= 0)571 close(fd);572 }573 }574 575 /*576 * Finally, execute the requested program.577 */578 rc = execve(pszExec, (char * const *)papszArgs, (char * const *)papszEnv);579 if (errno == ENOEXEC)580 {581 /* This can happen when trying to start a shell script without the magic #!/bin/sh */582 RTAssertMsg2Weak("Cannot execute this binary format!\n");583 }584 else585 RTAssertMsg2Weak("execve returns %d errno=%d\n", rc, errno);586 RTAssertReleasePanic();587 if (fFlags & RTPROC_FLAGS_DETACHED)588 _Exit(127);589 else590 exit(127);591 }592 #ifdef RT_OS_SOLARIS593 rtSolarisContractPostForkParent(templateFd, pid);594 #endif /* RT_OS_SOLARIS */595 if (pid > 0)596 {597 /* For a detached process this happens in the temp process, so598 * it's not worth doing anything as this process must exit. */599 if (fFlags & RTPROC_FLAGS_DETACHED)600 _Exit(0);601 if (phProcess)602 *phProcess = pid;603 return VINF_SUCCESS;604 }605 /* For a detached process this happens in the temp process, so606 * it's not worth doing anything as this process must exit. */607 if (fFlags & RTPROC_FLAGS_DETACHED)608 _Exit(124);609 return RTErrConvertFromErrno(errno);610 }611 612 return VERR_NOT_IMPLEMENTED;613 }614 615 616 55 RTR3DECL(int) RTProcWait(RTPROCESS Process, unsigned fFlags, PRTPROCSTATUS pProcStatus) 617 56 { … … 621 60 return rc; 622 61 } 62 623 63 624 64 RTR3DECL(int) RTProcWaitNoResume(RTPROCESS Process, unsigned fFlags, PRTPROCSTATUS pProcStatus) … … 697 137 698 138 699 RTR3DECL(uint64_t) RTProcGetAffinityMask( )139 RTR3DECL(uint64_t) RTProcGetAffinityMask(void) 700 140 { 701 // @todo141 /// @todo 702 142 return 1; 703 143 } 704 144 705 706 RTR3DECL(int) RTProcDaemonizeUsingFork(bool fNoChDir, bool fNoClose, const char *pszPidfile)707 {708 /*709 * Fork the child process in a new session and quit the parent.710 *711 * - fork once and create a new session (setsid). This will detach us712 * from the controlling tty meaning that we won't receive the SIGHUP713 * (or any other signal) sent to that session.714 * - The SIGHUP signal is ignored because the session/parent may throw715 * us one before we get to the setsid.716 * - When the parent exit(0) we will become an orphan and re-parented to717 * the init process.718 * - Because of the sometimes unexpected semantics of assigning the719 * controlling tty automagically when a session leader first opens a tty,720 * we will fork() once more to get rid of the session leadership role.721 */722 723 /* We start off by opening the pidfile, so that we can fail straight away724 * if it already exists. */725 int fdPidfile = -1;726 if (pszPidfile != NULL)727 {728 /* @note the exclusive create is not guaranteed on all file729 * systems (e.g. NFSv2) */730 if ((fdPidfile = open(pszPidfile, O_RDWR | O_CREAT | O_EXCL, 0644)) == -1)731 return RTErrConvertFromErrno(errno);732 }733 734 /* Ignore SIGHUP straight away. */735 struct sigaction OldSigAct;736 struct sigaction SigAct;737 memset(&SigAct, 0, sizeof(SigAct));738 SigAct.sa_handler = SIG_IGN;739 int rcSigAct = sigaction(SIGHUP, &SigAct, &OldSigAct);740 741 /* First fork, to become independent process. */742 pid_t pid = fork();743 if (pid == -1)744 return RTErrConvertFromErrno(errno);745 if (pid != 0)746 {747 /* Parent exits, no longer necessary. The child gets reparented748 * to the init process. */749 exit(0);750 }751 752 /* Create new session, fix up the standard file descriptors and the753 * current working directory. */754 pid_t newpgid = setsid();755 int SavedErrno = errno;756 if (rcSigAct != -1)757 sigaction(SIGHUP, &OldSigAct, NULL);758 if (newpgid == -1)759 return RTErrConvertFromErrno(SavedErrno);760 761 if (!fNoClose)762 {763 /* Open stdin(0), stdout(1) and stderr(2) as /dev/null. */764 int fd = open("/dev/null", O_RDWR);765 if (fd == -1) /* paranoia */766 {767 close(STDIN_FILENO);768 close(STDOUT_FILENO);769 close(STDERR_FILENO);770 fd = open("/dev/null", O_RDWR);771 }772 if (fd != -1)773 {774 dup2(fd, STDIN_FILENO);775 dup2(fd, STDOUT_FILENO);776 dup2(fd, STDERR_FILENO);777 if (fd > 2)778 close(fd);779 }780 }781 782 if (!fNoChDir)783 {784 int rcChdir = chdir("/");785 }786 787 /* Second fork to lose session leader status. */788 pid = fork();789 if (pid == -1)790 return RTErrConvertFromErrno(errno);791 792 if (pid != 0)793 {794 /* Write the pid file, this is done in the parent, before exiting. */795 if (fdPidfile != -1)796 {797 char szBuf[256];798 size_t cbPid = RTStrPrintf(szBuf, sizeof(szBuf), "%d\n", pid);799 int rcWrite = write(fdPidfile, szBuf, cbPid);800 close(fdPidfile);801 }802 exit(0);803 }804 805 return VINF_SUCCESS;806 }807
Note:
See TracChangeset
for help on using the changeset viewer.