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