3 Copyright 2006-2012 Taco Hoekwater <taco@luatex.org>
5 This file is part of LuaTeX.
7 LuaTeX is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2 of the License, or (at your
10 option) any later version.
12 LuaTeX is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 License for more details.
17 You should have received a copy of the GNU General Public License along
18 with LuaTeX; if not, see <http://www.gnu.org/licenses/>. */
21 #include "lua/luatex-api.h"
23 #include <kpathsea/c-stat.h>
24 #include <kpathsea/c-dir.h>
28 #if defined(_WIN32) || defined(__NT__)
29 # define MKDIR(a,b) mkdir(a)
31 # define MKDIR(a,b) mkdir(a,b)
34 /* An attempt to figure out the basic platform, does not
35 care about niceties like version numbers yet,
36 and ignores platforms where luatex is unlikely to
37 successfully compile without major prorting effort
38 (amiga|mac|os2|vms) */
40 #if defined(_WIN32) || defined(__NT__)
41 # define OS_PLATTYPE "windows"
42 # define OS_PLATNAME "windows"
43 #elif defined(__GO32__) || defined(__DJGPP__) || defined(__DOS__)
44 # define OS_PLATTYPE "msdos"
45 # define OS_PLATNAME "msdos"
46 #else /* assume everything else is unix-y */
47 # include <sys/utsname.h>
48 # define OS_PLATTYPE "unix"
49 /* this is just a first guess */
51 # define OS_PLATNAME "bsd"
52 # elif defined(__CYGWIN__)
53 # define OS_PLATNAME "cygwin"
54 # elif defined(__SYSV__)
55 # define OS_PLATNAME "sysv"
57 # define OS_PLATNAME "generic"
59 /* attempt to be more precise */
60 # if defined(__LINUX__) || defined (__linux)
62 # define OS_PLATNAME "linux"
63 # elif defined(__FREEBSD__) || defined(__FreeBSD__) || defined(__FreeBSD)
65 # define OS_PLATNAME "freebsd"
66 # elif defined(__FreeBSD_kernel__)
68 # define OS_PLATNAME "kfreebsd"
69 # elif defined(__OPENBSD__) || defined(__OpenBSD)
71 # define OS_PLATNAME "openbsd"
72 # elif defined(__SOLARIS__)
74 # define OS_PLATNAME "solaris"
75 # elif defined(__SUNOS__) || defined(__SUN__) || defined(sun)
77 # define OS_PLATNAME "sunos"
78 # elif defined(HPUX) || defined(__hpux)
80 # define OS_PLATNAME "hpux"
83 # define OS_PLATNAME "irix"
84 # elif defined(__MACH__) && defined(__APPLE__)
86 # define OS_PLATNAME "macosx"
87 # elif defined(__GNU__)
89 # define OS_PLATNAME "gnu"
97 /* there could be more platforms that don't have these two,
98 * but win32 and sunos are for sure.
99 * gettimeofday() for win32 is using an alternative definition
102 #if (! defined(_WIN32)) && (! defined(__SUNOS__))
103 # include <sys/time.h> /* gettimeofday() */
104 # include <sys/times.h> /* times() */
105 # include <sys/wait.h>
108 /* set this to one for spawn instead of exec on windows */
110 #define DONT_REALLY_EXIT 1
112 /* Note: under WIN32, |environ| is nothing but a copy of the actual
113 environment as it was during program startup. That variable
114 can then be changed (which is a little odd), but such changes
115 do not survive in the actual environment *unless* they are
116 passed on down in e.g. |_execvpe|, when they would be inherited
117 by the child process.
119 This gives trouble because some parts of the texk code actually
120 change the contents of the |environ| variable as a side-effect
121 of other processing, and that explains why the current code does
122 not use |environ| at all for the moment.
124 The API is kept in place for now, just in case. Thanks to Tomek
125 for the patch and the persistence in tracking this down.
129 # include <process.h>
130 # define spawn_command(a,b,c) c ? \
131 _spawnvpe(_P_WAIT,(const char *)a,(const char* const*)b,(const char* const*)c) : \
132 _spawnvp(_P_WAIT,(const char *)a,(const char* const*)b)
133 # if DONT_REALLY_EXIT
134 # define exec_command(a,b,c) exit(spawn_command((a),(b),(c)))
136 # define exec_command(a,b,c) c ? \
137 _execvpe((const char *)a,(const char* const*)b,(const char* const*)c) : \
138 _execvp((const char *)a,(const char* const*)b)
142 # define DEFAULT_PATH "/bin:/usr/bin:."
144 static int exec_command(const char *file
, char *const *av
, char *const *envp
)
147 const char *searchpath
, *esp
;
148 size_t prefixlen
, filelen
, totallen
;
150 if (strchr(file
, '/')) /* Specific path */
151 return envp
? execve(file
, av
, envp
) : execv(file
, av
);
153 filelen
= strlen(file
);
156 searchpath
= getenv("PATH");
158 searchpath
= DEFAULT_PATH
;
160 errno
= ENOENT
; /* Default errno, if execve() doesn't change it */
163 esp
= strchr(searchpath
, ':');
165 prefixlen
= (size_t) (esp
- searchpath
);
167 prefixlen
= strlen(searchpath
);
169 if (prefixlen
== 0 || searchpath
[prefixlen
- 1] == '/') {
170 totallen
= prefixlen
+ filelen
;
172 if (totallen
>= PATH_MAX
)
175 path
= malloc(totallen
+ 1);
176 memcpy(path
, searchpath
, prefixlen
);
177 memcpy(path
+ prefixlen
, file
, filelen
);
179 totallen
= prefixlen
+ filelen
+ 1;
181 if (totallen
>= PATH_MAX
)
184 path
= malloc(totallen
+ 1);
185 memcpy(path
, searchpath
, prefixlen
);
186 path
[prefixlen
] = '/';
187 memcpy(path
+ prefixlen
+ 1, file
, filelen
);
189 path
[totallen
] = '\0';
192 execve(path
, av
, envp
);
198 if (errno
== E2BIG
|| errno
== ENOEXEC
||
199 errno
== ENOMEM
|| errno
== ETXTBSY
)
200 break; /* Report this as an error, no more search */
202 searchpath
= esp
+ 1;
209 It is not possible to mimic |spawnve()| completely. The main problem is
210 that the |fork|--|waitpid| combination cannot really do identical error
211 reporting to the parent process, because it has to pass all the possible
212 error conditions as well as the actual process return status through a
215 The current implementation tries to give back meaningful results for |execve()|
216 errors in the child, for the cases that could also be returned by |spawnve()|,
217 and for |ETXTBSY|, because that can be triggered by our path searching routine.
219 This implementation does not differentiate abnormal status conditions reported
220 by |waitpid()|, but will simply return a single error indication value.
222 For all this, hyjacking a bunch of numbers in the range 1...255 is needed.
223 The chance of collisions is hopefully diminished by using a rather random
224 range in the 8-bit section.
227 # define INVALID_RET_E2BIG 143
228 # define INVALID_RET_ENOENT 144
229 # define INVALID_RET_ENOEXEC 145
230 # define INVALID_RET_ENOMEM 146
231 # define INVALID_RET_ETXTBSY 147
232 # define INVALID_RET_UNKNOWN 148
233 # define INVALID_RET_INTR 149
235 static int spawn_command(const char *file
, char *const *av
, char *const *envp
)
241 return -1; /* fork failed */
243 if (pid
> 0) { /* parent */
245 wait_pid
= waitpid(pid
, &status
, 0);
246 if (wait_pid
== pid
) {
247 if (WIFEXITED(status
))
248 return WEXITSTATUS(status
);
250 return INVALID_RET_INTR
;
252 return -1; /* some waitpid error */
256 /* somewhat random upper limit. ignore errors on purpose */
257 for (f
= 0; f
< 256; f
++)
260 if (exec_command(file
, av
, envp
)) {
261 /* let's hope no-one uses these values */
264 exit(INVALID_RET_E2BIG
);
266 exit(INVALID_RET_ETXTBSY
);
268 exit(INVALID_RET_ENOENT
);
270 exit(INVALID_RET_ENOEXEC
);
272 exit(INVALID_RET_ENOMEM
);
274 exit(INVALID_RET_UNKNOWN
);
285 static char *get_command_name(char *maincmd
)
287 /* retrieve argv[0] part from the command string,
288 it will be truncated to MAX_PATH if it's too long */
289 char *cmdname
= (char *) malloc(sizeof(char) * MAX_PATH
);
292 for (i
= 0; (i
< MAX_PATH
) && maincmd
[i
] &&
293 ((maincmd
[i
] != ' ' && maincmd
[i
] != '\t') || quoted
); i
++) {
294 if (maincmd
[i
] == '"') {
297 cmdname
[k
] = maincmd
[i
];
306 static char **do_split_command(const char *maincmd
, char **runcmd
)
308 char **cmdline
= NULL
;
310 /* On WIN32 don't split anything, because
311 _spawnvpe can't put it back together properly
312 if there are quoted arguments with spaces.
313 Instead, dump everything into one argument
314 and it will be passed through as is */
315 cmdline
= malloc(sizeof(char *) * 2);
316 cmdline
[0] = xstrdup(maincmd
);
318 *runcmd
= get_command_name(cmdline
[0]);
320 char *piece
, *start_piece
;
326 if (strlen(maincmd
) == 0)
328 /* allocate the array of options first. it will probably be
329 be a little bit too big, but better too much than to little */
331 for (i
= 0; i
< strlen(maincmd
); i
++) {
332 if (maincmd
[i
] == ' ')
335 cmdline
= malloc(sizeof(char *) * j
);
336 for (i
= 0; i
< j
; i
++) {
341 while (cmd
[i
] == ' ')
342 i
++; /* skip leading spaces */
343 start_piece
= malloc(strlen(cmd
) + 1); /* a buffer */
345 for (; i
<= strlen(maincmd
); i
++) {
346 if (cmd
[i
] == '\\' &&
347 (cmd
[i
+ 1] == '\\' || cmd
[i
+ 1] == '\'' || cmd
[i
+ 1] == '"')) {
351 if (in_string
&& cmd
[i
] == in_string
&& !quoted
) {
355 if ((cmd
[i
] == '"' || cmd
[i
] == '\'') && !quoted
) {
359 if ((in_string
== 0 && cmd
[i
] == ' ') || cmd
[i
] == 0) {
361 cmdline
[ret
++] = xstrdup(start_piece
);
363 while (i
< strlen(maincmd
) && cmd
[(i
+ 1)] == ' ')
371 *runcmd
= cmdline
[0];
376 static char **do_flatten_command(lua_State
* L
, char **runcmd
)
381 char **cmdline
= NULL
;
385 lua_rawgeti(L
, -1, j
);
386 if (lua_isnil(L
, -1)) {
394 cmdline
= malloc(sizeof(char *) * (unsigned) (j
+ 1));
395 for (i
= 1; i
<= (unsigned) j
; i
++) {
397 lua_rawgeti(L
, -1, (int) i
);
398 if (lua_isnil(L
, -1) || (s
= lua_tostring(L
, -1)) == NULL
) {
408 cmdline
[(i
- 1)] = xstrdup(s
);
413 lua_rawgeti(L
, -1, 0);
414 if (lua_isnil(L
, -1) || (s
= lua_tostring(L
, -1)) == NULL
) {
416 *runcmd
= get_command_name(cmdline
[0]);
418 *runcmd
= cmdline
[0];
421 *runcmd
= xstrdup(s
);
429 static int os_exec(lua_State
* L
)
432 const char *maincmd
= NULL
;
434 char *safecmd
= NULL
, *cmdname
= NULL
;
435 char **cmdline
= NULL
;
436 char **envblock
= NULL
;
438 if (lua_gettop(L
) != 1) {
440 lua_pushliteral(L
, "invalid arguments passed");
443 if (shellenabledp
<= 0) {
445 lua_pushliteral(L
, "All command execution disabled.");
448 if (lua_type(L
, 1) == LUA_TSTRING
) {
449 maincmd
= lua_tostring(L
, 1);
450 cmdline
= do_split_command(maincmd
, &runcmd
);
451 } else if (lua_type(L
, 1) == LUA_TTABLE
) {
452 cmdline
= do_flatten_command(L
, &runcmd
);
454 /* If restrictedshell == 0, any command is allowed. */
455 /* this is a little different from \write18/ os.execute processing
456 * because it does not test for commands with fixed arguments,
457 * but I am not so eager to attempt to fix that. Just document
458 * that os.exec() checks only the command name.
460 if (restrictedshell
== 0) {
463 const char *theruncmd
= runcmd
;
464 allow
= shell_cmd_is_allowed(theruncmd
, &safecmd
, &cmdname
);
467 if (allow
> 0 && cmdline
!= NULL
&& runcmd
!= NULL
) {
468 #if defined(_WIN32) && DONT_REALLY_EXIT
470 exec_command(safecmd
, cmdline
, envblock
);
472 exec_command(runcmd
, cmdline
, envblock
);
477 r
= exec_command(safecmd
, cmdline
, envblock
);
479 r
= exec_command(runcmd
, cmdline
, envblock
);
482 lua_pushfstring(L
, "%s: %s", runcmd
, strerror(errno
));
483 lua_pushinteger(L
, errno
);
495 lua_pushliteral(L
, "Command execution disabled via shell_escape='p'");
499 lua_pushliteral(L
, "invalid command line passed");
503 #define do_error_return(A,B) do { \
505 lua_pushfstring(L,"%s: %s",runcmd,(A)); \
506 lua_pushinteger(L, B); \
510 static int os_spawn(lua_State
* L
)
513 const char *maincmd
= NULL
;
515 char *safecmd
= NULL
, *cmdname
= NULL
;
516 char **cmdline
= NULL
;
517 char **envblock
= NULL
;
520 if (lua_gettop(L
) != 1) {
522 lua_pushliteral(L
, "invalid arguments passed");
525 if (shellenabledp
<= 0) {
527 lua_pushliteral(L
, "All command execution disabled.");
530 if (lua_type(L
, 1) == LUA_TSTRING
) {
531 maincmd
= lua_tostring(L
, 1);
532 cmdline
= do_split_command(maincmd
, &runcmd
);
533 } else if (lua_type(L
, 1) == LUA_TTABLE
) {
534 cmdline
= do_flatten_command(L
, &runcmd
);
536 /* If restrictedshell == 0, any command is allowed. */
537 /* this is a little different from \write18/ os.execute processing
538 * because it does not test for commands with fixed arguments,
539 * but I am not so eager to attempt to fix that. Just document
540 * that os.exec() checks only the command name.
542 if (restrictedshell
== 0) {
545 const char *theruncmd
= runcmd
;
546 allow
= shell_cmd_is_allowed(theruncmd
, &safecmd
, &cmdname
);
548 if (allow
> 0 && cmdline
!= NULL
&& runcmd
!= NULL
) {
550 i
= spawn_command(safecmd
, cmdline
, envblock
);
552 i
= spawn_command(runcmd
, cmdline
, envblock
);
558 lua_pushinteger(L
, i
);
560 } else if (i
== -1) {
561 /* this branch covers WIN32 as well as fork() and waitpid() errors */
562 do_error_return(strerror(errno
), errno
);
564 } else if (i
== INVALID_RET_E2BIG
) {
565 do_error_return(strerror(E2BIG
), i
);
566 } else if (i
== INVALID_RET_ENOENT
) {
567 do_error_return(strerror(ENOENT
), i
);
568 } else if (i
== INVALID_RET_ENOEXEC
) {
569 do_error_return(strerror(ENOEXEC
), i
);
570 } else if (i
== INVALID_RET_ENOMEM
) {
571 do_error_return(strerror(ENOMEM
), i
);
572 } else if (i
== INVALID_RET_ETXTBSY
) {
573 do_error_return(strerror(ETXTBSY
), i
);
574 } else if (i
== INVALID_RET_UNKNOWN
) {
575 do_error_return("execution failed", i
);
576 } else if (i
== INVALID_RET_INTR
) {
577 do_error_return("execution interrupted", i
);
580 lua_pushinteger(L
, i
);
590 lua_pushliteral(L
, "Command execution disabled via shell_escape='p'");
594 lua_pushliteral(L
, "invalid command line passed");
598 /* Hans wants to set env values */
600 static int os_setenv(lua_State
* L
)
602 const char *key
, *val
;
604 key
= luaL_optstring(L
, 1, NULL
);
605 val
= luaL_optstring(L
, 2, NULL
);
608 value
= xmalloc((unsigned) (strlen(key
) + strlen(val
) + 2));
609 sprintf(value
, "%s=%s", key
, val
);
611 return luaL_error(L
, "unable to change environment");
614 #if defined(_WIN32) || defined(__sun__) || defined(__sun) || defined(_AIX)
615 value
= xmalloc(strlen(key
) + 2);
616 sprintf(value
, "%s=", key
);
618 return luaL_error(L
, "unable to change environment");
621 (void) unsetenv(key
);
625 lua_pushboolean(L
, 1);
630 static void find_env(lua_State
* L
)
632 char *envitem
, *envitem_orig
;
635 envpointer
= environ
;
636 lua_getglobal(L
, "os");
637 if (envpointer
!= NULL
&& lua_istable(L
, -1)) {
638 luaL_checkstack(L
, 2, "out of stack space");
639 lua_pushstring(L
, "env");
641 while (*envpointer
) {
642 /* TODO: perhaps a memory leak here */
643 luaL_checkstack(L
, 2, "out of stack space");
644 envitem
= xstrdup(*envpointer
);
645 envitem_orig
= envitem
;
647 while (*envitem
!= '=') {
652 lua_pushstring(L
, envkey
);
653 lua_pushstring(L
, envitem
);
663 static int ex_sleep(lua_State
* L
)
665 lua_Number interval
= luaL_checknumber(L
, 1);
666 lua_Number units
= luaL_optnumber(L
, 2, 1);
668 Sleep((DWORD
) (1e3
* interval
/ units
));
669 #else /* assumes posix or bsd */
670 usleep((unsigned) (1e6
* interval
/ units
));
678 # define _UTSNAME_LENGTH 65
680 /* Structure describing the system and machine. */
682 char sysname
[_UTSNAME_LENGTH
];
683 char nodename
[_UTSNAME_LENGTH
];
684 char release
[_UTSNAME_LENGTH
];
685 char version
[_UTSNAME_LENGTH
];
686 char machine
[_UTSNAME_LENGTH
];
690 * Get name and information about current kernel.
692 static int uname(struct utsname
*uts
)
694 enum { WinNT
, Win95
, Win98
, WinUnknown
};
698 DWORD os
= WinUnknown
;
700 memset(uts
, 0, sizeof(*uts
));
702 osver
.dwOSVersionInfoSize
= sizeof(osver
);
703 GetVersionEx(&osver
);
704 GetSystemInfo(&sysinfo
);
706 switch (osver
.dwPlatformId
) {
707 case VER_PLATFORM_WIN32_NT
: /* NT, Windows 2000 or Windows XP */
708 if (osver
.dwMajorVersion
== 4)
709 strcpy(uts
->sysname
, "Windows NT4x"); /* NT4x */
710 else if (osver
.dwMajorVersion
<= 3)
711 strcpy(uts
->sysname
, "Windows NT3x"); /* NT3x */
712 else if (osver
.dwMajorVersion
== 5) {
713 if (osver
.dwMinorVersion
== 0)
714 strcpy(uts
->sysname
, "Windows 2000"); /* 2k */
715 else if (osver
.dwMinorVersion
== 1)
716 strcpy(uts
->sysname
, "Windows XP"); /* XP */
717 else if (osver
.dwMinorVersion
== 2)
718 strcpy(uts
->sysname
, "Windows Server 2003"); /* Server 2003 */
719 } else if (osver
.dwMajorVersion
== 6) {
721 if( osver.wProductType == VER_NT_WORKSTATION )
723 strcpy(uts
->sysname
, "Windows Vista"); /* Vista */
726 strcpy (uts->sysname, "Windows Server 2008");
732 case VER_PLATFORM_WIN32_WINDOWS
: /* Win95, Win98 or WinME */
733 if ((osver
.dwMajorVersion
> 4) ||
734 ((osver
.dwMajorVersion
== 4) && (osver
.dwMinorVersion
> 0))) {
735 if (osver
.dwMinorVersion
>= 90)
736 strcpy(uts
->sysname
, "Windows ME"); /* ME */
738 strcpy(uts
->sysname
, "Windows 98"); /* 98 */
741 strcpy(uts
->sysname
, "Windows 95"); /* 95 */
746 case VER_PLATFORM_WIN32s
: /* Windows 3.x */
747 strcpy(uts
->sysname
, "Windows");
750 default: /* anything else */
751 strcpy(uts
->sysname
, "Windows");
755 sprintf(uts
->version
, "%ld.%02ld",
756 osver
.dwMajorVersion
, osver
.dwMinorVersion
);
758 if (osver
.szCSDVersion
[0] != '\0' &&
759 (strlen(osver
.szCSDVersion
) + strlen(uts
->version
) + 1) <
760 sizeof(uts
->version
)) {
761 strcat(uts
->version
, " ");
762 strcat(uts
->version
, osver
.szCSDVersion
);
765 sprintf(uts
->release
, "build %ld", osver
.dwBuildNumber
& 0xFFFF);
767 switch (sysinfo
.wProcessorArchitecture
) {
768 case PROCESSOR_ARCHITECTURE_PPC
:
769 strcpy(uts
->machine
, "ppc");
771 case PROCESSOR_ARCHITECTURE_ALPHA
:
772 strcpy(uts
->machine
, "alpha");
774 case PROCESSOR_ARCHITECTURE_MIPS
:
775 strcpy(uts
->machine
, "mips");
777 case PROCESSOR_ARCHITECTURE_INTEL
:
779 * dwProcessorType is only valid in Win95 and Win98 and WinME
780 * wProcessorLevel is only valid in WinNT
785 switch (sysinfo
.dwProcessorType
) {
786 case PROCESSOR_INTEL_386
:
787 case PROCESSOR_INTEL_486
:
788 case PROCESSOR_INTEL_PENTIUM
:
789 sprintf(uts
->machine
, "i%ld", sysinfo
.dwProcessorType
);
792 strcpy(uts
->machine
, "i386");
797 sprintf(uts
->machine
, "i%d86", sysinfo
.wProcessorLevel
);
800 strcpy(uts
->machine
, "unknown");
805 strcpy(uts
->machine
, "unknown");
809 sLength
= sizeof(uts
->nodename
) - 1;
810 GetComputerName(uts
->nodename
, &sLength
);
816 static int ex_uname(lua_State
* L
)
819 if (uname(&uts
) >= 0) {
821 lua_pushstring(L
, uts
.sysname
);
822 lua_setfield(L
, -2, "sysname");
823 lua_pushstring(L
, uts
.machine
);
824 lua_setfield(L
, -2, "machine");
825 lua_pushstring(L
, uts
.release
);
826 lua_setfield(L
, -2, "release");
827 lua_pushstring(L
, uts
.version
);
828 lua_setfield(L
, -2, "version");
829 lua_pushstring(L
, uts
.nodename
);
830 lua_setfield(L
, -2, "nodename");
838 #if (! defined (_WIN32)) && (! defined (__SUNOS__))
839 static int os_times(lua_State
* L
)
844 lua_pushnumber(L
, /* float */
845 ((lua_Number
) (r
.tms_utime
)) /
846 (lua_Number
) sysconf(_SC_CLK_TCK
));
847 lua_setfield(L
, -2, "utime");
848 lua_pushnumber(L
, /* float */
849 ((lua_Number
) (r
.tms_stime
)) /
850 (lua_Number
) sysconf(_SC_CLK_TCK
));
851 lua_setfield(L
, -2, "stime");
852 lua_pushnumber(L
, /* float */
853 ((lua_Number
) (r
.tms_cutime
)) /
854 (lua_Number
) sysconf(_SC_CLK_TCK
));
855 lua_setfield(L
, -2, "cutime");
856 lua_pushnumber(L
, /* float */
857 ((lua_Number
) (r
.tms_cstime
)) /
858 (lua_Number
) sysconf(_SC_CLK_TCK
));
859 lua_setfield(L
, -2, "cstime");
864 #if ! defined (__SUNOS__)
866 # if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
867 # define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
869 # define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
872 static int os_gettimeofday(lua_State
* L
)
877 gettimeofday(&tv
, NULL
);
878 v
= (double) tv
.tv_sec
+ (double) tv
.tv_usec
/ 1000000.0;
883 GetSystemTimeAsFileTime(&ft
);
885 tmpres
|= ft
.dwHighDateTime
;
887 tmpres
|= ft
.dwLowDateTime
;
889 tmpres
-= DELTA_EPOCH_IN_MICROSECS
; /*converting file time to unix epoch */
890 v
= (double) tmpres
/ 1000000.0;
892 lua_pushnumber(L
, v
); /* float */
897 static const char repl
[] = "0123456789abcdefghijklmnopqrstuvwxyz";
899 #define MAXTRIES 36*36*36
902 static int dirs_made
= 0;
904 static char *do_mkdtemp(char *tmpl
)
908 char *xes
= &tmpl
[strlen(tmpl
) - 6];
909 /* this is not really all that random, but it will do */
910 if (dirs_made
== 0) {
911 srand((unsigned) time(NULL
));
914 for (count
= 0; count
< MAXTRIES
; value
+= 8413, ++count
) {
916 xes
[0] = repl
[v
% 36];
918 xes
[1] = repl
[v
% 36];
920 xes
[2] = repl
[v
% 36];
922 xes
[3] = repl
[v
% 36];
924 xes
[4] = repl
[v
% 36];
926 xes
[5] = repl
[v
% 36];
927 if (MKDIR(tmpl
, S_IRUSR
| S_IWUSR
| S_IXUSR
) >= 0) {
930 } else if (errno
!= EEXIST
) {
938 static int os_tmpdir(lua_State
* L
)
941 const char *tmp
= luaL_optstring(L
, 1, "luatex.XXXXXX");
943 strlen(tmp
) < 6 || (strcmp(tmp
+ strlen(tmp
) - 6, "XXXXXX") != 0)) {
945 lua_pushstring(L
, "Invalid argument to os.tmpdir()");
948 tempdir
= xstrdup(tmp
);
951 s
= mkdtemp(tempdir
);
953 s
= do_mkdtemp(tempdir
);
956 int en
= errno
; /* calls to Lua API may change this value */
958 lua_pushfstring(L
, "%s", strerror(en
));
961 lua_pushstring(L
, s
);
967 static int os_execute(lua_State
* L
)
971 char *safecmd
= NULL
;
972 char *cmdname
= NULL
;
973 const char *cmd
= luaL_optstring(L
, 1, NULL
);
975 if (cmd
== NULL
) { /* pretend we are \.{\\pdfshellescape} */
976 if (shellenabledp
<= 0) {
977 lua_pushinteger(L
, 0);
978 } else if (restrictedshell
== 0) {
979 lua_pushinteger(L
, 1);
981 lua_pushinteger(L
, 2);
985 if (shellenabledp
<= 0) {
987 lua_pushstring(L
, "All command execution disabled.");
990 /* If restrictedshell == 0, any command is allowed. */
991 if (restrictedshell
== 0)
994 allow
= shell_cmd_is_allowed(cmd
, &safecmd
, &cmdname
);
997 lua_pushinteger(L
, system(cmd
));
998 } else if (allow
== 2) {
999 lua_pushinteger(L
, system(safecmd
));
1005 "Command execution disabled via shell_escape='p'");
1006 else /* allow == -1 */
1007 lua_pushstring(L
, "Quoting error in system command line.");
1017 void open_oslibext(lua_State
* L
, int safer
)
1022 lua_getglobal(L
, "os");
1023 lua_pushcfunction(L
, ex_sleep
);
1024 lua_setfield(L
, -2, "sleep");
1025 lua_pushliteral(L
, OS_PLATTYPE
);
1026 lua_setfield(L
, -2, "type");
1027 lua_pushliteral(L
, OS_PLATNAME
);
1028 lua_setfield(L
, -2, "name");
1029 lua_pushcfunction(L
, ex_uname
);
1030 lua_setfield(L
, -2, "uname");
1031 #if (! defined (_WIN32)) && (! defined (__SUNOS__))
1032 lua_pushcfunction(L
, os_times
);
1033 lua_setfield(L
, -2, "times");
1035 #if ! defined (__SUNOS__)
1036 lua_pushcfunction(L
, os_gettimeofday
);
1037 lua_setfield(L
, -2, "gettimeofday");
1041 lua_pushcfunction(L
, os_setenv
);
1042 lua_setfield(L
, -2, "setenv");
1043 lua_pushcfunction(L
, os_exec
);
1044 lua_setfield(L
, -2, "exec");
1045 lua_pushcfunction(L
, os_spawn
);
1046 lua_setfield(L
, -2, "spawn");
1047 lua_pushcfunction(L
, os_execute
);
1048 lua_setfield(L
, -2, "execute");
1049 lua_pushcfunction(L
, os_tmpdir
);
1050 lua_setfield(L
, -2, "tmpdir");
1052 lua_pop(L
, 1); /* pop the table */