1 /* gawkmisc.c --- miscellaneous gawk routines that are OS specific.
2
3 Copyright (C) 1986, 1988, 1989, 1991 - 1998, 2001 - 2004, 2011, 2021, 2022, 2023,
4 the Free Software Foundation, Inc.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software Foundation,
18 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
19
20 #ifdef __CYGWIN__
21 #ifdef __MSYS__
22 #define WIN32_LEAN_AND_MEAN
23 #include <windows.h>
24 #include <sys/cygwin.h>
25 #endif
26 #include <io.h> /* for declaration of setmode(). */
27 #endif
28
29 const char quote = '\'';
30 const char *defpath = DEFPATH;
31 const char *deflibpath = DEFLIBPATH;
32 const char envsep = ':';
33
34 #ifndef INVALID_HANDLE
35 /* FIXME: is this value for INVALID_HANDLE correct? */
36 #define INVALID_HANDLE -1
37 #endif
38
39 /* gawk_name --- pull out the "gawk" part from how the OS called us */
40
41 const char *
42 gawk_name(const char *filespec)
43 {
44 const char *p;
45
46 /* "path/name" -> "name" */
47 p = strrchr(filespec, '/');
48 return (p == NULL ? (char *) filespec : p + 1);
49 }
50
51 /* os_arg_fixup --- fixup the command line */
52
53 void
54 os_arg_fixup(int *argcp, char ***argvp)
55 {
56 /* no-op */
57 return;
58 }
59
60 /* os_devopen --- open special per-OS devices */
61
62 int
63 os_devopen(const char *name, int flag)
64 {
65 /* no-op */
66 return INVALID_HANDLE;
67 }
68
69 /* optimal_bufsize --- determine optimal buffer size */
70
71 /*
72 * Enhance this for debugging purposes, as follows:
73 *
74 * Always stat the file, stat buffer is used by higher-level code.
75 *
76 * if (AWKBUFSIZE == "exact")
77 * return the file size
78 * else if (AWKBUFSIZE == a number)
79 * always return that number
80 * else
81 * if the size is < default_blocksize
82 * return the size
83 * else
84 * return default_blocksize
85 * end if
86 * endif
87 *
88 * Hair comes in an effort to only deal with AWKBUFSIZE
89 * once, the first time this routine is called, instead of
90 * every time. Performance, dontyaknow.
91 */
92
93 size_t
94 optimal_bufsize(int fd, struct stat *stb)
95 {
96 char *val;
97 static size_t env_val = 0;
98 static bool first = true;
99 static bool exact = false;
100
101 /* force all members to zero in case OS doesn't use all of them. */
102 memset(stb, '\0', sizeof(struct stat));
103
104 /* always stat, in case stb is used by higher level code. */
105 if (fstat(fd, stb) == -1)
106 fatal("can't stat fd %d (%s)", fd, strerror(errno));
107
108 if (first) {
109 first = false;
110
111 if ((val = getenv("AWKBUFSIZE")) != NULL) {
112 if (strcmp(val, "exact") == 0)
113 exact = true;
114 else if (isdigit((unsigned char) *val)) {
115 for (; *val && isdigit((unsigned char) *val); val++)
116 env_val = (env_val * 10) + *val - '0';
117
118 return env_val;
119 }
120 }
121 } else if (! exact && env_val > 0)
122 return env_val;
123 /* else
124 fall through */
125
126 /*
127 * System V.n, n < 4, doesn't have the file system block size in the
128 * stat structure. So we have to make some sort of reasonable
129 * guess. We use stdio's BUFSIZ, since that is what it was
130 * meant for in the first place.
131 */
132 #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
133 #define DEFBLKSIZE (stb->st_blksize > 0 ? stb->st_blksize : BUFSIZ)
134 #else
135 #define DEFBLKSIZE BUFSIZ
136 #endif
137
138 if (S_ISREG(stb->st_mode) /* regular file */
139 && 0 < stb->st_size /* non-zero size */
140 && (stb->st_size < DEFBLKSIZE /* small file */
141 || exact)) /* or debugging */
142 return stb->st_size; /* use file size */
143
144 return DEFBLKSIZE;
145 }
146
147 /* ispath --- return true if path has directory components */
148
149 int
150 ispath(const char *file)
151 {
152 return (strchr(file, '/') != NULL);
153 }
154
155 /* isdirpunct --- return true if char is a directory separator */
156
157 int
158 isdirpunct(int c)
159 {
160 return (c == '/');
161 }
162
163 /* os_close_on_exec --- set close on exec flag, print warning if fails */
164
165 void
166 os_close_on_exec(int fd, const char *name, const char *what, const char *dir)
167 {
168 int curflags = 0;
169
170 if (fd <= 2) /* sanity */
171 return;
172
173 /*
174 * Per POSIX, use Read/Modify/Write - get the flags,
175 * add FD_CLOEXEC, set the flags back.
176 */
177
178 if ((curflags = fcntl(fd, F_GETFD)) < 0) {
179 warning(_("%s %s `%s': could not get fd flags: (fcntl F_GETFD: %s)"),
180 what, dir, name, strerror(errno));
181 return;
182 }
183
184 #ifndef FD_CLOEXEC
185 #define FD_CLOEXEC 1
186 #endif
187
188 curflags |= FD_CLOEXEC;
189
190 if (fcntl(fd, F_SETFD, curflags) < 0)
191 warning(_("%s %s `%s': could not set close-on-exec: (fcntl F_SETFD: %s)"),
192 what, dir, name, strerror(errno));
193 }
194
195 /* os_isdir --- is this an fd on a directory? */
196
197 #if ! defined(S_ISDIR) && defined(S_IFDIR)
198 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
199 #endif
200
201 int
202 os_isdir(int fd)
203 {
204 struct stat sbuf;
205
206 return (fstat(fd, &sbuf) == 0 && S_ISDIR(sbuf.st_mode));
207 }
208
209 /* os_isreadable --- fd can be read from */
210
211 int
212 os_isreadable(const awk_input_buf_t *iobuf, bool *isdir)
213 {
214 *isdir = false;
215
216 if (iobuf->fd == INVALID_HANDLE)
217 return false;
218
219 switch (iobuf->sbuf.st_mode & S_IFMT) {
220 case S_IFREG:
221 case S_IFCHR: /* ttys, /dev/null, .. */
222 #ifdef S_IFSOCK
223 case S_IFSOCK:
224 #endif
225 #ifdef S_IFIFO
226 case S_IFIFO:
227 #endif
228 return true;
229 case S_IFDIR:
230 *isdir = true;
231 /* fall through */
232 default:
233 return false;
234 }
235 }
236
237 /* os_is_setuid --- true if running setuid root */
238
239 int
240 os_is_setuid()
241 {
242 long uid, euid;
243
244 uid = getuid();
245 euid = geteuid();
246
247 return (euid == 0 && euid != uid);
248 }
249
250 /* os_setbinmode --- set binary mode on file */
251
252 int
253 os_setbinmode(int fd, int mode)
254 {
255 #ifdef __CYGWIN__
256 setmode (fd, mode);
257 #endif
258 return 0;
259 }
260
261 /* os_restore_mode --- restore the original mode of the console device */
262
263 void
264 os_restore_mode(int fd)
265 {
266 /* no-op */
267 return;
268 }
269
270 /* os_isatty --- return true if fd is a tty */
271
272 int
273 os_isatty(int fd)
274 {
275 return isatty(fd);
276 }
277
278 /* files_are_same --- return true if files are identical */
279
280 int
281 files_are_same(char *path, SRCFILE *src)
282 {
283 struct stat st;
284
285 return (stat(path, & st) == 0
286 && st.st_dev == src->sbuf.st_dev
287 && st.st_ino == src->sbuf.st_ino);
288 }
289
290 void
291 init_sockets(void)
292 {
293 }
294
295 void
296 os_maybe_set_errno(void)
297 {
298 }
299
300 // For MSYS, restore behavior of working in text mode.
301 #ifdef __MSYS__
302 void
303 cygwin_premain0(int argc, char **argv, struct per_process *myself)
304 {
305 static struct __cygwin_perfile pf[] = {
306 { "", O_RDONLY | O_TEXT },
307 /*{ "", O_WRONLY | O_BINARY },*/
308 { NULL, 0 }
309 };
310 cygwin_internal(CW_PERFILE, pf);
311 }
312
313 void
314 cygwin_premain2(int argc, char **argv, struct per_process *myself)
315 {
316 setmode(fileno (stdin), O_TEXT);
317 }
318 #endif