The Open Group Base Specifications Issue 7
IEEE Std 1003.1-2008, 2016 Edition
Copyright © 2001-2016 The IEEE and The Open Group

### B.3 System Interfaces

See the RATIONALE sections on the individual reference pages.

#### B.3.1 System Interfaces Removed in this Version

The following section contains a list of the interfaces removed in POSIX.1-2008, together with advice for application developers on the alternative interfaces that should be used for maximum portability.

##### bcmp()

Applications are recommended to use the memcmp() function instead of this function.

For maximum portability, it is recommended to replace the function call to bcmp() as follows:

    #define bcmp(b1,b2,len) memcmp((b1), (b2), (size_t)(len))

##### bcopy()

Applications are recommended to use the memmove() function instead of this function.

The following are approximately equivalent (note the order of the arguments):

    bcopy(s1,s2,n) \(˜˜ memmove(s2,s1,n)

For maximum portability, it is recommended to replace the function call to bcopy() as follows:

    #define bcopy(b1,b2,len) (void)(memmove((b2), (b1), (len)))

##### bsd_signal()

Applications are recommended to use the sigaction() function instead of this function.

The bsd_signal() function was supplied as a migration path for the BSD signal() function for simple applications that installed a single-argument signal handler function.

Historically, the bsd_signal() function differs from signal() in that the SA_RESTART flag is set and the SA_RESETHAND flag is clear when bsd_signal() is used. The state of these flags is not specified for signal().

##### bzero()

Applications are recommended to use the memset() function instead of this function.

For maximum portability, it is recommended to replace the function call to bzero() as follows:

    #define bzero(b,len) (void)(memset((b), '\0', (len)))

##### ecvt(), fcvt(), gcvt()

Applications are recommended to use the sprintf() function instead of these functions.

The sprintf() function is required by ISO C and is thus more portable.

##### ftime()

Applications are recommended to use the time() function to determine the current time. Realtime applications should use clock_gettime() to determine the current time.

##### getcontext(), makecontext(), swapcontext()

Due to portability issues with these functions, especially with the manipulation of contexts, applications are recommended to be rewritten to use POSIX threads.

##### gethostbyaddr(), gethostbyname()

Applications are recommended to use the getaddrinfo() and getnameinfo() functions instead of these functions.

The gethostbyaddr() and gethostbyname() functions may return pointers to static data, which may be overwritten by subsequent calls to any of these functions. The suggested replacements do not have this problem and are also IPv6-capable.

##### getwd()

Applications are recommended to use the getcwd() function to determine the current working directory.

##### h_errno

Applications are recommended not to use this error return code. Previously it was set by the gethostbyaddr() and gethostbyname() functions.

##### index()

Applications are recommended to use the strchr() function instead of this function.

For maximum portability, it is recommended to replace the function call to index() as follows:

    #define index(a,b) strchr((a),(b))

##### makecontext()

Applications using the getcontext(), makecontext(), and swapcontext() functions should be rewritten to use POSIX threads.

##### mktemp()

Applications are recommended to use the mkstemp() function instead of this function.

The mktemp() function makes an application vulnerable to possible security problems since between the time a pathname is created and the file opened, it is possible for some other process to create a file with the same name. The mkstemp() function does not have this vulnerability.

##### pthread_attr_getstackaddr(), pthread_attr_setstackaddr()

Applications are recommended to use the pthread_attr_setstack() and pthread_attr_getstack() functions instead of these functions.

There are a number of ambiguities in the specification of the stackaddr attribute that makes portable use of these interfaces impossible.

##### rindex()

Applications are recommended to use the strrchr() function instead of this function.

For maximum portability, it is recommended to replace the function call to rindex() as follows:

    #define rindex(a,b) strrchr((a),(b))

##### scalb()

Applications are recommended to use either scalbln(), scalblnf(), or scalblnl() instead of these functions.

The behavior for the scalb() function was only defined when the n argument is an integer, a NaN, or Inf. The behavior of other values for the n argument was unspecified.

##### ualarm()

Applications are recommended to use timer_create(), timer_delete(), timer_getoverrun(), timer_gettime(), or timer_settime() instead of this function.

##### usleep()

Applications are recommended to use the nanosleep() function instead of this function.

##### vfork()

Applications are recommended to use the fork() function instead of this function.

The vfork() function was previously under-specified.

##### wcswcs()

Applications are recommended to use the wcsstr() function instead of this function.

The wcsstr() function is technically equivalent and is portable across all ISO C implementations.

#### B.3.2 System Interfaces Removed in the Previous Version

The following system interfaces, headers, and external variables were removed in the previous version of this standard:

advance() brk() chroot() compile() cuserid() gamma() | getdtablesize() getpagesize() getpass() getw() putw() re_comp() | re_exec() regcmp() regex() sbrk() sigstack() step() | ttyslot() valloc() wait3() <re_comp.h> <regexp.h> <varargs.h> | loc1 __loc1 loc2 locs

#### B.3.3 Examples for Spawn

The following long examples are provided in the Rationale (Informative) volume of POSIX.1-2008 as a supplement to the reference page for posix_spawn().

##### Example Library Implementation of Spawn

The posix_spawn() or posix_spawnp() functions provide the following:

- Simply start a process executing a process image. This is the simplest application for process creation, and it may cover most executions of fork().

- Support I/O redirection, including pipes.

- Run the child under a user and group ID in the domain of the parent.

- Run the child at any priority in the domain of the parent.

The posix_spawn() or posix_spawnp() functions do not cover every possible use of the fork() function, but they do span the common applications: typical use by a shell and a login utility.

The price for an application is that before it calls posix_spawn() or posix_spawnp(), the parent must adjust to a state that posix_spawn() or posix_spawnp() can map to the desired state for the child. Environment changes require the parent to save some of its state and restore it afterwards. The effective behavior of a successful invocation of posix_spawn() is as if the operation were implemented with POSIX operations as follows:

    #include <sys/types.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <sched.h>
    #include <fcntl.h>
    #include <signal.h>
    #include <errno.h>
    #include <string.h>
    #include <signal.h>

    /* #include <spawn.h> */
    /*******************************************/
    /* Things that could be defined in spawn.h */
    /*******************************************/
    typedef struct
    {
        short posix_attr_flags;
    #define POSIX_SPAWN_SETPGROUP       0x1
    #define POSIX_SPAWN_SETSIGMASK      0x2
    #define POSIX_SPAWN_SETSIGDEF       0x4
    #define POSIX_SPAWN_SETSCHEDULER    0x8
    #define POSIX_SPAWN_SETSCHEDPARAM   0x10
    #define POSIX_SPAWN_RESETIDS        0x20
        pid_t posix_attr_pgroup;
        sigset_t posix_attr_sigmask;
        sigset_t posix_attr_sigdefault;
        int posix_attr_schedpolicy;
        struct sched_param posix_attr_schedparam;
    }   posix_spawnattr_t;

    typedef char *posix_spawn_file_actions_t;

    int posix_spawn_file_actions_init(
        posix_spawn_file_actions_t *file_actions);
    int posix_spawn_file_actions_destroy(
        posix_spawn_file_actions_t *file_actions);
    int posix_spawn_file_actions_addclose(
        posix_spawn_file_actions_t *file_actions, int fildes);
    int posix_spawn_file_actions_adddup2(
        posix_spawn_file_actions_t *file_actions, int fildes,
        int newfildes);
    int posix_spawn_file_actions_addopen(
        posix_spawn_file_actions_t *file_actions, int fildes,
        const char *path, int oflag, mode_t mode);
    int posix_spawnattr_init(posix_spawnattr_t *attr);
    int posix_spawnattr_destroy(posix_spawnattr_t *attr);
    int posix_spawnattr_getflags(const posix_spawnattr_t *attr,
        short *lags);
    int posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags);
    int posix_spawnattr_getpgroup(const posix_spawnattr_t *attr,
        pid_t *pgroup);
    int posix_spawnattr_setpgroup(posix_spawnattr_t *attr, pid_t pgroup);
    int posix_spawnattr_getschedpolicy(const posix_spawnattr_t *attr,
        int *schedpolicy);
    int posix_spawnattr_setschedpolicy(posix_spawnattr_t *attr,
        int schedpolicy);
    int posix_spawnattr_getschedparam(const posix_spawnattr_t *attr,
        struct sched_param *schedparam);
    int posix_spawnattr_setschedparam(posix_spawnattr_t *attr,
        const struct sched_param *schedparam);
    int posix_spawnattr_getsigmask(const posix_spawnattr_t *attr,
        sigset_t *sigmask);
    int posix_spawnattr_setsigmask(posix_spawnattr_t *attr,
        const sigset_t *sigmask);
    int posix_spawnattr_getdefault(const posix_spawnattr_t *attr,
        sigset_t *sigdefault);
    int posix_spawnattr_setsigdefault(posix_spawnattr_t *attr,
        const sigset_t *sigdefault);
    int posix_spawn(pid_t *pid, const char *path,
        const posix_spawn_file_actions_t *file_actions,
        const posix_spawnattr_t *attrp, char *const argv[],
        char *const envp[]);
    int posix_spawnp(pid_t *pid, const char *file,
        const posix_spawn_file_actions_t *file_actions,
        const posix_spawnattr_t *attrp, char *const argv[],
        char *const envp[]);

    /*****************************************/
    /* Example posix_spawn() library routine */
    /*****************************************/
    int posix_spawn(pid_t *pid,
        const char *path,
        const posix_spawn_file_actions_t *file_actions,
        const posix_spawnattr_t *attrp,
        char *const argv[],
        char *const envp[])
    {
        /* Create process */
        if ((*pid = fork()) == (pid_t) 0)
        {
            /* This is the child process */
            /* Worry about process group */
            if (attrp->posix_attr_flags & POSIX_SPAWN_SETPGROUP)
            {
                /* Override inherited process group */
                if (setpgid(0, attrp->posix_attr_pgroup) != 0)
                {
                    /* Failed */
                    exit(127);
                }
            }

            /* Worry about thread signal mask */
            if (attrp->posix_attr_flags & POSIX_SPAWN_SETSIGMASK)
            {
                /* Set the signal mask (cannot fail) */
                sigprocmask(SIG_SETMASK, &attrp->posix_attr_sigmask, NULL);
            }

            /* Worry about resetting effective user and group IDs */
            if (attrp->posix_attr_flags & POSIX_SPAWN_RESETIDS)
            {
                /* None of these can fail for this case. */
                setuid(getuid());
                setgid(getgid());
            }

            /* Worry about defaulted signals */
            if (attrp->posix_attr_flags & POSIX_SPAWN_SETSIGDEF)
            {
                struct sigaction deflt;
                sigset_t all_signals;

                int s;

                /* Construct default signal action */
                deflt.sa_handler = SIG_DFL;
                deflt.sa_flags = 0;

                /* Construct the set of all signals */
                sigfillset(&all_signals);

                /* Loop for all signals */
                for (s = 0; sigismember(&all_signals, s); s++)
                {
                    /* Signal to be defaulted? */
                    if (sigismember(&attrp->posix_attr_sigdefault, s))
                    {
                        /* Yes; default this signal */
                        if (sigaction(s, &deflt, NULL) == -1)
                        {
                            /* Failed */
                            exit(127);
                        }
                    }
                }
            }

            /* Worry about the fds if they are to be mapped */
            if (file_actions != NULL)
            {
                /* Loop for all actions in object file_actions */
                /* (implementation dives beneath abstraction) */
                char *p = *file_actions;

                while (*p != '\0')
                {
                    if (strncmp(p, "close(", 6) == 0)
                    {
                        int fd;

                        if (sscanf(p + 6, "%d)", &fd) != 1)
                        {
                            exit(127);
                        }
                        if (close(fd) == -1)
                            exit(127);
                    }
                    else if (strncmp(p, "dup2(", 5) == 0)
                    {
                        int fd, newfd;

                        if (sscanf(p + 5, "%d,%d)", &fd, &newfd) != 2)
                        {
                            exit(127);
                        }
                        if (dup2(fd, newfd) == -1)
                            exit(127);
                    }
                    else if (strncmp(p, "open(", 5) == 0)
                    {
                        int fd, oflag;
                        mode_t mode;
                        int tempfd;
                        char path[1000];    /* Should be dynamic */
                        char *q;

                        if (sscanf(p + 5, "%d,", &fd) != 1)
                        {
                            exit(127);
                        }
                        p = strchr(p, ',') + 1;
                        q = strchr(p, '*');
                        if (q == NULL)
                            exit(127);
                        strncpy(path, p, q - p);
                        path[q - p] = '\0';
                        if (sscanf(q + 1, "%o,%o)", &oflag, &mode) != 2)
                        {
                            exit(127);
                        }
                        if (close(fd) == -1)
                        {
                            if (errno != EBADF)
                                exit(127);
                        }
                        tempfd = open(path, oflag, mode);
                        if (tempfd == -1)
                            exit(127);
                        if (tempfd != fd)
                        {
                            if (dup2(tempfd, fd) == -1)
                            {
                                exit(127);
                            }
                            if (close(tempfd) == -1)
                            {
                                exit(127);
                            }
                        }
                    }
                    else
                    {
                        exit(127);
                    }
                    p = strchr(p, ')') + 1;
                }
            }

            /* Worry about setting new scheduling policy and parameters */
            if (attrp->posix_attr_flags & POSIX_SPAWN_SETSCHEDULER)
            {
                if (sched_setscheduler(0, attrp->posix_attr_schedpolicy,
                    &attrp->posix_attr_schedparam) == -1)
                {
                    exit(127);
                }
            }

            /* Worry about setting only new scheduling parameters */
            if (attrp->posix_attr_flags & POSIX_SPAWN_SETSCHEDPARAM)
            {
                if (sched_setparam(0, &attrp->posix_attr_schedparam) == -1)
                {
                    exit(127);
                }
            }

            /* Now execute the program at path */
            /* Any fd that still has FD_CLOEXEC set will be closed */
            execve(path, argv, envp);
            exit(127);              /* exec failed */
        }
        else
        {
            /* This is the parent (calling) process */
            if (*pid == (pid_t) - 1)
                return errno;
            return 0;
        }
    }

    /*******************************************************/
    /* Here is a crude but effective implementation of the */
    /* file action object operators which store actions as */
    /* concatenated token-separated strings.               */
    /*******************************************************/
    /* Create object with no actions. */
    int posix_spawn_file_actions_init(
        posix_spawn_file_actions_t *file_actions)
    {
        *file_actions = malloc(sizeof(char));
        if (*file_actions == NULL)
            return ENOMEM;
        strcpy(*file_actions, "");
        return 0;
    }

    /* Free object storage and make invalid. */
    int posix_spawn_file_actions_destroy(
        posix_spawn_file_actions_t *file_actions)
    {
        free(*file_actions);
        *file_actions = NULL;
        return 0;
    }

    /* Add a new action string to object. */
    static int add_to_file_actions(
        posix_spawn_file_actions_t *file_actions, char *new_action)
    {
        *file_actions = realloc
        (*file_actions, strlen(*file_actions) + strlen(new_action) + 1);
        if (*file_actions == NULL)
            return ENOMEM;
        strcat(*file_actions, new_action);
        return 0;
    }

    /* Add a close action to object. */
    int posix_spawn_file_actions_addclose(
        posix_spawn_file_actions_t *file_actions, int fildes)
    {
        char temp[100];

        sprintf(temp, "close(%d)", fildes);
        return add_to_file_actions(file_actions, temp);
    }

    /* Add a dup2 action to object. */
    int posix_spawn_file_actions_adddup2(
        posix_spawn_file_actions_t *file_actions, int fildes,
        int newfildes)
    {
        char temp[100];

        sprintf(temp, "dup2(%d,%d)", fildes, newfildes);
        return add_to_file_actions(file_actions, temp);
    }

    /* Add an open action to object. */
    int posix_spawn_file_actions_addopen(
        posix_spawn_file_actions_t *file_actions, int fildes,
        const char *path, int oflag, mode_t mode)
    {
        char temp[100];

        sprintf(temp, "open(%d,%s*%o,%o)", fildes, path, oflag, mode);
        return add_to_file_actions(file_actions, temp);
    }

    /*******************************************************/
    /* Here is a crude but effective implementation of the */
    /* spawn attributes object functions which manipulate  */
    /* the individual attributes.                          */
    /*******************************************************/
    /* Initialize object with default values. */
    int posix_spawnattr_init(posix_spawnattr_t *attr)
    {
        attr->posix_attr_flags = 0;
        attr->posix_attr_pgroup = 0;
        /* Default value of signal mask is the parent's signal mask; */
        /* other values are also allowed */
        sigprocmask(0, NULL, &attr->posix_attr_sigmask);
        sigemptyset(&attr->posix_attr_sigdefault);
        /* Default values of scheduling attr inherited from the parent; */
        /* other values are also allowed */
        attr->posix_attr_schedpolicy = sched_getscheduler(0);
        sched_getparam(0, &attr->posix_attr_schedparam);
        return 0;
    }

    int posix_spawnattr_destroy(posix_spawnattr_t *attr)
    {
        /* No action needed */
        return 0;
    }

    int posix_spawnattr_getflags(const posix_spawnattr_t *attr,
        short *flags)
    {
        *flags = attr->posix_attr_flags;
        return 0;
    }

    int posix_spawnattr_setflags(posix_spawnattr_t *attr, short flags)
    {
        attr->posix_attr_flags = flags;
        return 0;
    }

    int posix_spawnattr_getpgroup(const posix_spawnattr_t *attr,
        pid_t *pgroup)
    {
        *pgroup = attr->posix_attr_pgroup;
        return 0;
    }

    int posix_spawnattr_setpgroup(posix_spawnattr_t *attr, pid_t pgroup)
    {
        attr->posix_attr_pgroup = pgroup;
        return 0;
    }

    int posix_spawnattr_getschedpolicy(const posix_spawnattr_t *attr,
        int *schedpolicy)
    {
        *schedpolicy = attr->posix_attr_schedpolicy;
        return 0;
    }

    int posix_spawnattr_setschedpolicy(posix_spawnattr_t *attr,
        int schedpolicy)
    {
        attr->posix_attr_schedpolicy = schedpolicy;
        return 0;
    }

    int posix_spawnattr_getschedparam(const posix_spawnattr_t *attr,
        struct sched_param *schedparam)
    {
        *schedparam = attr->posix_attr_schedparam;
        return 0;
    }

    int posix_spawnattr_setschedparam(posix_spawnattr_t *attr,
        const struct sched_param *schedparam)
    {
        attr->posix_attr_schedparam = *schedparam;
        return 0;
    }

    int posix_spawnattr_getsigmask(const posix_spawnattr_t *attr,
        sigset_t *sigmask)
    {
        *sigmask = attr->posix_attr_sigmask;
        return 0;
    }

    int posix_spawnattr_setsigmask(posix_spawnattr_t *attr,
        const sigset_t *sigmask)
    {
        attr->posix_attr_sigmask = *sigmask;
        return 0;
    }

    int posix_spawnattr_getsigdefault(const posix_spawnattr_t *attr,
        sigset_t *sigdefault)
    {
        *sigdefault = attr->posix_attr_sigdefault;
        return 0;
    }

    int posix_spawnattr_setsigdefault(posix_spawnattr_t *attr,
        const sigset_t *sigdefault)
    {
        attr->posix_attr_sigdefault = *sigdefault;
        return 0;
    }

