OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [uClibc/] [libc/] [stdio/] [popen.c] - Diff between revs 1325 and 1765

Only display areas with differences | Details | Blame | View Log

Rev 1325 Rev 1765
/*  Copyright (C) 2004     Manuel Novoa III
/*  Copyright (C) 2004     Manuel Novoa III
 *
 *
 *  This library is free software; you can redistribute it and/or
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *  version 2 of the License, or (at your option) any later version.
 *
 *
 *  This library is distributed in the hope that it will be useful,
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *  Library General Public License for more details.
 *
 *
 *  You should have received a copy of the GNU Library General Public
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the Free
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 */
 
 
/* Jan 1, 2004
/* Jan 1, 2004
 *
 *
 * Rewrite popen for SUSv3 compliance.
 * Rewrite popen for SUSv3 compliance.
 *   Added a list of popen()'d to store pids and use waitpid() in pclose().
 *   Added a list of popen()'d to store pids and use waitpid() in pclose().
 *   Loop on waitpid() failure due to EINTR as required.
 *   Loop on waitpid() failure due to EINTR as required.
 *   Close parent's popen()'d FILEs in the {v}fork()'d child.
 *   Close parent's popen()'d FILEs in the {v}fork()'d child.
 *   Fix failure exit code for failed execve().
 *   Fix failure exit code for failed execve().
 */
 */
 
 
 
 
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdlib.h>
#include <errno.h>
#include <errno.h>
#include <unistd.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/wait.h>
 
 
/* uClinux-2.0 has vfork, but Linux 2.0 doesn't */
/* uClinux-2.0 has vfork, but Linux 2.0 doesn't */
#include <sys/syscall.h>
#include <sys/syscall.h>
#if ! defined __NR_vfork
#if ! defined __NR_vfork
# define vfork fork     
# define vfork fork     
# define VFORK_LOCK             ((void) 0)
# define VFORK_LOCK             ((void) 0)
# define VFORK_UNLOCK   ((void) 0)
# define VFORK_UNLOCK   ((void) 0)
#endif
#endif
 
 
#ifdef __UCLIBC_HAS_THREADS__
#ifdef __UCLIBC_HAS_THREADS__
#include <pthread.h>
#include <pthread.h>
static pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
# define LOCK                   __pthread_mutex_lock(&mylock)
# define LOCK                   __pthread_mutex_lock(&mylock)
# define UNLOCK                 __pthread_mutex_unlock(&mylock);
# define UNLOCK                 __pthread_mutex_unlock(&mylock);
#else
#else
# define LOCK                   ((void) 0)
# define LOCK                   ((void) 0)
# define UNLOCK                 ((void) 0)
# define UNLOCK                 ((void) 0)
#endif      
#endif      
 
 
#ifndef VFORK_LOCK
#ifndef VFORK_LOCK
# define VFORK_LOCK             LOCK
# define VFORK_LOCK             LOCK
# define VFORK_UNLOCK   UNLOCK
# define VFORK_UNLOCK   UNLOCK
#endif
#endif
 
 
/* Temporarily support old stdio code. */
/* Temporarily support old stdio code. */
#ifndef __MASK_READING
#ifndef __MASK_READING
#define __filedes               filedes
#define __filedes               filedes
#endif
#endif
 
 
struct popen_list_item {
struct popen_list_item {
        struct popen_list_item *next;
        struct popen_list_item *next;
        FILE *f;
        FILE *f;
        pid_t pid;
        pid_t pid;
};
};
 
 
static struct popen_list_item *popen_list /* = NULL (bss initialized) */;
static struct popen_list_item *popen_list /* = NULL (bss initialized) */;
 
 
FILE *popen(const char *command, const char *modes)
FILE *popen(const char *command, const char *modes)
{
{
        FILE *fp;
        FILE *fp;
        struct popen_list_item *pi;
        struct popen_list_item *pi;
        struct popen_list_item *po;
        struct popen_list_item *po;
        int pipe_fd[2];
        int pipe_fd[2];
        int parent_fd;
        int parent_fd;
        int child_fd;
        int child_fd;
        int child_writing;                      /* Doubles as the desired child fildes. */
        int child_writing;                      /* Doubles as the desired child fildes. */
        pid_t pid;
        pid_t pid;
 
 
        child_writing = 0;                       /* Assume child is writing. */
        child_writing = 0;                       /* Assume child is writing. */
        if (modes[0] != 'w') {           /* Parent not writing... */
        if (modes[0] != 'w') {           /* Parent not writing... */
                ++child_writing;                /* so child must be writing. */
                ++child_writing;                /* so child must be writing. */
                if (modes[0] != 'r') {   /* Oops!  Parent not reading either! */
                if (modes[0] != 'r') {   /* Oops!  Parent not reading either! */
                        __set_errno(EINVAL);
                        __set_errno(EINVAL);
                        goto RET_NULL;
                        goto RET_NULL;
                }
                }
        }
        }
 
 
        if (!(pi = malloc(sizeof(struct popen_list_item)))) {
        if (!(pi = malloc(sizeof(struct popen_list_item)))) {
                goto RET_NULL;
                goto RET_NULL;
        }
        }
 
 
        if (pipe(pipe_fd)) {
        if (pipe(pipe_fd)) {
                goto FREE_PI;
                goto FREE_PI;
        }
        }
 
 
        child_fd = pipe_fd[child_writing];
        child_fd = pipe_fd[child_writing];
        parent_fd = pipe_fd[1-child_writing];
        parent_fd = pipe_fd[1-child_writing];
 
 
        if (!(fp = fdopen(parent_fd, modes))) {
        if (!(fp = fdopen(parent_fd, modes))) {
                close(parent_fd);
                close(parent_fd);
                close(child_fd);
                close(child_fd);
                goto FREE_PI;
                goto FREE_PI;
        }
        }
 
 
        VFORK_LOCK;
        VFORK_LOCK;
        if ((pid = vfork()) == 0) {      /* Child of vfork... */
        if ((pid = vfork()) == 0) {      /* Child of vfork... */
                close(parent_fd);
                close(parent_fd);
                if (child_fd != child_writing) {
                if (child_fd != child_writing) {
                        dup2(child_fd, child_writing);
                        dup2(child_fd, child_writing);
                        close(child_fd);
                        close(child_fd);
                }
                }
 
 
                /* SUSv3 requires that any previously popen()'d streams in the
                /* SUSv3 requires that any previously popen()'d streams in the
                 * parent shall be closed in the child. */
                 * parent shall be closed in the child. */
                for (po = popen_list ; po ; po = po->next) {
                for (po = popen_list ; po ; po = po->next) {
                        close(po->f->__filedes);
                        close(po->f->__filedes);
                }
                }
 
 
                execl("/bin/sh", "sh", "-c", command, (char *)0);
                execl("/bin/sh", "sh", "-c", command, (char *)0);
 
 
                /* SUSv3 mandates an exit code of 127 for the child if the
                /* SUSv3 mandates an exit code of 127 for the child if the
                 * command interpreter can not be invoked. */
                 * command interpreter can not be invoked. */
                _exit(127);
                _exit(127);
        }
        }
        VFORK_UNLOCK;
        VFORK_UNLOCK;
 
 
        /* We need to close the child filedes whether vfork failed or
        /* We need to close the child filedes whether vfork failed or
         * it succeeded and we're in the parent. */
         * it succeeded and we're in the parent. */
        close(child_fd);
        close(child_fd);
 
 
        if (pid > 0) {                           /* Parent of vfork... */
        if (pid > 0) {                           /* Parent of vfork... */
                pi->pid = pid;
                pi->pid = pid;
                pi->f = fp;
                pi->f = fp;
                LOCK;
                LOCK;
                pi->next = popen_list;
                pi->next = popen_list;
                popen_list = pi;
                popen_list = pi;
                UNLOCK;
                UNLOCK;
 
 
                return fp;
                return fp;
        }
        }
 
 
        /* If we get here, vfork failed. */
        /* If we get here, vfork failed. */
        fclose(fp);                                     /* Will close parent_fd. */
        fclose(fp);                                     /* Will close parent_fd. */
 
 
 FREE_PI:
 FREE_PI:
        free(pi);
        free(pi);
 
 
 RET_NULL:
 RET_NULL:
        return NULL;
        return NULL;
}
}
 
 
int pclose(FILE *stream)
int pclose(FILE *stream)
{
{
        struct popen_list_item *p;
        struct popen_list_item *p;
        int stat;
        int stat;
        pid_t pid;
        pid_t pid;
 
 
        /* First, find the list entry corresponding to stream and remove it
        /* First, find the list entry corresponding to stream and remove it
         * from the list.  Set p to the list item (NULL if not found). */
         * from the list.  Set p to the list item (NULL if not found). */
        LOCK;
        LOCK;
        if ((p = popen_list) != NULL) {
        if ((p = popen_list) != NULL) {
                if (p->f == stream) {
                if (p->f == stream) {
                        popen_list = p->next;
                        popen_list = p->next;
                } else {
                } else {
                        struct popen_list_item *t;
                        struct popen_list_item *t;
                        do {
                        do {
                                t = p;
                                t = p;
                                if (!(p = t->next)) {
                                if (!(p = t->next)) {
                                        __set_errno(EINVAL); /* Not required by SUSv3. */
                                        __set_errno(EINVAL); /* Not required by SUSv3. */
                                        break;
                                        break;
                                }
                                }
                                if (p->f == stream) {
                                if (p->f == stream) {
                                        t->next = p->next;
                                        t->next = p->next;
                                        break;
                                        break;
                                }
                                }
                        } while (1);
                        } while (1);
                }
                }
        }
        }
        UNLOCK;
        UNLOCK;
 
 
        if (p) {
        if (p) {
                pid = p->pid;                   /* Save the pid we need */
                pid = p->pid;                   /* Save the pid we need */
                free(p);                                /* and free the list item. */
                free(p);                                /* and free the list item. */
 
 
                fclose(stream); /* The SUSv3 example code ignores the return. */
                fclose(stream); /* The SUSv3 example code ignores the return. */
 
 
                /* SUSv3 specificly requires that pclose not return before the child
                /* SUSv3 specificly requires that pclose not return before the child
                 * terminates, in order to disallow pclose from returning on EINTR. */
                 * terminates, in order to disallow pclose from returning on EINTR. */
                do {
                do {
                        if (waitpid(pid, &stat, 0) >= 0) {
                        if (waitpid(pid, &stat, 0) >= 0) {
                                return stat;
                                return stat;
                        }
                        }
                        if (errno != EINTR) {
                        if (errno != EINTR) {
                                break;
                                break;
                        }
                        }
                } while (1);
                } while (1);
        }
        }
 
 
        return -1;
        return -1;
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.