Commit | Line | Data |
---|---|---|
b317b99d | 1 | .\" -*-nroff-*- |
c4ccbbf9 MW |
2 | .\" |
3 | .\" Manual for descriptor juggling | |
4 | .\" | |
5 | .\" (c) 2009, 2023, 2024 Straylight/Edgeware | |
6 | .\" | |
7 | . | |
8 | .\"----- Licensing notice --------------------------------------------------- | |
9 | .\" | |
10 | .\" This file is part of the mLib utilities library. | |
11 | .\" | |
12 | .\" mLib is free software: you can redistribute it and/or modify it under | |
13 | .\" the terms of the GNU Library General Public License as published by | |
14 | .\" the Free Software Foundation; either version 2 of the License, or (at | |
15 | .\" your option) any later version. | |
16 | .\" | |
17 | .\" mLib is distributed in the hope that it will be useful, but WITHOUT | |
18 | .\" ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
19 | .\" FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public | |
20 | .\" License for more details. | |
21 | .\" | |
22 | .\" You should have received a copy of the GNU Library General Public | |
23 | .\" License along with mLib. If not, write to the Free Software | |
24 | .\" Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | |
25 | .\" USA. | |
26 | . | |
27 | .\"-------------------------------------------------------------------------- | |
28 | .so ../defs.man \" @@@PRE@@@ | |
29 | . | |
30 | .\"-------------------------------------------------------------------------- | |
31 | .TH mdup 3mLib "4 January" "Straylight/Edgeware" "mLib utilities library" | |
32 | .\" @mdup | |
33 | . | |
34 | .\"-------------------------------------------------------------------------- | |
b317b99d MW |
35 | .SH NAME |
36 | mdup \- renumber file descriptors | |
c4ccbbf9 MW |
37 | . |
38 | .\"-------------------------------------------------------------------------- | |
b317b99d | 39 | .SH SYNOPSIS |
c4ccbbf9 | 40 | . |
8128dcdf | 41 | .nf |
b317b99d | 42 | .B "#include <mLib/mdup.h>" |
d056fbdf | 43 | .PP |
adec5584 | 44 | .ta 2n |
4729aa69 | 45 | .B "typedef struct {" |
adec5584 MW |
46 | .B " int cur;" |
47 | .B " int want;" | |
4729aa69 | 48 | .B "} mdup_fd;" |
d056fbdf | 49 | .PP |
b317b99d | 50 | .BI "int mdup(mdup_fd *" v ", size_t " n ");" |
8128dcdf | 51 | .fi |
c4ccbbf9 MW |
52 | . |
53 | .\"-------------------------------------------------------------------------- | |
b317b99d | 54 | .SH DESCRIPTION |
c4ccbbf9 | 55 | . |
b317b99d MW |
56 | The |
57 | .B mdup | |
58 | function renumbers file descriptors, using the | |
59 | .BR dup (2) | |
60 | and | |
61 | .BR dup2 (2) | |
62 | system calls. Its arguments are a pointer | |
63 | .I v | |
64 | to a vector of | |
65 | .B mdup_fd | |
66 | structures, and the length | |
67 | .I n | |
4729aa69 | 68 | of this vector, in elements. Each `slot' (element) in the vector |
b317b99d MW |
69 | .I v |
70 | represents a file. The slot's | |
71 | .B cur | |
72 | member names the current file descriptor for this file; the | |
73 | .B want | |
74 | member is the file descriptor to move it to. In order to keep a file | |
75 | alive when you don't care which descriptor it ends up with, set | |
76 | .I want | |
77 | = \-1. Several slots may specify the same | |
78 | .B cur | |
79 | descriptor; but they all have to declare different | |
80 | .BR want s | |
81 | (except that several slots may have | |
82 | .I want | |
83 | = \-1. | |
84 | .PP | |
85 | On successful exit, the function will have rearranged the file | |
86 | descriptors as requested. To reflect this, the | |
87 | .B cur | |
88 | members will all be set to match the | |
89 | .B want | |
90 | members (except where the latter are \-1). | |
91 | .PP | |
92 | If there is a failure, then some rearrangement may have been performed | |
93 | and some not; the | |
94 | .B cur | |
95 | members are set to reflect which file descriptors are to be used. | |
96 | .PP | |
97 | The old file descriptors are | |
98 | .IR closed . | |
99 | This is different from usual | |
100 | .BR dup (2) | |
101 | behaviour, of course, but essential for reliable error handling. If you | |
102 | want to keep a particular source file descriptor open as well as make a | |
103 | new copy then specify two slots with the same | |
104 | .BR cur , | |
105 | one with | |
106 | .B want " = " cur | |
107 | and one with the desired output descriptor. | |
108 | .PP | |
109 | The | |
110 | .B mdup | |
111 | function is capable of arbitrary file descriptor remappings. In | |
112 | particular, it works correctly even if the desired remappings contain | |
113 | cycles. | |
c4ccbbf9 | 114 | . |
b317b99d MW |
115 | .SS "Background: the problem that mdup solves" |
116 | The | |
117 | .B mdup | |
118 | function is intended to be used to adjust file descriptors prior to | |
119 | invoking one of the | |
120 | .B exec | |
121 | system calls. The standard use of | |
122 | .BR dup (2) | |
123 | to establish the child process's standard input/output/error files is | |
124 | prone to errors in the case where the newly opened file in fact already | |
125 | has one of the relevant file descriptors. | |
126 | .PP | |
127 | Consider the case where we want to run a process with separate pipes | |
128 | attached to each of the standard descriptors. Typical code looks like | |
129 | this. | |
130 | .VS | |
131 | #define P_INIT { \-1, \-1 } | |
132 | int p_in[2] = P_INIT, p_out[2] = P_INIT, p_err[2] = P_INIT; | |
133 | pid_t kid = -1; | |
134 | int i; | |
d056fbdf | 135 | .VP |
b317b99d MW |
136 | if (pipe(p_in) || pipe(p_out) || pipe(p_err)) goto error; |
137 | if ((kid = fork()) < 0) goto error; | |
138 | if (!kid) { | |
adec5584 MW |
139 | .ta 2n 4n 2n+\w'\fBif ('u |
140 | if (dup2(p_in[0], STDIN_FILENO) < 0 || | |
141 | dup2(p_out[1], STDOUT_FILENO) < 0 || | |
142 | dup2(p_err[2], STDERR_FILENO) < 0 || | |
143 | close(p_in[0]) || close(p_out[0]) || close(p_err[0]) || | |
144 | close(p_in[1]) || close(p_out[1]) || close(p_err[1])) | |
145 | _exit(127); | |
146 | execvp("/bin/sh", "sh", "-c", "...", (char *)0); | |
b317b99d MW |
147 | } |
148 | \&... | |
149 | .VE | |
150 | Now suppose that, in the parent process, the standard input, output and | |
151 | error descriptors are all initially closed. After the calls to | |
152 | .BR pipe (2), | |
153 | descriptors 0, 1, and 2 refer to | |
154 | .BR p_in[0] , | |
155 | .BR p_in[1] , | |
156 | and | |
157 | .B p_out[0] | |
158 | respectively. In the child process, the calls to | |
159 | .BR dup2 (2) | |
160 | rearrange these. But then the | |
161 | .BR close (2) | |
162 | calls will immediately close all three descriptors, before | |
163 | .BR exec ing | |
164 | the child. | |
165 | .PP | |
166 | Here's how to rewrite the above function using | |
167 | .BR mdup . | |
168 | .VS | |
adec5584 | 169 | .ta 2n 4n 2n+\w'\fBmd[0].cur = p_out[1]; 'u |
b317b99d MW |
170 | #define P_INIT { \-1, \-1 } |
171 | int p_in[2] = P_INIT, p_out[2] = P_INIT, p_err[2] = P_INIT; | |
172 | pid_t kid = -1; | |
173 | mdup_fd md[3]; | |
174 | int i; | |
d056fbdf | 175 | .VP |
b317b99d MW |
176 | if (pipe(p_in) || pipe(p_out) || pipe(p_err)) goto error; |
177 | if ((kid = fork()) < 0) goto error; | |
178 | if (!kid) { | |
adec5584 MW |
179 | if (close(p_in[1] || close(p_out[0]) || close(p_err[0])) |
180 | goto _exit(127); | |
181 | md[0].cur = p_in[0]; md[0].want = STDIN_FILENO; | |
182 | md[1].cur = p_out[1]; md[1].want = STDOUT_FILENO; | |
183 | md[2].cur = p_err[1]; md[2].want = STDERR_FILENO; | |
184 | if (mdup(md, 3)) _exit(127); | |
185 | execvp("/bin/sh", "sh", "-c", "...", (char *)0); | |
b317b99d MW |
186 | } |
187 | \&... | |
188 | .VE | |
189 | One can see that, not only is the resulting program more correct, it's | |
190 | also simpler. Note that we close the unwanted ends of the pipes | |
191 | .I before | |
192 | invoking | |
193 | .BR mdup . | |
194 | Closing them afterwards risks interfering with the newly assigned | |
195 | descriptors which are meant to be passed to the child process. Note | |
196 | also that | |
197 | .B mdup | |
198 | has taken responsibility for closing the other descriptors for the | |
199 | wanted ends of the pipes. | |
c4ccbbf9 MW |
200 | . |
201 | .\"-------------------------------------------------------------------------- | |
b317b99d | 202 | .SH "SEE ALSO" |
c4ccbbf9 | 203 | . |
b317b99d MW |
204 | .BR dup (2), |
205 | .BR dup2 (2), | |
206 | .BR mLib (3). | |
c4ccbbf9 MW |
207 | . |
208 | .\"-------------------------------------------------------------------------- | |
b317b99d | 209 | .SH AUTHOR |
c4ccbbf9 | 210 | . |
b317b99d | 211 | Mark Wooding, <mdw@distorted.org.uk> |
c4ccbbf9 MW |
212 | . |
213 | .\"----- That's all, folks -------------------------------------------------- |