##### I/O Redirection with Spawn

I/O redirection with posix_spawn() or posix_spawnp() is accomplished by crafting a file_actions argument to effect the desired redirection. Such a redirection follows the general outline of the following example:

    /* To redirect new standard output (fd 1) to a file, */
    /* and redirect new standard input (fd 0) from my fd socket_pair[1], */
    /* and close my fd socket_pair[0] in the new process. */
    posix_spawn_file_actions_t file_actions;
    posix_spawn_file_actions_init(&file_actions);
    posix_spawn_file_actions_addopen(&file_actions, 1, "newout", ...);
    posix_spawn_file_actions_dup2(&file_actions, socket_pair[1], 0);
    posix_spawn_file_actions_close(&file_actions, socket_pair[0]);
    posix_spawn_file_actions_close(&file_actions, socket_pair[1]);
    posix_spawn(..., &file_actions, ...);
    posix_spawn_file_actions_destroy(&file_actions);

##### Spawning a Process Under a New User ID

Spawning a process under a new user ID follows the outline shown in the following example:

    Save = getuid();
    setuid(newid);
    posix_spawn(...);
    setuid(Save);

return to top of page

UNIX ® is a registered Trademark of The Open Group.
POSIX ® is a registered Trademark of The IEEE.
Copyright © 2001-2016 The IEEE and The Open Group, All Rights Reserved
[ Main Index | XBD | XSH | XCU | XRAT ]