xref: /openbsd-src/gnu/usr.bin/cvs/lib/savecwd.c (revision e77048c1007676349fedef3cd7d0b6b93f74c675)
1c26070a5Stholo #ifdef HAVE_CONFIG_H
2c26070a5Stholo # include "config.h"
3c26070a5Stholo #endif
4c26070a5Stholo 
5c26070a5Stholo #include <stdio.h>
6c26070a5Stholo 
7c26070a5Stholo #ifdef STDC_HEADERS
8c26070a5Stholo # include <stdlib.h>
9c26070a5Stholo #endif
10c26070a5Stholo 
11c26070a5Stholo #ifdef HAVE_UNISTD_H
12c26070a5Stholo # include <unistd.h>
13c26070a5Stholo #endif
14c26070a5Stholo 
15c26070a5Stholo #ifdef HAVE_FCNTL_H
16*e77048c1Stholo # include <sys/types.h>
17c26070a5Stholo # include <fcntl.h>
18c26070a5Stholo #else
19c26070a5Stholo # include <sys/file.h>
20c26070a5Stholo #endif
21c26070a5Stholo 
22c26070a5Stholo #ifdef HAVE_DIRECT_H
23c26070a5Stholo # include <direct.h>
24c26070a5Stholo #endif
25c26070a5Stholo 
26c26070a5Stholo #ifdef HAVE_IO_H
27c26070a5Stholo # include <io.h>
28c26070a5Stholo #endif
29c26070a5Stholo 
30c26070a5Stholo #include <errno.h>
31c26070a5Stholo # ifndef errno
32c26070a5Stholo extern int errno;
33c26070a5Stholo #endif
34c26070a5Stholo 
35c26070a5Stholo #include "savecwd.h"
36c26070a5Stholo #include "error.h"
37c26070a5Stholo 
38c26070a5Stholo char *xgetwd __PROTO((void));
39c26070a5Stholo 
40c26070a5Stholo /* Record the location of the current working directory in CWD so that
41c26070a5Stholo    the program may change to other directories and later use restore_cwd
42c26070a5Stholo    to return to the recorded location.  This function may allocate
43c26070a5Stholo    space using malloc (via xgetwd) or leave a file descriptor open;
44c26070a5Stholo    use free_cwd to perform the necessary free or close.  Upon failure,
45c26070a5Stholo    no memory is allocated, any locally opened file descriptors are
46c26070a5Stholo    closed;  return non-zero -- in that case, free_cwd need not be
47c26070a5Stholo    called, but doing so is ok.  Otherwise, return zero.  */
48c26070a5Stholo 
49c26070a5Stholo int
save_cwd(cwd)50c26070a5Stholo save_cwd (cwd)
51c26070a5Stholo      struct saved_cwd *cwd;
52c26070a5Stholo {
53c26070a5Stholo   static int have_working_fchdir = 1;
54c26070a5Stholo 
55c26070a5Stholo   cwd->desc = -1;
56c26070a5Stholo   cwd->name = NULL;
57c26070a5Stholo 
58c26070a5Stholo   if (have_working_fchdir)
59c26070a5Stholo     {
60c26070a5Stholo #ifdef HAVE_FCHDIR
61c26070a5Stholo       cwd->desc = open (".", O_RDONLY);
62c26070a5Stholo       if (cwd->desc < 0)
63c26070a5Stholo 	{
64c26070a5Stholo 	  error (0, errno, "cannot open current directory");
65c26070a5Stholo 	  return 1;
66c26070a5Stholo 	}
67c26070a5Stholo 
68c26070a5Stholo # if __sun__ || sun
69c26070a5Stholo       /* On SunOS 4, fchdir returns EINVAL if accounting is enabled,
70c26070a5Stholo 	 so we have to fall back to chdir.  */
71c26070a5Stholo       if (fchdir (cwd->desc))
72c26070a5Stholo 	{
73c26070a5Stholo 	  if (errno == EINVAL)
74c26070a5Stholo 	    {
75c26070a5Stholo 	      close (cwd->desc);
76c26070a5Stholo 	      cwd->desc = -1;
77c26070a5Stholo 	      have_working_fchdir = 0;
78c26070a5Stholo 	    }
79c26070a5Stholo 	  else
80c26070a5Stholo 	    {
81c26070a5Stholo 	      error (0, errno, "current directory");
82c26070a5Stholo 	      close (cwd->desc);
83c26070a5Stholo 	      cwd->desc = -1;
84c26070a5Stholo 	      return 1;
85c26070a5Stholo 	    }
86c26070a5Stholo 	}
87c26070a5Stholo # endif /* __sun__ || sun */
88c26070a5Stholo #else
89c26070a5Stholo #define fchdir(x) (abort (), 0)
90c26070a5Stholo       have_working_fchdir = 0;
91c26070a5Stholo #endif
92c26070a5Stholo     }
93c26070a5Stholo 
94c26070a5Stholo   if (!have_working_fchdir)
95c26070a5Stholo     {
96c26070a5Stholo       cwd->name = xgetwd ();
97c26070a5Stholo       if (cwd->name == NULL)
98c26070a5Stholo 	{
99c26070a5Stholo 	  error (0, errno, "cannot get current directory");
100c26070a5Stholo 	  return 1;
101c26070a5Stholo 	}
102c26070a5Stholo     }
103c26070a5Stholo   return 0;
104c26070a5Stholo }
105c26070a5Stholo 
106c26070a5Stholo /* Change to recorded location, CWD, in directory hierarchy.
107c26070a5Stholo    If "saved working directory", NULL))
108c26070a5Stholo    */
109c26070a5Stholo 
110c26070a5Stholo int
restore_cwd(cwd,dest)111c26070a5Stholo restore_cwd (cwd, dest)
112c26070a5Stholo      const struct saved_cwd *cwd;
113c26070a5Stholo      const char *dest;
114c26070a5Stholo {
115c26070a5Stholo   int fail = 0;
116c26070a5Stholo   if (cwd->desc >= 0)
117c26070a5Stholo     {
118c26070a5Stholo       if (fchdir (cwd->desc))
119c26070a5Stholo 	{
120c26070a5Stholo 	  error (0, errno, "cannot return to %s",
121c26070a5Stholo 		 (dest ? dest : "saved working directory"));
122c26070a5Stholo 	  fail = 1;
123c26070a5Stholo 	}
124c26070a5Stholo     }
125c26070a5Stholo   else if (chdir (cwd->name) < 0)
126c26070a5Stholo     {
127c26070a5Stholo       error (0, errno, "%s", cwd->name);
128c26070a5Stholo       fail = 1;
129c26070a5Stholo     }
130c26070a5Stholo   return fail;
131c26070a5Stholo }
132c26070a5Stholo 
133c26070a5Stholo void
free_cwd(cwd)134c26070a5Stholo free_cwd (cwd)
135c26070a5Stholo      struct saved_cwd *cwd;
136c26070a5Stholo {
137c26070a5Stholo   if (cwd->desc >= 0)
138c26070a5Stholo     close (cwd->desc);
139c26070a5Stholo   if (cwd->name)
140c26070a5Stholo     free (cwd->name);
141c26070a5Stholo }
142c26070a5Stholo 
143