OpenCoverage

savewd.c

Absolute File Name:/home/opencoverage/opencoverage/guest-scripts/coreutils/src/gnulib/lib/savewd.c
Source codeSwitch to Preprocessed file
LineSourceCount
1/* Save and restore the working directory, possibly using a child process.-
2-
3 Copyright (C) 2006-2007, 2009-2018 Free Software Foundation, Inc.-
4-
5 This program is free software: you can redistribute it and/or modify-
6 it under the terms of the GNU General Public License as published by-
7 the Free Software Foundation; either version 3 of the License, or-
8 (at your option) any later version.-
9-
10 This program is distributed in the hope that it will be useful,-
11 but WITHOUT ANY WARRANTY; without even the implied warranty of-
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the-
13 GNU General Public License for more details.-
14-
15 You should have received a copy of the GNU General Public License-
16 along with this program. If not, see <https://www.gnu.org/licenses/>. */-
17-
18/* Written by Paul Eggert. */-
19-
20#include <config.h>-
21-
22#define SAVEWD_INLINE _GL_EXTERN_INLINE-
23-
24#include "savewd.h"-
25-
26#include <errno.h>-
27#include <fcntl.h>-
28#include <signal.h>-
29#include <stdbool.h>-
30#include <stdlib.h>-
31#include <sys/types.h>-
32#include <sys/wait.h>-
33#include <unistd.h>-
34-
35#include "assure.h"-
36#include "dosname.h"-
37#include "fcntl-safer.h"-
38-
39#ifndef FALLTHROUGH-
40# if __GNUC__ < 7-
41# define FALLTHROUGH ((void) 0)-
42# else-
43# define FALLTHROUGH __attribute__ ((__fallthrough__))-
44# endif-
45#endif-
46-
47/* Save the working directory into *WD, if it hasn't been saved-
48 already. Return true if a child has been forked to do the real-
49 work. */-
50static bool-
51savewd_save (struct savewd *wd)-
52{-
53 switch (wd->state)-
54 {-
55 case INITIAL_STATE:
executed 12 times by 2 tests: case INITIAL_STATE:
Executed by:
  • ginstall
  • mkdir
12
56 /* Save the working directory, or prepare to fall back if possible. */-
57 {-
58 int fd = open_safer (".", O_SEARCH);-
59 if (0 <= fd)
0 <= fdDescription
TRUEevaluated 10 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
FALSEevaluated 2 times by 1 test
Evaluated by:
  • ginstall
2-10
60 {-
61 wd->state = FD_STATE;-
62 wd->val.fd = fd;-
63 break;
executed 10 times by 2 tests: break;
Executed by:
  • ginstall
  • mkdir
10
64 }-
65 if (errno != EACCES && errno != ESTALE)
(*__errno_location ()) != 13Description
TRUEnever evaluated
FALSEevaluated 2 times by 1 test
Evaluated by:
  • ginstall
(*__errno_location ()) != 116Description
TRUEnever evaluated
FALSEnever evaluated
0-2
66 {-
67 wd->state = ERROR_STATE;-
68 wd->val.errnum = errno;-
69 break;
never executed: break;
0
70 }-
71 }-
72 wd->state = FORKING_STATE;-
73 wd->val.child = -1;-
74 FALLTHROUGH;-
75 case FORKING_STATE:
code before this statement executed 2 times by 1 test: case FORKING_STATE:
Executed by:
  • ginstall
executed 2 times by 1 test: case FORKING_STATE:
Executed by:
  • ginstall
2
76 if (wd->val.child < 0)
wd->val.child < 0Description
TRUEevaluated 4 times by 1 test
Evaluated by:
  • ginstall
FALSEnever evaluated
0-4
77 {-
78 /* "Save" the initial working directory by forking a new-
79 subprocess that will attempt all the work from the chdir-
80 until the next savewd_restore. */-
81 wd->val.child = fork ();-
82 if (wd->val.child != 0)
wd->val.child != 0Description
TRUEevaluated 4 times by 1 test
Evaluated by:
  • ginstall
FALSEnever evaluated
0-4
83 {-
84 if (0 < wd->val.child)
0 < wd->val.childDescription
TRUEevaluated 4 times by 1 test
Evaluated by:
  • ginstall
FALSEnever evaluated
0-4
85 return true;
executed 4 times by 1 test: return 1 ;
Executed by:
  • ginstall
4
86 wd->state = ERROR_STATE;-
87 wd->val.errnum = errno;-
88 }
never executed: end of block
0
89 }
never executed: end of block
0
90 break;
never executed: break;
0
91-
92 case FD_STATE:
executed 3 times by 1 test: case FD_STATE:
Executed by:
  • mkdir
3
93 case FD_POST_CHDIR_STATE:
executed 18 times by 2 tests: case FD_POST_CHDIR_STATE:
Executed by:
  • ginstall
  • mkdir
18
94 case ERROR_STATE:
never executed: case ERROR_STATE:
0
95 case FINAL_STATE:
executed 12275 times by 2 tests: case FINAL_STATE:
Executed by:
  • ginstall
  • mkdir
12275
96 break;
executed 12296 times by 2 tests: break;
Executed by:
  • ginstall
  • mkdir
12296
97-
98 default:
never executed: default:
0
99 assure (false);-
100 }
never executed: end of block
0
101-
102 return false;
executed 12306 times by 2 tests: return 0 ;
Executed by:
  • ginstall
  • mkdir
12306
103}-
104-
105int-
106savewd_chdir (struct savewd *wd, char const *dir, int options,-
107 int open_result[2])-
108{-
109 int fd = -1;-
110 int result = 0;-
111-
112 /* Open the directory if requested, or if avoiding a race condition-
113 is requested and possible. */-
114 if (open_result
open_resultDescription
TRUEevaluated 9 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
FALSEevaluated 12310 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
9-12310
115 || (options & (HAVE_WORKING_O_NOFOLLOW ? SAVEWD_CHDIR_NOFOLLOW : 0)))
(options & (1 ...NOFOLLOW : 0))Description
TRUEevaluated 12138 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
FALSEevaluated 172 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
172-12138
116 {-
117 fd = open (dir,-
118 (O_SEARCH | O_DIRECTORY | O_NOCTTY | O_NONBLOCK-
119 | (options & SAVEWD_CHDIR_NOFOLLOW ? O_NOFOLLOW : 0)));-
120-
121 if (open_result)
open_resultDescription
TRUEevaluated 9 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
FALSEevaluated 12138 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
9-12138
122 {-
123 open_result[0] = fd;-
124 open_result[1] = errno;-
125 }
executed 9 times by 2 tests: end of block
Executed by:
  • ginstall
  • mkdir
9
126-
127 if (fd < 0 && errno != EACCES)
fd < 0Description
TRUEnever evaluated
FALSEevaluated 12147 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
(*__errno_location ()) != 13Description
TRUEnever evaluated
FALSEnever evaluated
0-12147
128 result = -1;
never executed: result = -1;
0
129 }
executed 12147 times by 2 tests: end of block
Executed by:
  • ginstall
  • mkdir
12147
130-
131 if (result == 0 && ! (0 <= fd && options & SAVEWD_CHDIR_SKIP_READABLE))
result == 0Description
TRUEevaluated 12319 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
FALSEnever evaluated
0 <= fdDescription
TRUEevaluated 12147 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
FALSEevaluated 172 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
options & SAVE..._SKIP_READABLEDescription
TRUEevaluated 9 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
FALSEevaluated 12138 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
0-12319
132 {-
133 if (savewd_save (wd))
savewd_save (wd)Description
TRUEevaluated 4 times by 1 test
Evaluated by:
  • ginstall
FALSEevaluated 12306 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
4-12306
134 {-
135 open_result = NULL;-
136 result = -2;-
137 }
executed 4 times by 1 test: end of block
Executed by:
  • ginstall
4
138 else-
139 {-
140 result = (fd < 0 ? chdir (dir) : fchdir (fd));
fd < 0Description
TRUEevaluated 169 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
FALSEevaluated 12137 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
169-12137
141-
142 if (result == 0)
result == 0Description
TRUEevaluated 12305 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
FALSEevaluated 1 time by 1 test
Evaluated by:
  • ginstall
1-12305
143 switch (wd->state)-
144 {-
145 case FD_STATE:
executed 13 times by 2 tests: case FD_STATE:
Executed by:
  • ginstall
  • mkdir
13
146 wd->state = FD_POST_CHDIR_STATE;-
147 break;
executed 13 times by 2 tests: break;
Executed by:
  • ginstall
  • mkdir
13
148-
149 case ERROR_STATE:
never executed: case ERROR_STATE:
0
150 case FD_POST_CHDIR_STATE:
executed 18 times by 2 tests: case FD_POST_CHDIR_STATE:
Executed by:
  • ginstall
  • mkdir
18
151 case FINAL_STATE:
executed 12274 times by 2 tests: case FINAL_STATE:
Executed by:
  • ginstall
  • mkdir
12274
152 break;
executed 12292 times by 2 tests: break;
Executed by:
  • ginstall
  • mkdir
12292
153-
154 case FORKING_STATE:
never executed: case FORKING_STATE:
0
155 assure (wd->val.child == 0);-
156 break;
never executed: break;
0
157-
158 default:
never executed: default:
0
159 assure (false);-
160 }
never executed: end of block
0
161 }
executed 12306 times by 2 tests: end of block
Executed by:
  • ginstall
  • mkdir
12306
162 }-
163-
164 if (0 <= fd && ! open_result)
0 <= fdDescription
TRUEevaluated 12147 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
FALSEevaluated 172 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
! open_resultDescription
TRUEevaluated 12138 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
FALSEevaluated 9 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
9-12147
165 {-
166 int e = errno;-
167 close (fd);-
168 errno = e;-
169 }
executed 12138 times by 2 tests: end of block
Executed by:
  • ginstall
  • mkdir
12138
170-
171 return result;
executed 12319 times by 2 tests: return result;
Executed by:
  • ginstall
  • mkdir
12319
172}-
173-
174int-
175savewd_restore (struct savewd *wd, int status)-
176{-
177 switch (wd->state)-
178 {-
179 case INITIAL_STATE:
executed 10013 times by 2 tests: case INITIAL_STATE:
Executed by:
  • ginstall
  • mkdir
10013
180 case FD_STATE:
executed 2 times by 1 test: case FD_STATE:
Executed by:
  • mkdir
2
181 /* The working directory is the desired directory, so there's no-
182 work to do. */-
183 break;
executed 10015 times by 2 tests: break;
Executed by:
  • ginstall
  • mkdir
10015
184-
185 case FD_POST_CHDIR_STATE:
executed 13 times by 2 tests: case FD_POST_CHDIR_STATE:
Executed by:
  • ginstall
  • mkdir
13
186 /* Restore the working directory using fchdir. */-
187 if (fchdir (wd->val.fd) == 0)
fchdir (wd->val.fd) == 0Description
TRUEevaluated 13 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
FALSEnever evaluated
0-13
188 {-
189 wd->state = FD_STATE;-
190 break;
executed 13 times by 2 tests: break;
Executed by:
  • ginstall
  • mkdir
13
191 }-
192 else-
193 {-
194 int chdir_errno = errno;-
195 close (wd->val.fd);-
196 wd->state = ERROR_STATE;-
197 wd->val.errnum = chdir_errno;-
198 }
never executed: end of block
0
199 FALLTHROUGH;-
200 case ERROR_STATE:
code before this statement never executed: case ERROR_STATE:
never executed: case ERROR_STATE:
0
201 /* Report an error if asked to restore the working directory. */-
202 errno = wd->val.errnum;-
203 return -1;
never executed: return -1;
0
204-
205 case FORKING_STATE:
executed 4 times by 1 test: case FORKING_STATE:
Executed by:
  • ginstall
4
206 /* "Restore" the working directory by waiting for the subprocess-
207 to finish. */-
208 {-
209 pid_t child = wd->val.child;-
210 if (child == 0)
child == 0Description
TRUEnever evaluated
FALSEevaluated 4 times by 1 test
Evaluated by:
  • ginstall
0-4
211 _exit (status);
never executed: _exit (status);
0
212 if (0 < child)
0 < childDescription
TRUEevaluated 4 times by 1 test
Evaluated by:
  • ginstall
FALSEnever evaluated
0-4
213 {-
214 int child_status;-
215 while (waitpid (child, &child_status, 0) < 0)
waitpid (child...status, 0) < 0Description
TRUEnever evaluated
FALSEevaluated 4 times by 1 test
Evaluated by:
  • ginstall
0-4
216 assure (errno == EINTR);
never executed: (((*__errno_location ()) == 4) ? (void) (0) : __assert_fail ( "(*__errno_location ()) == 4" , "lib/savewd.c", 216, __PRETTY_FUNCTION__)) ;
0
217 wd->val.child = -1;-
218 if (! WIFEXITED (child_status))
! ((( child_st... & 0x7f) == 0)Description
TRUEnever evaluated
FALSEevaluated 4 times by 1 test
Evaluated by:
  • ginstall
0-4
219 raise (WTERMSIG (child_status));
never executed: raise ( (( child_status ) & 0x7f) );
0
220 return WEXITSTATUS (child_status);
executed 4 times by 1 test: return ((( child_status ) & 0xff00) >> 8) ;
Executed by:
  • ginstall
4
221 }-
222 }-
223 break;
never executed: break;
0
224-
225 default:
never executed: default:
0
226 assure (false);-
227 }
never executed: end of block
0
228-
229 return 0;
executed 10028 times by 2 tests: return 0;
Executed by:
  • ginstall
  • mkdir
10028
230}-
231-
232void-
233savewd_finish (struct savewd *wd)-
234{-
235 switch (wd->state)-
236 {-
237 case INITIAL_STATE:
executed 247 times by 2 tests: case INITIAL_STATE:
Executed by:
  • ginstall
  • mkdir
247
238 case ERROR_STATE:
never executed: case ERROR_STATE:
0
239 break;
executed 247 times by 2 tests: break;
Executed by:
  • ginstall
  • mkdir
247
240-
241 case FD_STATE:
executed 10 times by 2 tests: case FD_STATE:
Executed by:
  • ginstall
  • mkdir
10
242 case FD_POST_CHDIR_STATE:
never executed: case FD_POST_CHDIR_STATE:
0
243 close (wd->val.fd);-
244 break;
executed 10 times by 2 tests: break;
Executed by:
  • ginstall
  • mkdir
10
245-
246 case FORKING_STATE:
executed 2 times by 1 test: case FORKING_STATE:
Executed by:
  • ginstall
2
247 assure (wd->val.child < 0);-
248 break;
executed 2 times by 1 test: break;
Executed by:
  • ginstall
2
249-
250 default:
never executed: default:
0
251 assure (false);-
252 }
never executed: end of block
0
253-
254 wd->state = FINAL_STATE;-
255}
executed 259 times by 2 tests: end of block
Executed by:
  • ginstall
  • mkdir
259
256-
257/* Return true if the actual work is currently being done by a-
258 subprocess.-
259-
260 A true return means that the caller and the subprocess should-
261 resynchronize later with savewd_restore, using only their own-
262 memory to decide when to resynchronize; they should not consult the-
263 file system to decide, because that might lead to race conditions.-
264 This is why savewd_chdir is broken out into another function;-
265 savewd_chdir's callers _can_ inspect the file system to decide-
266 whether to call savewd_chdir. */-
267static bool-
268savewd_delegating (struct savewd const *wd)-
269{-
270 return wd->state == FORKING_STATE && 0 < wd->val.child;
executed 10027 times by 2 tests: return wd->state == FORKING_STATE && 0 < wd->val.child;
Executed by:
  • ginstall
  • mkdir
10027
271}-
272-
273int-
274savewd_process_files (int n_files, char **file,-
275 int (*act) (char *, struct savewd *, void *),-
276 void *options)-
277{-
278 int i = 0;-
279 int last_relative;-
280 int exit_status = EXIT_SUCCESS;-
281 struct savewd wd;-
282 savewd_init (&wd);-
283-
284 for (last_relative = n_files - 1; 0 <= last_relative; last_relative--)
0 <= last_relativeDescription
TRUEevaluated 254 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
FALSEnever evaluated
0-254
285 if (! IS_ABSOLUTE_FILE_NAME (file[last_relative]))
(((file[last_r...])[0]) == '/')Description
TRUEnever evaluated
FALSEevaluated 254 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
0 != 0Description
TRUEnever evaluated
FALSEevaluated 254 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
0-254
286 break;
executed 254 times by 2 tests: break;
Executed by:
  • ginstall
  • mkdir
254
287-
288 for (; i < last_relative; i++)
i < last_relativeDescription
TRUEevaluated 10027 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
FALSEevaluated 254 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
254-10027
289 {-
290 if (! savewd_delegating (&wd))
! savewd_delegating (&wd)Description
TRUEevaluated 10027 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
FALSEnever evaluated
0-10027
291 {-
292 int s = act (file[i], &wd, options);-
293 if (exit_status < s)
exit_status < sDescription
TRUEnever evaluated
FALSEevaluated 10027 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
0-10027
294 exit_status = s;
never executed: exit_status = s;
0
295 }
executed 10027 times by 2 tests: end of block
Executed by:
  • ginstall
  • mkdir
10027
296-
297 if (! IS_ABSOLUTE_FILE_NAME (file[i + 1]))
(((file[i + 1])[0]) == '/')Description
TRUEnever evaluated
FALSEevaluated 10027 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
0 != 0Description
TRUEnever evaluated
FALSEevaluated 10027 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
0-10027
298 {-
299 int r = savewd_restore (&wd, exit_status);-
300 if (exit_status < r)
exit_status < rDescription
TRUEevaluated 1 time by 1 test
Evaluated by:
  • ginstall
FALSEevaluated 10026 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
1-10026
301 exit_status = r;
executed 1 time by 1 test: exit_status = r;
Executed by:
  • ginstall
1
302 }
executed 10027 times by 2 tests: end of block
Executed by:
  • ginstall
  • mkdir
10027
303 }
executed 10027 times by 2 tests: end of block
Executed by:
  • ginstall
  • mkdir
10027
304-
305 savewd_finish (&wd);-
306-
307 for (; i < n_files; i++)
i < n_filesDescription
TRUEevaluated 254 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
FALSEevaluated 254 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
254
308 {-
309 int s = act (file[i], &wd, options);-
310 if (exit_status < s)
exit_status < sDescription
TRUEnever evaluated
FALSEevaluated 254 times by 2 tests
Evaluated by:
  • ginstall
  • mkdir
0-254
311 exit_status = s;
never executed: exit_status = s;
0
312 }
executed 254 times by 2 tests: end of block
Executed by:
  • ginstall
  • mkdir
254
313-
314 return exit_status;
executed 254 times by 2 tests: return exit_status;
Executed by:
  • ginstall
  • mkdir
254
315}-
Source codeSwitch to Preprocessed file

Generated by Squish Coco 4.1.2