1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2016-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING.  If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 // These functions may be provided by gnulib.  We don't include gnulib
27 // headers directly in Octave's C++ source files to avoid problems that
28 // may be caused by the way that gnulib overrides standard library
29 // functions.
30 
31 #if defined (HAVE_CONFIG_H)
32 #  include "config.h"
33 #endif
34 
35 #include <stdio.h>
36 
37 #include <sys/types.h>
38 #include <unistd.h>
39 
40 #if defined (__WIN32__) && ! defined (__CYGWIN__)
41 #  include <process.h>
42 #endif
43 
44 #if defined (OCTAVE_USE_WINDOWS_API)
45 #  include <windows.h>
46 #  include <wchar.h>
47 #endif
48 
49 #include "uniconv-wrappers.h"
50 #include "unistd-wrappers.h"
51 
52 int
octave_access_f_ok(void)53 octave_access_f_ok (void)
54 {
55   return F_OK;
56 }
57 
58 int
octave_access_r_ok(void)59 octave_access_r_ok (void)
60 {
61   return R_OK;
62 }
63 
64 int
octave_access_w_ok(void)65 octave_access_w_ok (void)
66 {
67   return W_OK;
68 }
69 
70 int
octave_access_x_ok(void)71 octave_access_x_ok (void)
72 {
73   return X_OK;
74 }
75 
76 int
octave_access_wrapper(const char * nm,int mode)77 octave_access_wrapper (const char *nm, int mode)
78 {
79   return access (nm, mode);
80 }
81 
82 int
octave_chdir_wrapper(const char * nm)83 octave_chdir_wrapper (const char *nm)
84 {
85 #if defined (OCTAVE_USE_WINDOWS_API)
86   wchar_t *wnm = u8_to_wchar (nm);
87   int status = _wchdir (wnm);
88   free ((void *) wnm);
89   return status;
90 #else
91   return chdir (nm);
92 #endif
93 }
94 
95 int
octave_close_wrapper(int fd)96 octave_close_wrapper (int fd)
97 {
98   return close (fd);
99 }
100 
101 const char *
octave_ctermid_wrapper(void)102 octave_ctermid_wrapper (void)
103 {
104 #if defined (HAVE_CTERMID)
105   return ctermid (0);
106 #else
107   return "/dev/tty";
108 #endif
109 }
110 
111 int
octave_dup2_wrapper(int fd1,int fd2)112 octave_dup2_wrapper (int fd1, int fd2)
113 {
114   return dup2 (fd1, fd2);
115 }
116 
117 #if defined (__WIN32__) && ! defined (__CYGWIN__)
118 
119 // Adapted from libtool wrapper.
120 
121 /* Prepares an argument vector before calling spawn().
122 
123    Note that spawn() does not by itself call the command interpreter
124      (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
125       ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
126          GetVersionEx(&v);
127          v.dwPlatformId == VER_PLATFORM_WIN32_NT;
128       }) ? "cmd.exe" : "command.com").
129 
130    Instead it simply concatenates the arguments, separated by ' ', and calls
131    CreateProcess().  We must quote the arguments since Win32 CreateProcess()
132    interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
133    special way:
134 
135    - Space and tab are interpreted as delimiters. They are not treated as
136      delimiters if they are surrounded by double quotes: "...".
137 
138    - Unescaped double quotes are removed from the input. Their only effect is
139      that within double quotes, space and tab are treated like normal
140      characters.
141 
142    - Backslashes not followed by double quotes are not special.
143 
144    - But 2*n+1 backslashes followed by a double quote become
145      n backslashes followed by a double quote (n >= 0):
146        \" -> "
147        \\\" -> \"
148        \\\\\" -> \\"
149  */
150 
151 #define SHELL_SPECIAL_CHARS \
152   "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
153 
154 #define SHELL_SPACE_CHARS \
155   " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
156 
157 static char **
prepare_spawn(char * const * argv)158 prepare_spawn (char *const *argv)
159 {
160   size_t argc;
161   char **new_argv;
162   size_t i;
163 
164   /* Count number of arguments.  */
165   for (argc = 0; argv[argc] != NULL; argc++)
166     ;
167 
168   /* Allocate new argument vector.  */
169   new_argv = (char **) malloc ((argc + 1) * sizeof (char *));
170 
171   /* Put quoted arguments into the new argument vector.  */
172   for (i = 0; i < argc; i++)
173     {
174       const char *string = argv[i];
175 
176       if (string[0] == '\0')
177         new_argv[i] = strdup ("\"\"");
178       else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
179         {
180           int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
181           size_t length;
182           unsigned int backslashes;
183           const char *s;
184           char *quoted_string;
185           char *p;
186 
187           length = 0;
188           backslashes = 0;
189           if (quote_around)
190             length++;
191           for (s = string; *s != '\0'; s++)
192             {
193               char c = *s;
194               if (c == '"')
195                 length += backslashes + 1;
196               length++;
197               if (c == '\\')
198                 backslashes++;
199               else
200                 backslashes = 0;
201             }
202           if (quote_around)
203             length += backslashes + 1;
204 
205           quoted_string = (char *) malloc (length + 1);
206 
207           p = quoted_string;
208           backslashes = 0;
209           if (quote_around)
210             *p++ = '"';
211           for (s = string; *s != '\0'; s++)
212             {
213               char c = *s;
214               if (c == '"')
215                 {
216                   unsigned int j;
217                   for (j = backslashes + 1; j > 0; j--)
218                     *p++ = '\\';
219                 }
220               *p++ = c;
221               if (c == '\\')
222                 backslashes++;
223               else
224                 backslashes = 0;
225             }
226           if (quote_around)
227             {
228               unsigned int j;
229               for (j = backslashes; j > 0; j--)
230                 *p++ = '\\';
231               *p++ = '"';
232             }
233           *p = '\0';
234 
235           new_argv[i] = quoted_string;
236         }
237       else
238         new_argv[i] = strdup (string);
239     }
240 
241   new_argv[argc] = NULL;
242 
243   return new_argv;
244 }
245 
246 #endif
247 
248 int
octave_execv_wrapper(const char * file,char * const * argv)249 octave_execv_wrapper (const char *file, char *const *argv)
250 {
251 #if defined (__WIN32__) && ! defined (__CYGWIN__)
252 
253   char **sanitized_argv = prepare_spawn (argv);
254 
255   int status = spawnv (P_OVERLAY, file, sanitized_argv);
256 
257   // This only happens if spawnv fails.
258 
259   char **p = sanitized_argv;
260   while (*p)
261     free (*p++);
262   free (sanitized_argv);
263 
264   return status;
265 
266 #else
267 
268   return execv (file, argv);
269 
270 #endif
271 }
272 
273 int
octave_execvp_wrapper(const char * file,char * const * argv)274 octave_execvp_wrapper (const char *file, char *const *argv)
275 {
276   return execvp (file, argv);
277 }
278 
279 pid_t
octave_fork_wrapper(void)280 octave_fork_wrapper (void)
281 {
282 #if defined (HAVE_FORK)
283   return fork ();
284 #else
285   return -1;
286 #endif
287 }
288 
289 int
octave_ftruncate_wrapper(int fd,off_t sz)290 octave_ftruncate_wrapper (int fd, off_t sz)
291 {
292   return ftruncate (fd, sz);
293 }
294 
295 char *
octave_getcwd_wrapper(char * nm,size_t len)296 octave_getcwd_wrapper (char *nm, size_t len)
297 {
298 #if defined (OCTAVE_USE_WINDOWS_API)
299   wchar_t *tmp = _wgetcwd (NULL, 0);
300   char *retval = NULL;
301 
302   if (! tmp)
303     return retval;
304 
305   retval = u8_from_wchar (tmp);
306   if (! nm)
307     return retval;
308   else
309     {
310       if (strlen (retval) > len)
311         return NULL;
312 
313       memcpy (nm, retval, len);
314       free (retval);
315       return nm;
316     }
317 #else
318   return getcwd (nm, len);
319 #endif
320 }
321 
322 gid_t
octave_getegid_wrapper(void)323 octave_getegid_wrapper (void)
324 {
325 #if defined (HAVE_GETEGID)
326   return getegid ();
327 #else
328   return -1;
329 #endif
330 }
331 
332 uid_t
octave_geteuid_wrapper(void)333 octave_geteuid_wrapper (void)
334 {
335 #if defined (HAVE_GETEUID)
336   return geteuid ();
337 #else
338   return -1;
339 #endif
340 }
341 
342 gid_t
octave_getgid_wrapper(void)343 octave_getgid_wrapper (void)
344 {
345 #if defined (HAVE_GETGID)
346   return getgid ();
347 #else
348   return -1;
349 #endif
350 }
351 
352 int
octave_gethostname_wrapper(char * nm,size_t len)353 octave_gethostname_wrapper (char *nm, size_t len)
354 {
355   return gethostname (nm, len);
356 }
357 
358 pid_t
octave_getpgrp_wrapper(void)359 octave_getpgrp_wrapper (void)
360 {
361 #if defined (HAVE_GETPGRP)
362   return getpgrp ();
363 #else
364   return -1;
365 #endif
366 }
367 
368 pid_t
octave_getpid_wrapper(void)369 octave_getpid_wrapper (void)
370 {
371 #if defined (HAVE_GETPID)
372   return getpid ();
373 #else
374   return -1;
375 #endif
376 }
377 
378 pid_t
octave_getppid_wrapper(void)379 octave_getppid_wrapper (void)
380 {
381 #if defined (HAVE_GETPPID)
382   return getppid ();
383 #else
384   return -1;
385 #endif
386 }
387 
388 uid_t
octave_getuid_wrapper(void)389 octave_getuid_wrapper (void)
390 {
391 #if defined (HAVE_GETUID)
392   return getuid ();
393 #else
394   return -1;
395 #endif
396 }
397 
398 int
octave_isatty_wrapper(int fd)399 octave_isatty_wrapper (int fd)
400 {
401   return isatty (fd);
402 }
403 
404 int
octave_link_wrapper(const char * nm1,const char * nm2)405 octave_link_wrapper (const char *nm1, const char *nm2)
406 {
407   return link (nm1, nm2);
408 }
409 
410 int
octave_pipe_wrapper(int * fd)411 octave_pipe_wrapper (int *fd)
412 {
413   return pipe (fd);
414 }
415 
416 int
octave_rmdir_wrapper(const char * nm)417 octave_rmdir_wrapper (const char *nm)
418 {
419 #if defined (OCTAVE_USE_WINDOWS_API)
420   wchar_t *wnm = u8_to_wchar (nm);
421   int status = _wrmdir (wnm);
422   free ((void *) wnm);
423   return status;
424 #else
425   return rmdir (nm);
426 #endif
427 }
428 
429 pid_t
octave_setsid_wrapper(void)430 octave_setsid_wrapper (void)
431 {
432 #if defined (HAVE_SETSID)
433   return setsid ();
434 #else
435   return -1;
436 #endif
437 }
438 
439 int
octave_stdin_fileno(void)440 octave_stdin_fileno (void)
441 {
442   return STDIN_FILENO;
443 }
444 
445 int
octave_stdout_fileno(void)446 octave_stdout_fileno (void)
447 {
448   return STDOUT_FILENO;
449 }
450 
451 int
octave_symlink_wrapper(const char * nm1,const char * nm2)452 octave_symlink_wrapper (const char *nm1, const char *nm2)
453 {
454   return symlink (nm1, nm2);
455 }
456 
457 int
octave_unlink_wrapper(const char * nm)458 octave_unlink_wrapper (const char *nm)
459 {
460 #if defined (OCTAVE_USE_WINDOWS_API)
461   wchar_t *wnm = u8_to_wchar (nm);
462   int status = _wunlink (wnm);
463   free ((void *) wnm);
464   return status;
465 #else
466   return unlink (nm);
467 #endif
468 }
469 
470 pid_t
octave_vfork_wrapper(void)471 octave_vfork_wrapper (void)
472 {
473 #if defined (HAVE_VFORK)
474   return vfork ();
475 #else
476   return -1;
477 #endif
478 }
479 
480 bool
octave_have_fork(void)481 octave_have_fork (void)
482 {
483 #if defined (HAVE_FORK)
484   return true;
485 #else
486   return false;
487 #endif
488 }
489 
490 bool
octave_have_vfork(void)491 octave_have_vfork (void)
492 {
493 #if defined (HAVE_VFORK)
494   return true;
495 #else
496   return false;
497 #endif
498 }
499