1010#import " ZBDevice.h"
1111#import " spawn.h"
1212
13- typedef struct ZBCommandFds {
14- int stdOut[2 ];
15- int stdErr[2 ];
16- int finish[2 ];
17- } ZBCommandFds;
13+ @interface ZBPipe : NSObject {
14+ @public
15+ int fds[2 ];
16+ }
17+ - (void )close ;
18+ - (void )closeRead ;
19+ - (void )closeWrite ;
20+ @end
21+
22+ @implementation ZBPipe
23+ - (instancetype )init {
24+ self = [super init ];
25+ if (![self open ]) {
26+ return nil ;
27+ }
28+ return self;
29+ }
30+ - (BOOL )open {
31+ if (pipe (fds) == -1 ) return NO ;
32+ return YES ;
33+ }
34+ - (void )close {
35+ [self closeRead ];
36+ [self closeWrite ];
37+ }
38+ - (void )closeRead {
39+ [self close: 0 ];
40+ }
41+ - (void )closeWrite {
42+ [self close: 1 ];
43+ }
44+ - (void )close : (int )idx {
45+ NSParameterAssert (idx == 0 || idx == 1 );
46+ if (fds[idx] > 0 ) {
47+ close (fds[idx]);
48+ fds[idx] = -1 ;
49+ }
50+ }
51+ @end
52+
53+ @interface ZBCommandFds : NSObject {
54+ @public
55+ ZBPipe *stdOut;
56+ ZBPipe *stdErr;
57+ ZBPipe *finish;
58+ }
59+ + (instancetype )useFinish : (BOOL )useFinishFd ;
60+ - (void )close ;
61+ - (void )closeRead : (BOOL )useFinishFd ;
62+ - (void )closeWrite : (BOOL )useFinishFd ;
63+ @end
64+
65+ @implementation ZBCommandFds
66+
67+ + (instancetype )useFinish : (BOOL )useFinishFd {
68+ ZBCommandFds *fds = [ZBCommandFds new ];
69+ fds->stdOut = [ZBPipe new ];
70+ fds->stdErr = [ZBPipe new ];
71+
72+ if (!fds->stdOut || !fds->stdErr ) {
73+ return nil ;
74+ }
75+
76+ if (useFinishFd) {
77+ fds->finish = [ZBPipe new ];
78+ if (!fds->finish ) return nil ;
79+ }
80+
81+ return fds;
82+ }
83+
84+ - (void )close {
85+ [self closeRead ];
86+ [self closeWrite ];
87+ }
88+ - (void )closeRead {
89+ [self ->stdOut closeRead ];
90+ [self ->stdErr closeRead ];
91+ [self ->finish closeRead ];
92+ }
93+ - (void )closeWrite {
94+ [self ->stdOut closeWrite ];
95+ [self ->stdErr closeWrite ];
96+ [self ->finish closeWrite ];
97+ }
98+ @end
1899
19100static const int ZBCommandFinishFileno = 3 ;
20101
@@ -105,19 +186,11 @@ - (void)setUseFinishFd:(BOOL)useFinishFd {
105186
106187- (int )execute {
107188 // Create output and error pipes
108- fds = malloc (sizeof (ZBCommandFds));
109- if (pipe (fds->stdOut ) == -1 || pipe (fds->stdErr ) == -1 ) {
110- free (fds);
189+ fds = [ZBCommandFds useFinish: _useFinishFd];
190+ if (!fds) {
111191 return errno; // pipe() sets errno on failure
112192 }
113193
114- if (_useFinishFd) {
115- if (pipe (fds->finish ) == -1 ) {
116- free (fds);
117- return errno; // pipe() sets errno on failure
118- }
119- }
120-
121194 // Convert our arguments array from NSStrings to char pointers
122195 char **argv = (char **)malloc ((_arguments.count + 1 ) * sizeof (char *));
123196 for (int i = 0 ; i < _arguments.count ; i++) {
@@ -145,17 +218,17 @@ - (int)execute {
145218 // Create our file actions to read data back from posix_spawn
146219 posix_spawn_file_actions_t child_fd_actions;
147220 posix_spawn_file_actions_init (&child_fd_actions);
148- posix_spawn_file_actions_addclose (&child_fd_actions, fds->stdOut [0 ]);
149- posix_spawn_file_actions_addclose (&child_fd_actions, fds->stdErr [0 ]);
150- posix_spawn_file_actions_adddup2 (&child_fd_actions, fds->stdOut [1 ], STDOUT_FILENO);
151- posix_spawn_file_actions_adddup2 (&child_fd_actions, fds->stdErr [1 ], STDERR_FILENO);
152- posix_spawn_file_actions_addclose (&child_fd_actions, fds->stdOut [1 ]);
153- posix_spawn_file_actions_addclose (&child_fd_actions, fds->stdErr [1 ]);
221+ posix_spawn_file_actions_addclose (&child_fd_actions, fds->stdOut -> fds [0 ]);
222+ posix_spawn_file_actions_addclose (&child_fd_actions, fds->stdErr -> fds [0 ]);
223+ posix_spawn_file_actions_adddup2 (&child_fd_actions, fds->stdOut -> fds [1 ], STDOUT_FILENO);
224+ posix_spawn_file_actions_adddup2 (&child_fd_actions, fds->stdErr -> fds [1 ], STDERR_FILENO);
225+ posix_spawn_file_actions_addclose (&child_fd_actions, fds->stdOut -> fds [1 ]);
226+ posix_spawn_file_actions_addclose (&child_fd_actions, fds->stdErr -> fds [1 ]);
154227
155228 if (_useFinishFd) {
156- posix_spawn_file_actions_addclose (&child_fd_actions, fds->finish [0 ]);
157- posix_spawn_file_actions_adddup2 (&child_fd_actions, fds->finish [1 ], ZBCommandFinishFileno);
158- posix_spawn_file_actions_addclose (&child_fd_actions, fds->finish [1 ]);
229+ posix_spawn_file_actions_addclose (&child_fd_actions, fds->finish -> fds [0 ]);
230+ posix_spawn_file_actions_adddup2 (&child_fd_actions, fds->finish -> fds [1 ], ZBCommandFinishFileno);
231+ posix_spawn_file_actions_addclose (&child_fd_actions, fds->finish -> fds [1 ]);
159232 }
160233
161234 // Create persona config if needed
@@ -175,12 +248,12 @@ - (int)execute {
175248 dispatch_queue_t readQueue = dispatch_queue_create (" xyz.willy.Zebra.david" , DISPATCH_QUEUE_CONCURRENT);
176249
177250 // Setup the dispatch handler for the output pipes
178- dispatch_source_t stdOutSource = dispatch_source_create (DISPATCH_SOURCE_TYPE_READ, fds->stdOut [0 ], 0 , readQueue);
179- dispatch_source_t stdErrSource = dispatch_source_create (DISPATCH_SOURCE_TYPE_READ, fds->stdErr [0 ], 0 , readQueue);
251+ dispatch_source_t stdOutSource = dispatch_source_create (DISPATCH_SOURCE_TYPE_READ, fds->stdOut -> fds [0 ], 0 , readQueue);
252+ dispatch_source_t stdErrSource = dispatch_source_create (DISPATCH_SOURCE_TYPE_READ, fds->stdErr -> fds [0 ], 0 , readQueue);
180253 dispatch_source_t finishSource = nil ;
181254
182255 if (_useFinishFd) {
183- finishSource = dispatch_source_create (DISPATCH_SOURCE_TYPE_READ, fds->finish [0 ], 0 , readQueue);
256+ finishSource = dispatch_source_create (DISPATCH_SOURCE_TYPE_READ, fds->finish -> fds [0 ], 0 , readQueue);
184257 }
185258
186259 void (^handleSourceEvent)(dispatch_source_t , int , void (^)(NSString *)) = ^(dispatch_source_t source, int fd, void (^action)(NSString *)) {
@@ -202,37 +275,39 @@ - (int)execute {
202275 free (buffer);
203276 };
204277
278+ ZBCommandFds *fds = self->fds ;
279+
205280 dispatch_source_set_event_handler (stdOutSource, ^{
206- handleSourceEvent (stdOutSource, self-> fds ->stdOut [0 ], ^(NSString *string) {
281+ handleSourceEvent (stdOutSource, fds->stdOut -> fds [0 ], ^(NSString *string) {
207282 if (self->delegate ) [self ->delegate receivedData: string];
208283 if (self.output ) [self .output appendString: string];
209284 });
210285 });
211286 dispatch_source_set_event_handler (stdErrSource, ^{
212- handleSourceEvent (stdErrSource, self-> fds ->stdErr [0 ], ^(NSString *string) {
287+ handleSourceEvent (stdErrSource, fds->stdErr -> fds [0 ], ^(NSString *string) {
213288 if (self->delegate ) [self ->delegate receivedErrorData: string];
214289 if (self.output ) [self .output appendString: string];
215290 });
216291 });
217292
218293 dispatch_source_set_cancel_handler (stdOutSource, ^{
219- close (self-> fds ->stdOut [ 0 ]) ;
294+ [ fds->stdOut closeRead ] ;
220295 dispatch_semaphore_signal (lock);
221296 });
222297 dispatch_source_set_cancel_handler (stdErrSource, ^{
223- close (self-> fds ->stdErr [ 0 ]) ;
298+ [ fds->stdErr closeRead ] ;
224299 dispatch_semaphore_signal (lock);
225300 });
226301
227302 if (_useFinishFd) {
228303 dispatch_source_set_event_handler (finishSource, ^{
229- handleSourceEvent (finishSource, self-> fds ->finish [0 ], ^(NSString *string) {
304+ handleSourceEvent (finishSource, fds->finish -> fds [0 ], ^(NSString *string) {
230305 if (self->delegate ) [self ->delegate receivedFinishData: string];
231306 });
232307 });
233308 dispatch_source_set_cancel_handler (finishSource, ^{
234309 // Finish fd isn’t expected to be closed, so no semaphore involved here.
235- close (self-> fds ->finish [ 0 ]) ;
310+ [ fds->finish closeRead ] ;
236311 });
237312 }
238313
@@ -251,20 +326,14 @@ - (int)execute {
251326 free (argv);
252327 free (envp);
253328 if (ret < 0 ) {
254- close (fds->stdOut [0 ]);
255- close (fds->stdOut [1 ]);
256- close (fds->stdErr [0 ]);
257- close (fds->stdErr [1 ]);
258- if (_useFinishFd) {
259- close (fds->finish [0 ]);
260- close (fds->finish [1 ]);
261- }
329+ [fds close ];
330+ fds = nil ;
262331 return ret;
263332 }
264333
265334 // Close the write ends of the pipes so no odd data comes through them
266- close ( fds->stdOut [ 1 ]) ;
267- close ( fds->stdErr [ 1 ]) ;
335+ [ fds->stdOut closeWrite ] ;
336+ [ fds->stdErr closeWrite ] ;
268337
269338 // We need to wait twice, once for the output handler and once for the error handler
270339 dispatch_semaphore_wait (lock, DISPATCH_TIME_FOREVER);
@@ -280,7 +349,7 @@ - (int)execute {
280349 }
281350
282351 // Free our pipes
283- free ( fds) ;
352+ fds = nil ;
284353
285354 // Get the true status code, if the process exited normally. If it died for some other reason,
286355 // we return the actual value we got back from waitpid(3), which should still be useful for
0 commit comments