VirtualBox

Changeset 33602 in vbox for trunk/src/VBox/Runtime/r3/posix


Ignore:
Timestamp:
Oct 29, 2010 12:39:54 PM (14 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
67213
Message:

IPRT/r3/posix: Split out RTPathUserHome and the process creation APIs into separate files to avoid linker warnings on linux when linking statically.

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  
    4747#include <iprt/log.h>
    4848#include "internal/path.h"
    49 #include "internal/process.h"
    5049#include "internal/fs.h"
    51 
    52 #ifdef RT_OS_L4
    53 # include <l4/vboxserver/vboxserver.h>
    54 #endif
    55 
    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 it
    70          * 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         else
    77             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, and
    90  * 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_UNC
    103     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 #endif
    112 
    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 > 1
    140         &&  RTPATH_IS_SLASH(pszTrg[-1])
    141 #ifdef HAVE_DRIVE
    142         &&  !RTPATH_IS_VOLSEP(pszTrg[-2])
    143 #endif
    144         &&  !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_DRIVE
    188     if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == '/')
    189         pszCur += 3;
    190 # ifdef HAVE_UNC
    191     else if (pszCur[0] == '/' && pszCur[1] == '/')
    192         pszCur += 2;
    193 # endif
    194 #else  /* !HAVE_DRIVE */
    195     if (pszCur[0] == '/')
    196         pszCur += 1;
    197 #endif /* !HAVE_DRIVE */
    198     else
    199     {
    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_DRIVE
    220         if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == '/')
    221             pszCur += 3;
    222 # ifdef HAVE_UNC
    223         else if (pszCur[0] == '/' && pszCur[1] == '/')
    224             pszCur += 2;
    225 # endif
    226 #else
    227         if (pszCur[0] == '/')
    228             pszCur += 1;
    229 #endif
    230         else
    231             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         else
    257         {
    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     else
    297         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 }
    30350
    30451
     
    415162}
    416163
    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_NOTHING
    433                     &&  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         else
    449             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         else
    472             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         else
    518         {
    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             else
    530             {
    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                 else
    538                     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                 else
    553                 {
    554                     if (lutimes(pszNativePath, aTimevals))
    555                         rc = RTErrConvertFromErrno(errno);
    556                 }
    557 #else
    558                 else
    559                 {
    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 #endif
    571                 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 1
    618         else
    619         {
    620             if (lchown(pszNativePath, uidNative, gidNative))
    621                 rc = RTErrConvertFromErrno(errno);
    622         }
    623 #else
    624         else
    625         {
    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 #endif
    637         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     else
    669     {
    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_dev
    691         &&  SrcStat.st_ino == DstStat.st_ino
    692         &&  (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 the
    707  *                      source is a directory. If Its RTFS_TYPE_FILE we'll check that it's
    708  *                      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_EXISTS
    726              * errors from the next step.
    727              *
    728              * There are race conditions here (perhaps unlikely ones but still), but I'm
    729              * 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             else
    739                 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                 else
    753                 {
    754                     Assert(SrcStat.st_dev && DstStat.st_dev);
    755                     Assert(SrcStat.st_ino && DstStat.st_ino);
    756                     if (    SrcStat.st_dev == DstStat.st_dev
    757                         &&  SrcStat.st_ino == DstStat.st_ino
    758                         &&  (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                     else
    771                         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                         else
    792                         {
    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                             else
    798                                 rc = VINF_SUCCESS;
    799                             if (RT_SUCCESS(rc))
    800                             {
    801                                 if (!unlink(pszNativeDst))
    802                                 {
    803                                     if (!rename(pszNativeSrc, pszNativeDst))
    804                                         rc = VINF_SUCCESS;
    805                                     else
    806                                     {
    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                                 else
    813                                 {
    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                             else
    820                                 Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): dst !dir check failed rc=%Rrc\n",
    821                                      pszSrc, pszDst, fRename, fFileType, rc));
    822                         }
    823                     }
    824                     else
    825                     {
    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                 else
    834                     Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): destination check failed rc=%Rrc errno=%d\n",
    835                          pszSrc, pszDst, fRename, fFileType, rc, errno));
    836             }
    837             else
    838                 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         else
    896             rc = lstat(pszNativePath, &Stat);
    897         if (!rc)
    898             rc = VINF_SUCCESS;
    899         else
    900             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     else
    914         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  
    299299    LogFlow(("RTPathAbs(%p:{%s}, %p:{%s}, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath,
    300300             RT_SUCCESS(rc) ? pszAbsPath : "<failed>", cchAbsPath, rc));
    301     return rc;
    302 }
    303 
    304 
    305 #ifndef RT_OS_L4
    306 /**
    307  * Worker for RTPathUserHome that looks up the home directory
    308  * 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" any
    319      * extra memory it needs. On some systems we should probably use the
    320      * sysconf function to find the appropriate buffer size, but since it won't
    321      * work everywhere we'll settle with a 5KB buffer and ASSUME that it'll
    322      * 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_dir
    339         ||  !*pPasswd->pw_dir
    340         ||  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 #endif
    350 
    351 
    352 /**
    353  * Worker for RTPathUserHome that looks up the home directory
    354  * 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_L4
    383     /*
    384      * We make an exception for the root user and use the system call
    385      * getpwuid_r to determine their initial home path instead of
    386      * reading it from the $HOME variable.  This is because the $HOME
    387      * 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      else
    394          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          else
    406              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));
    414301    return rc;
    415302}
  • trunk/src/VBox/Runtime/r3/posix/process-creation-posix.cpp

    r33593 r33602  
    11/* $Id$ */
    22/** @file
    3  * IPRT - Process, POSIX.
     3 * IPRT - Process Creation, POSIX.
    44 */
    55
     
    2424 * terms and conditions of either the GPL or the CDDL or both.
    2525 */
    26 
    2726
    2827
     
    614613
    615614
    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             else
    663             {
    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     // @todo
    702     return 1;
    703 }
    704 
    705 
    706615RTR3DECL(int)   RTProcDaemonizeUsingFork(bool fNoChDir, bool fNoClose, const char *pszPidfile)
    707616{
  • trunk/src/VBox/Runtime/r3/posix/process-posix.cpp

    r33135 r33602  
    3737#include <sys/stat.h>
    3838#include <sys/wait.h>
    39 #include <fcntl.h>
    4039#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 #endif
    46 #if defined(RT_OS_LINUX) || defined(RT_OS_OS2)
    47 /* While Solaris has posix_spawn() of course we don't want to use it as
    48  * we need to have the child in a different process contract, no matter
    49  * whether it is started detached or not. */
    50 # define HAVE_POSIX_SPAWN 1
    51 #endif
    52 #ifdef HAVE_POSIX_SPAWN
    53 # include <spawn.h>
    54 #endif
    55 #ifdef RT_OS_DARWIN
    56 # include <mach-o/dyld.h>
    57 #endif
    58 #ifdef RT_OS_SOLARIS
    59 # include <limits.h>
    60 # include <sys/ctfs.h>
    61 # include <sys/contract/process.h>
    62 # include <libcontract.h>
    63 #endif
    6440
    6541#include <iprt/process.h>
     
    7753
    7854
    79 /**
    80  * Check the credentials and return the gid/uid of user.
    81  *
    82  * @param    pszUser     username
    83  * @param    pszPasswd   password
    84  * @param    gid         where to store the GID of the user
    85  * @param    uid         where to store the UID of the user
    86  * @returns IPRT status code
    87  */
    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 #else
    142     return VERR_PERMISSION_DENIED;
    143 #endif
    144 }
    145 
    146 
    147 #ifdef RT_OS_SOLARIS
    148 /** @todo the error reporting of the Solaris process contract code could be
    149  * a lot better, but essentially it is not meant to run into errors after
    150  * 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 validation
    265      */
    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_RTFILE
    294                                ? (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_RTPIPE
    300                                ? (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_RTSOCKET
    306                                ? (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 = pid
    354      * to make sure it differs from that of the parent process to ensure that
    355      * the IPRT waitpid call doesn't race anyone (read XPCOM) doing group wide
    356      * 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_OS2
    360     if (fFlags & RTPROC_FLAGS_DETACHED)
    361     {
    362 # ifdef RT_OS_SOLARIS
    363         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_SOLARIS
    371             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         else
    379         {
    380 #ifdef RT_OS_SOLARIS
    381             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                 do
    391                 {
    392                     pidChild = waitpid(pid, &status, 0);
    393                 } while (   pidChild == -1
    394                          && 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 #endif
    407 
    408     /*
    409      * Spawn the child.
    410      *
    411      * Any spawn code MUST not execute any atexit functions if it is for a
    412      * detached process. It would lead to running the atexit functions which
    413      * make only sense for the parent. libORBit e.g. gets confused by multiple
    414      * execution. Remember, there was only a fork() so far, and until exec()
    415      * is successfully run there is nothing which would prevent doing anything
    416      * silly with the (duplicated) file descriptors.
    417      */
    418 #ifdef HAVE_POSIX_SPAWN
    419     /** @todo OS/2: implement DETACHED (BACKGROUND stuff), see VbglR3Daemonize.  */
    420     if (   uid == ~(uid_t)0
    421         && 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 # endif
    437 
    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, so
    489                  * 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, so
    498          * it's not worth doing anything as this process must exit. */
    499         if (fFlags & RTPROC_FLAGS_DETACHED)
    500             _Exit(124);
    501     }
    502     else
    503 #endif
    504     {
    505 #ifdef RT_OS_SOLARIS
    506         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_SOLARIS
    514             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                     else
    530                         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                     else
    541                         exit(126);
    542                 }
    543             }
    544 #endif
    545 
    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                         else
    562                             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             else
    585                 RTAssertMsg2Weak("execve returns %d errno=%d\n", rc, errno);
    586             RTAssertReleasePanic();
    587             if (fFlags & RTPROC_FLAGS_DETACHED)
    588                 _Exit(127);
    589             else
    590                 exit(127);
    591         }
    592 #ifdef RT_OS_SOLARIS
    593         rtSolarisContractPostForkParent(templateFd, pid);
    594 #endif /* RT_OS_SOLARIS */
    595         if (pid > 0)
    596         {
    597             /* For a detached process this happens in the temp process, so
    598              * 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, so
    606          * 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 
    61655RTR3DECL(int)   RTProcWait(RTPROCESS Process, unsigned fFlags, PRTPROCSTATUS pProcStatus)
    61756{
     
    62160    return rc;
    62261}
     62
    62363
    62464RTR3DECL(int)   RTProcWaitNoResume(RTPROCESS Process, unsigned fFlags, PRTPROCSTATUS pProcStatus)
     
    697137
    698138
    699 RTR3DECL(uint64_t) RTProcGetAffinityMask()
     139RTR3DECL(uint64_t) RTProcGetAffinityMask(void)
    700140{
    701     // @todo
     141    /// @todo
    702142    return 1;
    703143}
    704144
    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 us
    712      *   from the controlling tty meaning that we won't receive the SIGHUP
    713      *   (or any other signal) sent to that session.
    714      * - The SIGHUP signal is ignored because the session/parent may throw
    715      *   us one before we get to the setsid.
    716      * - When the parent exit(0) we will become an orphan and re-parented to
    717      *   the init process.
    718      * - Because of the sometimes unexpected semantics of assigning the
    719      *   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 away
    724      * if it already exists. */
    725     int fdPidfile = -1;
    726     if (pszPidfile != NULL)
    727     {
    728         /* @note the exclusive create is not guaranteed on all file
    729          * 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 reparented
    748          * to the init process. */
    749         exit(0);
    750     }
    751 
    752     /* Create new session, fix up the standard file descriptors and the
    753      * 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.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette