1 /* Save and restore the working directory, possibly using a subprocess. 2 3 Copyright (C) 2006, 2009-2021 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 #ifndef SAVEWD_H 21 # define SAVEWD_H 1 22 23 #include <stdbool.h> 24 #include <sys/types.h> 25 26 #ifndef _GL_INLINE_HEADER_BEGIN 27 #error "Please include config.h first." 28 #endif 29 _GL_INLINE_HEADER_BEGIN 30 #ifndef SAVEWD_INLINE 31 # define SAVEWD_INLINE _GL_INLINE 32 #endif 33 34 /* A saved working directory. The member names and constants defined 35 by this structure are private to the savewd module. */ 36 struct savewd 37 { 38 /* The state of this object. */ 39 enum 40 { 41 /* This object has been created but does not yet represent 42 the working directory. */ 43 INITIAL_STATE, 44 45 /* val.fd is the original working directory's file descriptor. 46 It is still the working directory. */ 47 FD_STATE, 48 49 /* Like FD_STATE, but the working directory has changed, so 50 restoring it will require a fchdir. */ 51 FD_POST_CHDIR_STATE, 52 53 /* Fork and let the subprocess do the work. val.child is 0 in a 54 child, negative in a childless parent, and the child process 55 ID in a parent with a child. */ 56 FORKING_STATE, 57 58 /* A serious problem argues against further efforts. val.errnum 59 contains the error number (e.g., EIO). */ 60 ERROR_STATE, 61 62 /* savewd_finish has been called, so the application no longer 63 cares whether the working directory is saved, and there is no 64 more work to do. */ 65 FINAL_STATE 66 } state; 67 68 /* The object's value. */ 69 union 70 { 71 int fd; 72 int errnum; 73 pid_t child; 74 } val; 75 }; 76 77 /* Initialize a saved working directory object. */ 78 SAVEWD_INLINE void 79 savewd_init (struct savewd *wd) /* */ 80 { 81 wd->state = INITIAL_STATE; 82 } 83 84 85 /* Options for savewd_chdir. Can be ORed together. */ 86 enum 87 { 88 /* Do not follow symbolic links, if supported. */ 89 SAVEWD_CHDIR_NOFOLLOW = 1, 90 91 /* Do not chdir if the directory is readable; simply succeed 92 without invoking chdir if the directory was opened. */ 93 SAVEWD_CHDIR_SKIP_READABLE = 2 94 }; 95 96 /* Change the directory, and if successful, record into *WD the fact 97 that the process chdired into DIR. A process using this module 98 should use savewd_chdir rather than chdir or fchdir. Obey the 99 options specified in OPTIONS. 100 101 If OPEN_RESULT is not null, store into OPEN_RESULT[0] a file 102 descriptor that accesses DIR if a file descriptor is successfully 103 obtained. Store -1 otherwise, setting OPEN_RESULT[1] to the error 104 number. Store through OPEN_RESULT regardless of whether the chdir 105 is successful. However, when -2 is returned, the contents of 106 OPEN_RESULT are indeterminate since the file descriptor is closed 107 in the parent. 108 109 Return -2 if a subprocess was spun off to do the real work, -1 110 (setting errno) if unsuccessful, 0 if successful. */ 111 int savewd_chdir (struct savewd *wd, char const *dir, int options, 112 int open_result[2]); 113 114 /* Restore the working directory from *WD. STATUS indicates the exit 115 status corresponding to the work done since the last save; this is 116 used when the caller is in a subprocess. Return 0 if successful, 117 -1 (setting errno) on our failure, a positive subprocess exit 118 status if the working directory was restored in the parent but the 119 subprocess failed. */ 120 int savewd_restore (struct savewd *wd, int status); 121 122 /* Return WD's error number, or 0 if WD is not in an error state. */ 123 SAVEWD_INLINE int _GL_ATTRIBUTE_PURE 124 savewd_errno (struct savewd const *wd) /* */ 125 { 126 return (wd->state == ERROR_STATE ? wd->val.errnum : 0); 127 } 128 129 /* Deallocate any resources associated with WD. A program that chdirs 130 should restore before finishing. */ 131 void savewd_finish (struct savewd *wd); 132 133 /* Process N_FILES file names, FILE[0] through FILE[N_FILES - 1]. 134 For each file name F, call ACT (F, WD, OPTIONS); ACT should invoke 135 savewd_chdir as needed, and should return an exit status. WD 136 represents the working directory; it may be in an error state when 137 ACT is called. 138 139 Save and restore the working directory as needed by the file name 140 vector; assume that ACT does not require access to any relative 141 file names other than its first argument, and that it is OK if the 142 working directory is changed when this function returns. Some 143 actions may be applied in a subprocess. 144 145 Return the maximum exit status that any call to ACT returned, or 146 EXIT_SUCCESS (i.e., 0) if no calls were made. */ 147 int savewd_process_files (int n_files, char **file, 148 int (*act) (char *, struct savewd *, void *), 149 void *options); 150 151 _GL_INLINE_HEADER_END 152 153 #endif