VirtualBox

Ignore:
Timestamp:
Oct 29, 2010 12:39:54 PM (15 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.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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.

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