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