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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [uClibc/] [libc/] [stdio/] [popen.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1325 phoenix
/*  Copyright (C) 2004     Manuel Novoa III
2
 *
3
 *  This library is free software; you can redistribute it and/or
4
 *  modify it under the terms of the GNU Library General Public
5
 *  License as published by the Free Software Foundation; either
6
 *  version 2 of the License, or (at your option) any later version.
7
 *
8
 *  This library is distributed in the hope that it will be useful,
9
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
 *  Library General Public License for more details.
12
 *
13
 *  You should have received a copy of the GNU Library General Public
14
 *  License along with this library; if not, write to the Free
15
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16
 */
17
 
18
/* Jan 1, 2004
19
 *
20
 * Rewrite popen for SUSv3 compliance.
21
 *   Added a list of popen()'d to store pids and use waitpid() in pclose().
22
 *   Loop on waitpid() failure due to EINTR as required.
23
 *   Close parent's popen()'d FILEs in the {v}fork()'d child.
24
 *   Fix failure exit code for failed execve().
25
 */
26
 
27
 
28
#include <stdio.h>
29
#include <stdlib.h>
30
#include <errno.h>
31
#include <unistd.h>
32
#include <sys/wait.h>
33
 
34
/* uClinux-2.0 has vfork, but Linux 2.0 doesn't */
35
#include <sys/syscall.h>
36
#if ! defined __NR_vfork
37
# define vfork fork     
38
# define VFORK_LOCK             ((void) 0)
39
# define VFORK_UNLOCK   ((void) 0)
40
#endif
41
 
42
#ifdef __UCLIBC_HAS_THREADS__
43
#include <pthread.h>
44
static pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
45
# define LOCK                   __pthread_mutex_lock(&mylock)
46
# define UNLOCK                 __pthread_mutex_unlock(&mylock);
47
#else
48
# define LOCK                   ((void) 0)
49
# define UNLOCK                 ((void) 0)
50
#endif      
51
 
52
#ifndef VFORK_LOCK
53
# define VFORK_LOCK             LOCK
54
# define VFORK_UNLOCK   UNLOCK
55
#endif
56
 
57
/* Temporarily support old stdio code. */
58
#ifndef __MASK_READING
59
#define __filedes               filedes
60
#endif
61
 
62
struct popen_list_item {
63
        struct popen_list_item *next;
64
        FILE *f;
65
        pid_t pid;
66
};
67
 
68
static struct popen_list_item *popen_list /* = NULL (bss initialized) */;
69
 
70
FILE *popen(const char *command, const char *modes)
71
{
72
        FILE *fp;
73
        struct popen_list_item *pi;
74
        struct popen_list_item *po;
75
        int pipe_fd[2];
76
        int parent_fd;
77
        int child_fd;
78
        int child_writing;                      /* Doubles as the desired child fildes. */
79
        pid_t pid;
80
 
81
        child_writing = 0;                       /* Assume child is writing. */
82
        if (modes[0] != 'w') {           /* Parent not writing... */
83
                ++child_writing;                /* so child must be writing. */
84
                if (modes[0] != 'r') {   /* Oops!  Parent not reading either! */
85
                        __set_errno(EINVAL);
86
                        goto RET_NULL;
87
                }
88
        }
89
 
90
        if (!(pi = malloc(sizeof(struct popen_list_item)))) {
91
                goto RET_NULL;
92
        }
93
 
94
        if (pipe(pipe_fd)) {
95
                goto FREE_PI;
96
        }
97
 
98
        child_fd = pipe_fd[child_writing];
99
        parent_fd = pipe_fd[1-child_writing];
100
 
101
        if (!(fp = fdopen(parent_fd, modes))) {
102
                close(parent_fd);
103
                close(child_fd);
104
                goto FREE_PI;
105
        }
106
 
107
        VFORK_LOCK;
108
        if ((pid = vfork()) == 0) {      /* Child of vfork... */
109
                close(parent_fd);
110
                if (child_fd != child_writing) {
111
                        dup2(child_fd, child_writing);
112
                        close(child_fd);
113
                }
114
 
115
                /* SUSv3 requires that any previously popen()'d streams in the
116
                 * parent shall be closed in the child. */
117
                for (po = popen_list ; po ; po = po->next) {
118
                        close(po->f->__filedes);
119
                }
120
 
121
                execl("/bin/sh", "sh", "-c", command, (char *)0);
122
 
123
                /* SUSv3 mandates an exit code of 127 for the child if the
124
                 * command interpreter can not be invoked. */
125
                _exit(127);
126
        }
127
        VFORK_UNLOCK;
128
 
129
        /* We need to close the child filedes whether vfork failed or
130
         * it succeeded and we're in the parent. */
131
        close(child_fd);
132
 
133
        if (pid > 0) {                           /* Parent of vfork... */
134
                pi->pid = pid;
135
                pi->f = fp;
136
                LOCK;
137
                pi->next = popen_list;
138
                popen_list = pi;
139
                UNLOCK;
140
 
141
                return fp;
142
        }
143
 
144
        /* If we get here, vfork failed. */
145
        fclose(fp);                                     /* Will close parent_fd. */
146
 
147
 FREE_PI:
148
        free(pi);
149
 
150
 RET_NULL:
151
        return NULL;
152
}
153
 
154
int pclose(FILE *stream)
155
{
156
        struct popen_list_item *p;
157
        int stat;
158
        pid_t pid;
159
 
160
        /* First, find the list entry corresponding to stream and remove it
161
         * from the list.  Set p to the list item (NULL if not found). */
162
        LOCK;
163
        if ((p = popen_list) != NULL) {
164
                if (p->f == stream) {
165
                        popen_list = p->next;
166
                } else {
167
                        struct popen_list_item *t;
168
                        do {
169
                                t = p;
170
                                if (!(p = t->next)) {
171
                                        __set_errno(EINVAL); /* Not required by SUSv3. */
172
                                        break;
173
                                }
174
                                if (p->f == stream) {
175
                                        t->next = p->next;
176
                                        break;
177
                                }
178
                        } while (1);
179
                }
180
        }
181
        UNLOCK;
182
 
183
        if (p) {
184
                pid = p->pid;                   /* Save the pid we need */
185
                free(p);                                /* and free the list item. */
186
 
187
                fclose(stream); /* The SUSv3 example code ignores the return. */
188
 
189
                /* SUSv3 specificly requires that pclose not return before the child
190
                 * terminates, in order to disallow pclose from returning on EINTR. */
191
                do {
192
                        if (waitpid(pid, &stat, 0) >= 0) {
193
                                return stat;
194
                        }
195
                        if (errno != EINTR) {
196
                                break;
197
                        }
198
                } while (1);
199
        }
200
 
201
        return -1;
202
}

powered by: WebSVN 2.1.0

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