1 /*************************************************************************
2 * *
3 * YAP Prolog *
4 * *
5 * Yap Prolog was developed at NCCUP - Universidade do Porto *
6 * *
7 * Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997 *
8 * *
9 **************************************************************************
10 * *
11 * $Id: sys.c,v 1.36 2008-07-11 17:02:09 vsc Exp $ *
12 * mods: $Log: not supported by cvs2svn $
13 * mods: Revision 1.35 2008/05/23 13:16:13 vsc
14 * mods: fix sys.c for win32
15 * mods:
16 * mods: Revision 1.34 2008/05/22 23:25:21 vsc
17 * mods: add tmp_file/2
18 * mods:
19 * mods: Revision 1.33 2007/10/05 18:24:30 vsc
20 * mods: fix garbage collector and fix LeaveGoal
21 * mods:
22 * mods: Revision 1.32 2007/05/07 12:11:39 vsc
23 * mods: fix mktime fix
24 * mods:
25 * mods: Revision 1.31 2007/05/07 11:21:29 vsc
26 * mods: mktime needs to know if daylight time savings are on
27 * mods: (obs from Bernd Gutmann).
28 * mods:
29 * mods: Revision 1.30 2007/05/02 11:16:43 vsc
30 * mods: small fixes to sys.c
31 * mods:
32 * mods: Revision 1.29 2006/10/10 14:08:17 vsc
33 * mods: small fixes on threaded implementation.
34 * mods:
35 * mods: Revision 1.28 2006/05/25 16:28:28 vsc
36 * mods: include thread_sleep functionality.
37 * mods:
38 * mods: Revision 1.27 2006/05/17 18:38:11 vsc
39 * mods: make system library use true file name
40 * mods:
41 * mods: Revision 1.26 2006/04/25 03:23:40 vsc
42 * mods: fix ! in debugger (execute_clause)
43 * mods: improve system/1 and execute/1
44 * mods:
45 * mods: Revision 1.25 2006/01/17 14:10:42 vsc
46 * mods: YENV may be an HW register (breaks some tabling code)
47 * mods: All YAAM instructions are now brackedted, so Op introduced an { and EndOp introduces an }. This is because Ricardo assumes that.
48 * mods: Fix attvars when COROUTING is undefined.
49 * mods:
50 * mods: Revision 1.24 2006/01/08 23:01:48 vsc
51 * mods: *** empty log message ***
52 * mods:
53 * mods: Revision 1.23 2005/10/21 16:09:03 vsc
54 * mods: SWI compatible module only operators
55 * mods:
56 * mods: Revision 1.22 2005/03/10 18:04:01 rslopes
57 * mods: update YAP_Error arguments
58 * mods: to be able to compile on Windows...
59 * mods:
60 * mods: Revision 1.21 2004/08/11 16:14:54 vsc
61 * mods: whole lot of fixes:
62 * mods: - memory leak in indexing
63 * mods: - memory management in WIN32 now supports holes
64 * mods: - extend Yap interface, more support for SWI-Interface
65 * mods: - new predicate mktime in system
66 * mods: - buffer console I/O in WIN32
67 * mods:
68 * mods: Revision 1.20 2004/07/23 19:02:09 vsc
69 * mods: misc fixes
70 * mods:
71 * mods: Revision 1.19 2004/07/23 03:37:17 vsc
72 * mods: fix heap overflow in YAP_LookupAtom
73 * mods:
74 * mods: Revision 1.18 2004/01/26 12:51:33 vsc
75 * mods: should be datime/1 not date/1
76 * mods:
77 * mods: Revision 1.17 2004/01/26 12:41:06 vsc
78 * mods: bug fixes
79 * mods:
80 * mods: Revision 1.16 2003/01/27 15:55:40 vsc
81 * mods: use CVS Id
82 * mods:
83 * mods: Revision 1.15 2003/01/27 15:54:10 vsc
84 * mods: fix header
85 * mods: *
86 * comments: regular expression interpreter *
87 * *
88 *************************************************************************/
89
90 #include "config.h"
91 #include "YapInterface.h"
92 #include <stdlib.h>
93 #if HAVE_UNISTD_H
94 #include <unistd.h>
95 #endif
96 #include <stdio.h>
97 #if HAVE_TIME_H
98 #include <time.h>
99 #endif
100 #if HAVE_SYS_TYPES_H
101 #include <sys/types.h>
102 #endif
103 #if HAVE_SYS_STAT_H
104 #include <sys/stat.h>
105 #endif
106 #if HAVE_FCNTL_H
107 #include <fcntl.h>
108 #endif
109 #if HAVE_MATH_H
110 #include <math.h>
111 #endif
112 #if HAVE_UNISTD_H
113 #include <unistd.h>
114 #endif
115 #if HAVE_ERRNO_H
116 #include <errno.h>
117 #endif
118 #if HAVE_STRING_H
119 #include <string.h>
120 #endif
121 #if HAVE_SIGNAL_H
122 #include <signal.h>
123 #endif
124 #if HAVE_SYS_WAIT_H
125 #include <sys/wait.h>
126 #endif
127 #if HAVE_DIRENT_H
128 #include <dirent.h>
129 #endif
130 #if HAVE_DIRECT_H
131 #include <direct.h>
132 #endif
133 #if defined(__MINGW32__) || _MSC_VER
134 #include <windows.h>
135 #include <process.h>
136 #endif
137 #ifdef __MINGW32__
138 #ifdef HAVE_ENVIRON
139 #undef HAVE_ENVIRON
140 #endif
141 #endif
142
143 void PROTO(init_sys, (void));
144
145 #if defined(__MINGW32__) || _MSC_VER
146 static YAP_Term
WinError(void)147 WinError(void)
148 {
149 char msg[256];
150 /* Error, we could not read time */
151 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
152 NULL, GetLastError(),
153 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), msg, 256,
154 NULL);
155 return(YAP_MkAtomTerm(YAP_LookupAtom(msg)));
156 }
157 #endif
158
159 /* Return time in a structure */
160 static int
sysmktime(void)161 sysmktime(void)
162 {
163
164 #if defined(__MINGW32__) || _MSC_VER
165 SYSTEMTIME stime, stime0;
166 FILETIME ftime, ftime0;
167
168 stime.wYear = YAP_IntOfTerm(YAP_ARG1);
169 stime.wMonth = YAP_IntOfTerm(YAP_ARG2);
170 stime.wDay = YAP_IntOfTerm(YAP_ARG3);
171 stime.wHour = YAP_IntOfTerm(YAP_ARG4);
172 stime.wMinute = YAP_IntOfTerm(YAP_ARG5);
173 stime.wSecond = YAP_IntOfTerm(YAP_ARG6);
174 stime.wMilliseconds = 0;
175 stime0.wYear = 1970;
176 stime0.wMonth = 1;
177 stime0.wDay = 1;
178 stime0.wHour = 12;
179 stime0.wMinute = 0;
180 stime0.wSecond = 0;
181 stime0.wMilliseconds = 0;
182 if (!SystemTimeToFileTime(&stime,&ftime)) {
183 return YAP_Unify(YAP_ARG8, YAP_MkIntTerm(errno));
184 }
185 if (!SystemTimeToFileTime(&stime0,&ftime0)) {
186 return YAP_Unify(YAP_ARG8, YAP_MkIntTerm(errno));
187 }
188 #if __GNUC__
189 {
190 unsigned long long f1 = (((unsigned long long)ftime.dwHighDateTime)<<32)+(unsigned long long)ftime.dwLowDateTime;
191 unsigned long long f0 = (((unsigned long long)ftime0.dwHighDateTime)<<32)+(unsigned long long)ftime0.dwLowDateTime;
192 return YAP_Unify(YAP_ARG7,YAP_MkIntTerm((long int)((f1-f0)/10000000)));
193 }
194 #else
195 return FALSE;
196 #endif
197 #else
198 #ifdef HAVE_MKTIME
199 struct tm loc;
200 time_t tim;
201
202 loc.tm_year = YAP_IntOfTerm(YAP_ARG1)-1900;
203 loc.tm_mon = YAP_IntOfTerm(YAP_ARG2)-1;
204 loc.tm_mday = YAP_IntOfTerm(YAP_ARG3);
205 loc.tm_hour = YAP_IntOfTerm(YAP_ARG4);
206 loc.tm_min = YAP_IntOfTerm(YAP_ARG5);
207 loc.tm_sec = YAP_IntOfTerm(YAP_ARG6);
208 loc.tm_isdst = -1;
209
210 if ((tim = mktime(&loc)) == (time_t)-1) {
211 return YAP_Unify(YAP_ARG8, YAP_MkIntTerm(errno));
212 }
213 return YAP_Unify(YAP_ARG7,YAP_MkIntTerm(tim));
214 #else
215 oops
216 #endif /* HAVE_MKTIME */
217 #endif /* WINDOWS */
218 }
219
220 /* Return time in a structure */
221 static int
datime(void)222 datime(void)
223 {
224 YAP_Term tf, out[6];
225 #if defined(__MINGW32__) || _MSC_VER
226 SYSTEMTIME stime;
227 GetLocalTime(&stime);
228 out[0] = YAP_MkIntTerm(stime.wYear);
229 out[1] = YAP_MkIntTerm(stime.wMonth);
230 out[2] = YAP_MkIntTerm(stime.wDay);
231 out[3] = YAP_MkIntTerm(stime.wHour);
232 out[4] = YAP_MkIntTerm(stime.wMinute);
233 out[5] = YAP_MkIntTerm(stime.wSecond);
234 #elif HAVE_TIME
235 time_t tp;
236
237 if ((tp = time(NULL)) == -1) {
238 return(YAP_Unify(YAP_ARG2, YAP_MkIntTerm(errno)));
239 }
240 #ifdef HAVE_LOCALTIME
241 {
242 struct tm *loc = localtime(&tp);
243 if (loc == NULL) {
244 return(YAP_Unify(YAP_ARG2, YAP_MkIntTerm(errno)));
245 }
246 out[0] = YAP_MkIntTerm(1900+loc->tm_year);
247 out[1] = YAP_MkIntTerm(1+loc->tm_mon);
248 out[2] = YAP_MkIntTerm(loc->tm_mday);
249 out[3] = YAP_MkIntTerm(loc->tm_hour);
250 out[4] = YAP_MkIntTerm(loc->tm_min);
251 out[5] = YAP_MkIntTerm(loc->tm_sec);
252 }
253 #else
254 oops
255 #endif /* HAVE_LOCALTIME */
256 #else
257 oops
258 #endif /* HAVE_TIME */
259 tf = YAP_MkApplTerm(YAP_MkFunctor(YAP_LookupAtom("datime"),6), 6, out);
260 return YAP_Unify(YAP_ARG1, tf);
261 }
262
263 #define BUF_SIZE 1024
264
265 /* Return a list of files for a directory */
266 static int
list_directory(void)267 list_directory(void)
268 {
269 YAP_Term tf = YAP_MkAtomTerm(YAP_LookupAtom("[]"));
270 long sl = YAP_InitSlot(tf);
271
272 char *buf = (char *)YAP_AtomName(YAP_AtomOfTerm(YAP_ARG1));
273 #if defined(__MINGW32__) || _MSC_VER
274 struct _finddata_t c_file;
275 char bs[BUF_SIZE];
276 long hFile;
277
278 bs[0] = '\0';
279 #if HAVE_STRNCPY
280 strncpy(bs, buf, BUF_SIZE);
281 #else
282 strcpy(bs, buf);
283 #endif
284 #if HAVE_STRNCAT
285 strncat(bs, "/*", BUF_SIZE);
286 #else
287 strcat(bs, "/*");
288 #endif
289 if ((hFile = _findfirst(bs, &c_file)) == -1L) {
290 return(YAP_Unify(YAP_ARG2,tf));
291 }
292 YAP_PutInSlot(sl, YAP_MkPairTerm(YAP_MkAtomTerm(YAP_LookupAtom(c_file.name)), YAP_GetFromSlot(sl)));
293 while (_findnext( hFile, &c_file) == 0) {
294 YAP_Term ti = YAP_MkAtomTerm(YAP_LookupAtom(c_file.name));
295 YAP_PutInSlot(sl,YAP_MkPairTerm(ti, YAP_GetFromSlot(sl)));
296 }
297 _findclose( hFile );
298 #elif HAVE_OPENDIR
299 {
300 DIR *de;
301 struct dirent *dp;
302
303 if ((de = opendir(buf)) == NULL) {
304 return(YAP_Unify(YAP_ARG3, YAP_MkIntTerm(errno)));
305 }
306 while ((dp = readdir(de))) {
307 YAP_Term ti = YAP_MkAtomTerm(YAP_LookupAtom(dp->d_name));
308 YAP_PutInSlot(sl,YAP_MkPairTerm(ti, YAP_GetFromSlot(sl)));
309 }
310 closedir(de);
311 }
312 #endif /* HAVE_OPENDIR */
313 tf = YAP_GetFromSlot(sl);
314 return YAP_Unify(YAP_ARG2, tf);
315 }
316
317 static int
p_unlink(void)318 p_unlink(void)
319 {
320 char *fd = (char *)YAP_AtomName(YAP_AtomOfTerm(YAP_ARG1));
321 #if defined(__MINGW32__) || _MSC_VER
322 if (_unlink(fd) == -1)
323 #else
324 if (unlink(fd) == -1)
325 #endif
326 {
327 /* return an error number */
328 return(YAP_Unify(YAP_ARG2, YAP_MkIntTerm(errno)));
329 }
330 return(TRUE);
331 }
332
333 static int
p_mkdir(void)334 p_mkdir(void)
335 {
336 char *fd = (char *)YAP_AtomName(YAP_AtomOfTerm(YAP_ARG1));
337 #if defined(__MINGW32__) || _MSC_VER
338 if (_mkdir(fd) == -1) {
339 #else
340 if (mkdir(fd, 0777) == -1) {
341 #endif
342 /* return an error number */
343 return(YAP_Unify(YAP_ARG2, YAP_MkIntTerm(errno)));
344 }
345 return(TRUE);
346 }
347
348 static int
349 p_rmdir(void)
350 {
351 char *fd = (char *)YAP_AtomName(YAP_AtomOfTerm(YAP_ARG1));
352 #if defined(__MINGW32__) || _MSC_VER
353 if (_rmdir(fd) == -1) {
354 #else
355 if (rmdir(fd) == -1) {
356 #endif
357 /* return an error number */
358 return(YAP_Unify(YAP_ARG2, YAP_MkIntTerm(errno)));
359 }
360 return(TRUE);
361 }
362
363 static int
364 rename_file(void)
365 {
366 char *s1 = (char *)YAP_AtomName(YAP_AtomOfTerm(YAP_ARG1));
367 char *s2 = (char *)YAP_AtomName(YAP_AtomOfTerm(YAP_ARG2));
368 #if HAVE_RENAME
369 if (rename(s1, s2) == -1) {
370 /* return an error number */
371 return(YAP_Unify(YAP_ARG3, YAP_MkIntTerm(errno)));
372 }
373 #endif
374 return(TRUE);
375 }
376
377 static int
378 dir_separator(void)
379 {
380 return(YAP_Unify(YAP_ARG1,YAP_MkAtomTerm(YAP_LookupAtom("/"))));
381 }
382
383 static int
384 file_property(void)
385 {
386 const char *fd;
387 #if HAVE_LSTAT
388 struct stat buf;
389
390 fd = (char *)YAP_AtomName(YAP_AtomOfTerm(YAP_ARG1));
391 if (lstat(fd, &buf) == -1) {
392 /* return an error number */
393 return(YAP_Unify(YAP_ARG7, YAP_MkIntTerm(errno)));
394 }
395 if (S_ISREG(buf.st_mode)) {
396 if (!(YAP_Unify(YAP_ARG2, YAP_MkAtomTerm(YAP_LookupAtom("regular"))) &&
397 YAP_Unify(YAP_ARG6, YAP_MkIntTerm(0))))
398 return(FALSE);
399 } else if (S_ISDIR(buf.st_mode)) {
400 if (!(YAP_Unify(YAP_ARG2, YAP_MkAtomTerm(YAP_LookupAtom("directory"))) &&
401 YAP_Unify(YAP_ARG6, YAP_MkIntTerm(0))))
402 return(FALSE);
403 } else if (S_ISFIFO(buf.st_mode)) {
404 if (!(YAP_Unify(YAP_ARG2, YAP_MkAtomTerm(YAP_LookupAtom("fifo"))) &&
405 YAP_Unify(YAP_ARG6, YAP_MkIntTerm(0))))
406 return(FALSE);
407 } else if (S_ISLNK(buf.st_mode)) {
408 if (!YAP_Unify(YAP_ARG2, YAP_MkAtomTerm(YAP_LookupAtom("symlink"))))
409 return(FALSE);
410 #if HAVE_READLINK
411 {
412 char tmp[256];
413 int n;
414 if ((n = readlink(fd,tmp,256)) == -1) {
415 return(YAP_Unify(YAP_ARG7, YAP_MkIntTerm(errno)));
416 }
417 tmp[n] = '\0';
418 if(!YAP_Unify(YAP_ARG6,YAP_MkAtomTerm(YAP_LookupAtom(tmp)))) {
419 return(FALSE);
420 }
421 }
422 #else
423 if (!YAP_Unify(YAP_ARG6, YAP_MkIntTerm(0)))
424 return(FALSE);
425 #endif
426 } else if (S_ISSOCK(buf.st_mode)) {
427 if (!(YAP_Unify(YAP_ARG2, YAP_MkAtomTerm(YAP_LookupAtom("socket"))) &&
428 YAP_Unify(YAP_ARG6, YAP_MkIntTerm(0))))
429 return(FALSE);
430 } else {
431 if (!(YAP_Unify(YAP_ARG2, YAP_MkAtomTerm(YAP_LookupAtom("unknown"))) &&
432 YAP_Unify(YAP_ARG6, YAP_MkIntTerm(0))))
433 return(FALSE);
434 }
435 #elif defined(__MINGW32__) || _MSC_VER
436 /* for some weird reason _stat did not work with mingw32 */
437 struct _stat buf;
438
439 fd = YAP_AtomName(YAP_AtomOfTerm(YAP_ARG1));
440 if (_stat(fd, &buf) != 0) {
441 /* return an error number */
442 return(YAP_Unify(YAP_ARG7, YAP_MkIntTerm(errno)));
443 }
444 if (buf.st_mode & S_IFREG) {
445 if (!YAP_Unify(YAP_ARG2, YAP_MkAtomTerm(YAP_LookupAtom("regular"))))
446 return(FALSE);
447 } else if (buf.st_mode & S_IFDIR) {
448 if (!YAP_Unify(YAP_ARG2, YAP_MkAtomTerm(YAP_LookupAtom("directory"))))
449 return(FALSE);
450 } else {
451 if (!YAP_Unify(YAP_ARG2, YAP_MkAtomTerm(YAP_LookupAtom("unknown"))))
452 return(FALSE);
453 }
454 #endif
455 return (
456 YAP_Unify(YAP_ARG3, YAP_MkIntTerm(buf.st_size)) &&
457 YAP_Unify(YAP_ARG4, YAP_MkIntTerm(buf.st_mtime)) &&
458 YAP_Unify(YAP_ARG5, YAP_MkIntTerm(buf.st_mode))
459 );
460 }
461
462 /* temporary files */
463
464 static int
465 p_mktemp(void)
466 {
467 #if HAVE_MKTEMP || defined(__MINGW32__) || _MSC_VER
468 char *s, tmp[BUF_SIZE];
469 s = (char *)YAP_AtomName(YAP_AtomOfTerm(YAP_ARG1));
470 #if HAVE_STRNCPY
471 strncpy(tmp, s, BUF_SIZE);
472 #else
473 strcpy(tmp, s);
474 #endif
475 #if defined(__MINGW32__) || _MSC_VER
476 if ((s = _mktemp(tmp)) == NULL) {
477 /* return an error number */
478 return(YAP_Unify(YAP_ARG3, YAP_MkIntTerm(errno)));
479 }
480 return(YAP_Unify(YAP_ARG2,YAP_MkAtomTerm(YAP_LookupAtom(s))));
481 #else
482 if ((s = mktemp(tmp)) == NULL) {
483 /* return an error number */
484 return(YAP_Unify(YAP_ARG3, YAP_MkIntTerm(errno)));
485 }
486 return YAP_Unify(YAP_ARG2,YAP_MkAtomTerm(YAP_LookupAtom(s)));
487 #endif
488 #else
489 return FALSE;
490 #endif
491 return(TRUE);
492 }
493
494 static int
495 p_tmpnam(void)
496 {
497 #if HAVE_TMPNAM
498 char buf[L_tmpnam], *s;
499 if (!(s = tmpnam(buf)))
500 return FALSE;
501 return YAP_Unify(YAP_ARG1,YAP_MkAtomTerm(YAP_LookupAtom(s)));
502 #else
503 return FALSE;
504 #endif
505 }
506
507 static int
508 p_tmpdir(void)
509 {
510 #if defined(__MINGW32__) || _MSC_VER
511 char buf[512];
512 DWORD out = GetTempPath(512, buf);
513 if (!out) {
514 return(YAP_Unify(YAP_ARG2, WinError()));
515 }
516 if (out > 511) {
517 char *nbuf = malloc(out+1);
518 if (!nbuf)
519 return YAP_Unify(YAP_ARG2, YAP_MkAtomTerm(YAP_LookupAtom("no malloc memory")));
520 out = GetTempPath(512, nbuf);
521 if (!out) {
522 return YAP_Unify(YAP_ARG2, WinError());
523 }
524 return YAP_Unify(YAP_ARG1,YAP_MkAtomTerm(YAP_LookupAtom(nbuf)));
525 }
526 return YAP_Unify(YAP_ARG1,YAP_MkAtomTerm(YAP_LookupAtom(buf)));
527 #else
528 char *s;
529 if ((s = getenv("TMPDIR")))
530 return YAP_Unify(YAP_ARG1,YAP_MkAtomTerm(YAP_LookupAtom(s)));
531 #ifdef P_tmpdir
532 return YAP_Unify(YAP_ARG1,YAP_MkAtomTerm(YAP_LookupAtom(P_tmpdir)));
533 #endif
534 return YAP_Unify(YAP_ARG1,YAP_MkAtomTerm(YAP_LookupAtom("/tmp")));
535 #endif
536 }
537
538 /* return YAP's environment */
539 static int
540 p_environ(void)
541 {
542 #if HAVE_ENVIRON && 0
543 #if HAVE__NSGETENVIRON
544 char ** ptr = _NSGetEnviron();
545 #elif defined(__MINGW32__) || _MSC_VER
546 extern char **_environ;
547 char ** ptr = _environ;
548 #else
549 extern char **environ;
550 char ** ptr = environ;
551 #endif
552 YAP_Term t1 = YAP_ARG1;
553 long int i;
554
555 i = YAP_IntOfTerm(t1);
556 if (ptr[i] == NULL)
557 return(FALSE);
558 else {
559 YAP_Term t = YAP_BufferToString(ptr[i]);
560 return(YAP_Unify(t, YAP_ARG2));
561 }
562 #else
563 YAP_Error(0, 0L, "environ not available in this configuration" );
564 return(FALSE);
565 #endif
566 }
567
568 #if defined(__MINGW32__) || _MSC_VER
569 static HANDLE
570 get_handle(YAP_Term ti, DWORD fd)
571 {
572 if (YAP_IsAtomTerm(ti)) {
573 HANDLE out;
574 SECURITY_ATTRIBUTES satt;
575
576 satt.nLength = sizeof(satt);
577 satt.lpSecurityDescriptor = NULL;
578 satt.bInheritHandle = TRUE;
579 out = CreateFile("NUL",
580 GENERIC_READ|GENERIC_WRITE,
581 FILE_SHARE_READ|FILE_SHARE_WRITE,
582 &satt,
583 OPEN_EXISTING,
584 0,
585 NULL);
586 return(out);
587 } else {
588 if (YAP_IsIntTerm(ti)) {
589 return(GetStdHandle(fd));
590 } else
591 return((HANDLE)YAP_StreamToFileNo(ti));
592 }
593 }
594
595 static void
596 close_handle(YAP_Term ti, HANDLE h)
597 {
598 if (YAP_IsAtomTerm(ti)) {
599 CloseHandle(h);
600 }
601 }
602
603 #endif
604
605 /* execute a command as a detached process */
606 static int
607 execute_command(void)
608 {
609 YAP_Term ti = YAP_ARG2, to = YAP_ARG3, te = YAP_ARG4;
610 int res;
611 #if defined(__MINGW32__) || _MSC_VER
612 HANDLE inpf, outf, errf;
613 DWORD CreationFlags = 0;
614 STARTUPINFO StartupInfo;
615 PROCESS_INFORMATION ProcessInformation;
616 inpf = get_handle(ti, STD_INPUT_HANDLE);
617 if (inpf == INVALID_HANDLE_VALUE) {
618 return(YAP_Unify(YAP_ARG6, WinError()));
619 }
620 outf = get_handle(to, STD_OUTPUT_HANDLE);
621 if (outf == INVALID_HANDLE_VALUE) {
622 close_handle(ti, inpf);
623 return(YAP_Unify(YAP_ARG6, WinError()));
624 }
625 errf = get_handle(te, STD_OUTPUT_HANDLE);
626 if (errf == INVALID_HANDLE_VALUE) {
627 close_handle(ti, inpf);
628 close_handle(to, outf);
629 return(YAP_Unify(YAP_ARG6, WinError()));
630 }
631 if (!YAP_IsIntTerm(ti) && !YAP_IsIntTerm(to) && !YAP_IsIntTerm(te)) {
632 /* we do not keep a current stream */
633 CreationFlags = DETACHED_PROCESS;
634 }
635 StartupInfo.cb = sizeof(STARTUPINFO);
636 StartupInfo.lpReserved = NULL;
637 StartupInfo.lpDesktop = NULL; /* inherit */
638 StartupInfo.lpTitle = NULL; /* we do not create a new console window */
639 StartupInfo.dwFlags = STARTF_USESTDHANDLES;
640 StartupInfo.cbReserved2 = 0;
641 StartupInfo.lpReserved2 = NULL;
642 StartupInfo.hStdInput = inpf;
643 StartupInfo.hStdOutput = outf;
644 StartupInfo.hStdError = errf;
645 /* got stdin, stdout and error as I like it */
646 if (CreateProcess(NULL,
647 (char *)YAP_AtomName(YAP_AtomOfTerm(YAP_ARG1)),
648 NULL,
649 NULL,
650 TRUE,
651 CreationFlags,
652 NULL,
653 NULL,
654 &StartupInfo,
655 &ProcessInformation) == FALSE) {
656 close_handle(ti, inpf);
657 close_handle(to, outf);
658 close_handle(te, errf);
659 return(YAP_Unify(YAP_ARG6, WinError()));
660 }
661 close_handle(ti, inpf);
662 close_handle(to, outf);
663 close_handle(te, errf);
664 res = ProcessInformation.dwProcessId;
665 return(YAP_Unify(YAP_ARG5,YAP_MkIntTerm(res)));
666 #else /* UNIX CODE */
667 int inpf, outf, errf;
668 /* process input first */
669 if (YAP_IsAtomTerm(ti)) {
670 inpf = open("/dev/null", O_RDONLY);
671 } else {
672 int sd;
673 if (YAP_IsIntTerm(ti))
674 sd = 0;
675 else
676 sd = YAP_StreamToFileNo(ti);
677 inpf = dup(sd);
678 }
679 if (inpf < 0) {
680 /* return an error number */
681 return(YAP_Unify(YAP_ARG6, YAP_MkIntTerm(errno)));
682 }
683 /* then output stream */
684 if (YAP_IsAtomTerm(to)) {
685 outf = open("/dev/zero", O_WRONLY);
686 } else {
687 int sd;
688 if (YAP_IsIntTerm(to))
689 sd = 1;
690 else
691 sd = YAP_StreamToFileNo(to);
692 outf = dup(sd);
693 }
694 if (outf < 0) {
695 /* return an error number */
696 close(inpf);
697 return(YAP_Unify(YAP_ARG6, YAP_MkIntTerm(errno)));
698 }
699 /* then error stream */
700 if (YAP_IsAtomTerm(te)) {
701 errf = open("/dev/zero", O_WRONLY);
702 } else {
703 int sd;
704 if (YAP_IsIntTerm(te))
705 sd = 2;
706 else
707 sd = YAP_StreamToFileNo(te);
708 errf = dup(sd);
709 }
710 if (errf < 0) {
711 /* return an error number */
712 close(inpf);
713 close(outf);
714 return(YAP_Unify(YAP_ARG6, YAP_MkIntTerm(errno)));
715 }
716 YAP_FlushAllStreams();
717 /* we are now ready to fork */
718 if ((res = fork()) < 0) {
719 /* close streams we don't need */
720 close(inpf);
721 close(outf);
722 close(errf);
723 /* return an error number */
724 return(YAP_Unify(YAP_ARG6, YAP_MkIntTerm(errno)));
725 } else if (res == 0) {
726 char *argv[4];
727
728 /* child */
729 /* close current streams, but not std streams */
730 YAP_CloseAllOpenStreams();
731 close(0);
732 dup(inpf);
733 close(inpf);
734 close(1);
735 dup(outf);
736 close(outf);
737 close(2);
738 dup(errf);
739 close(errf);
740 argv[0] = "sh";
741 argv[1] = "-c";
742 argv[2] = (char *)YAP_AtomName(YAP_AtomOfTerm(YAP_ARG1));
743 argv[3] = NULL;
744 execv("/bin/sh", argv);
745 exit(127);
746 /* we have the streams where we want them, just want to execute now */
747 } else {
748 close(inpf);
749 close(outf);
750 close(errf);
751 return(YAP_Unify(YAP_ARG5,YAP_MkIntTerm(res)));
752 }
753 #endif /* UNIX code */
754 }
755
756 /* execute a command as a detached process */
757 static int
758 do_system(void)
759 {
760 char *command = (char *)YAP_AtomName(YAP_AtomOfTerm(YAP_ARG1));
761 #if HAVE_SYSTEM
762 int sys = system(command);
763 if (sys < 0) {
764 return YAP_Unify(YAP_ARG3,YAP_MkIntTerm(errno));
765 }
766 return YAP_Unify(YAP_ARG2, YAP_MkIntTerm(sys));
767 #else
768 YAP_Error(0,0L,"system not available in this configuration, trying %s", command);
769 return FALSE;
770 #endif
771 }
772
773
774
775 /* execute a command as a detached process */
776 static int
777 do_shell(void)
778 {
779 #if defined(__MINGW32__) || _MSC_VER
780 YAP_Error(0,0L,"system not available in this configuration");
781 return(FALSE);
782 #elif HAVE_SYSTEM
783 char *buf = YAP_AllocSpaceFromYap(BUF_SIZE);
784 int sys;
785
786 if (buf == NULL) {
787 YAP_Error(0,0L,"No Temporary Space for Shell");
788 return(FALSE);
789 }
790 #if HAVE_STRNCPY
791 strncpy(buf, YAP_AtomName(YAP_AtomOfTerm(YAP_ARG1)), BUF_SIZE);
792 strncpy(buf, " ", BUF_SIZE);
793 strncpy(buf, YAP_AtomName(YAP_AtomOfTerm(YAP_ARG2)), BUF_SIZE);
794 strncpy(buf, " ", BUF_SIZE);
795 strncpy(buf, YAP_AtomName(YAP_AtomOfTerm(YAP_ARG3)), BUF_SIZE);
796 #else
797 strcpy(buf, YAP_AtomName(YAP_AtomOfTerm(YAP_ARG1)));
798 strcpy(buf, YAP_AtomName(YAP_AtomOfTerm(YAP_ARG2)));
799 strcpy(buf, " ");
800 strcpy(buf, YAP_AtomName(YAP_AtomOfTerm(YAP_ARG3)));
801 #endif
802 sys = system(buf);
803 YAP_FreeSpaceFromYap(buf);
804 if (sys < 0) {
805 return YAP_Unify(YAP_ARG5,YAP_MkIntTerm(errno));
806 }
807 return YAP_Unify(YAP_ARG4, YAP_MkIntTerm(sys));
808 #else
809 char *cptr[4];
810 int t;
811 int sys;
812
813 cptr[0]= (char *)YAP_AtomName(YAP_AtomOfTerm(YAP_ARG1));
814 cptr[1]= (char *)YAP_AtomName(YAP_AtomOfTerm(YAP_ARG2));
815 cptr[2]= (char *)YAP_AtomName(YAP_AtomOfTerm(YAP_ARG3));
816 cptr[3]= NULL;
817 t = fork();
818 if (t < 0) {
819 return YAP_Unify(YAP_ARG5,YAP_MkIntTerm(errno));
820 } else if (t == 0) {
821 t = execvp(cptr[0],cptr);
822 return t;
823 } else {
824 t = wait(&sys);
825 fprintf(stderr,"after wait %x:%x\n",t,sys);
826 if (t < 0) {
827 return YAP_Unify(YAP_ARG5,YAP_MkIntTerm(errno));
828 }
829 }
830 fprintf(stderr,"after wait %x\n", sys);
831 return YAP_Unify(YAP_ARG4, YAP_MkIntTerm(sys));
832 #endif
833 }
834
835 /* execute a command as a detached process */
836 static int
837 p_wait(void)
838 {
839 long int pid = YAP_IntOfTerm(YAP_ARG1);
840 #if defined(__MINGW32__) || _MSC_VER
841 HANDLE proc = OpenProcess(STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE, FALSE, pid);
842 DWORD ExitCode;
843 if (proc == NULL) {
844 return(YAP_Unify(YAP_ARG3, WinError()));
845 }
846 if (WaitForSingleObject(proc, INFINITE) == WAIT_FAILED) {
847 return(YAP_Unify(YAP_ARG3, WinError()));
848 }
849 if (GetExitCodeProcess(proc, &ExitCode) == 0) {
850 return(YAP_Unify(YAP_ARG3, WinError()));
851 }
852 CloseHandle(proc);
853 return(YAP_Unify(YAP_ARG2, YAP_MkIntTerm(ExitCode)));
854 #else
855 do {
856 int status;
857
858 /* check for interruptions */
859 if (waitpid(pid, &status, 0) == -1) {
860 if (errno != EINTR)
861 return -1;
862 return(YAP_Unify(YAP_ARG3, YAP_MkIntTerm(errno)));
863 } else {
864 return(YAP_Unify(YAP_ARG2, YAP_MkIntTerm(status)));
865 }
866 } while(TRUE);
867 #endif
868 }
869
870 /* execute a command as a detached process */
871 static int
872 p_popen(void)
873 {
874 char *command = (char *)YAP_AtomName(YAP_AtomOfTerm(YAP_ARG1));
875 long int mode = YAP_IntOfTerm(YAP_ARG2);
876 FILE *pfd;
877 YAP_Term tsno;
878 int flags;
879
880 #if HAVE_POPEN
881 #if defined(__MINGW32__) || _MSC_VER
882 /* This will only work for console applications. FIX */
883 if (mode == 0)
884 pfd = _popen(command, "r");
885 else
886 pfd = _popen(command, "w");
887 #else
888 if (mode == 0)
889 pfd = popen(command, "r");
890 else
891 pfd = popen(command, "w");
892 #endif
893 if (pfd == NULL) {
894 return(YAP_Unify(YAP_ARG4, YAP_MkIntTerm(errno)));
895 }
896 if (mode == 0)
897 flags = YAP_INPUT_STREAM | YAP_POPEN_STREAM;
898 else
899 flags = YAP_OUTPUT_STREAM | YAP_POPEN_STREAM;
900 tsno = YAP_OpenStream((void *)pfd,
901 "pipe",
902 YAP_MkAtomTerm(YAP_LookupAtom("pipe")),
903 flags);
904 #endif
905 return(YAP_Unify(YAP_ARG3, tsno));
906 }
907
908 static int
909 p_sleep(void)
910 {
911 YAP_Term ts = YAP_ARG1;
912 unsigned long int secs = 0, usecs = 0, out;
913 if (YAP_IsIntTerm(ts)) {
914 secs = YAP_IntOfTerm(ts);
915 } else if (YAP_IsFloatTerm(ts)) {
916 double tfl = YAP_FloatOfTerm(ts);
917 if (tfl > 1.0)
918 secs = tfl;
919 else
920 usecs = tfl*1000000;
921 }
922 #if defined(__MINGW32__) || _MSC_VER
923 if (secs) usecs = secs*1000 + usecs/1000;
924 Sleep(usecs);
925 /* no errors possible */
926 out = 0;
927 #elif HAVE_NANOSLEEP
928 {
929 struct timespec req;
930 if (YAP_IsFloatTerm(ts)) {
931 double tfl = YAP_FloatOfTerm(ts);
932
933 req.tv_nsec = (tfl-floor(tfl))*1000000000;
934 req.tv_sec = rint(tfl);
935 } else {
936 req.tv_nsec = 0;
937 req.tv_sec = secs;
938 }
939 out = nanosleep(&req, NULL);
940 }
941 #elif HAVE_USLEEP
942 if (usecs > 0) {
943 out = usleep(usecs);
944 } else
945 #elif HAVE_SLEEP
946 {
947 out = sleep(secs);
948 }
949 #else
950 YAP_Error(0,0L,"sleep not available in this configuration");
951 return FALSE:
952 #endif
953 return(YAP_Unify(YAP_ARG2, YAP_MkIntTerm(out)));
954 }
955
956 /* host info */
957
958 static int
959 host_name(void)
960 {
961 #if defined(__MINGW32__) || _MSC_VER
962 char name[MAX_COMPUTERNAME_LENGTH+1];
963 DWORD nSize = MAX_COMPUTERNAME_LENGTH+1;
964 if (GetComputerName(name, &nSize) == 0) {
965 return(YAP_Unify(YAP_ARG2, WinError()));
966 }
967 #else
968 #if HAVE_GETHOSTNAME
969 char name[256];
970 if (gethostname(name, 256) == -1) {
971 /* return an error number */
972 return(YAP_Unify(YAP_ARG2, YAP_MkIntTerm(errno)));
973 }
974 #endif
975 #endif /* defined(__MINGW32__) || _MSC_VER */
976 return(YAP_Unify(YAP_ARG1, YAP_MkAtomTerm(YAP_LookupAtom(name))));
977 }
978
979 static int
980 host_id(void)
981 {
982 #if HAVE_GETHOSTID
983 return(YAP_Unify(YAP_ARG1, YAP_MkIntTerm(gethostid())));
984 #else
985 return(YAP_Unify(YAP_ARG1, YAP_MkIntTerm(0)));
986 #endif
987 }
988
989 static int
990 pid(void)
991 {
992 #if defined(__MINGW32__) || _MSC_VER
993 return(YAP_Unify(YAP_ARG1, YAP_MkIntTerm(_getpid())));
994 #else
995 return(YAP_Unify(YAP_ARG1, YAP_MkIntTerm(getpid())));
996 #endif
997 }
998
999 static int
1000 win(void)
1001 {
1002 #if defined(__MINGW32__) || _MSC_VER
1003 return(TRUE);
1004 #else
1005 return(FALSE);
1006 #endif
1007 }
1008
1009 static int
1010 p_kill(void)
1011 {
1012 #if defined(__MINGW32__) || _MSC_VER
1013 /* Windows does not support cross-process signals, so we shall do the
1014 SICStus thing and assume that a signal to a process will
1015 always kill it */
1016 HANDLE proc = OpenProcess(STANDARD_RIGHTS_REQUIRED|PROCESS_TERMINATE, FALSE, YAP_IntOfTerm(YAP_ARG1));
1017 if (proc == NULL) {
1018 return(YAP_Unify(YAP_ARG3, WinError()));
1019 }
1020 if (TerminateProcess(proc, -1) == 0) {
1021 return(YAP_Unify(YAP_ARG3, WinError()));
1022 }
1023 CloseHandle(proc);
1024 #else
1025 if (kill(YAP_IntOfTerm(YAP_ARG1), YAP_IntOfTerm(YAP_ARG2)) < 0) {
1026 /* return an error number */
1027 return(YAP_Unify(YAP_ARG3, YAP_MkIntTerm(errno)));
1028 }
1029 #endif /* defined(__MINGW32__) || _MSC_VER */
1030 return(TRUE);
1031 }
1032
1033 static int
1034 error_message(void)
1035 {
1036 #if HAVE_STRERROR
1037 return YAP_Unify(YAP_ARG2,YAP_MkAtomTerm(YAP_LookupAtom(strerror(YAP_IntOfTerm(YAP_ARG1)))));
1038 #else
1039 return YAP_Unify(YAP_ARG2,YAP_ARG1);
1040 #endif
1041 }
1042
1043 void
1044 init_sys(void)
1045 {
1046 #if HAVE_MKTIME
1047 tzset();
1048 #endif
1049 YAP_UserCPredicate("datime", datime, 2);
1050 YAP_UserCPredicate("mktime", sysmktime, 8);
1051 YAP_UserCPredicate("list_directory", list_directory, 3);
1052 YAP_UserCPredicate("file_property", file_property, 7);
1053 YAP_UserCPredicate("unlink", p_unlink, 2);
1054 YAP_UserCPredicate("mkdir", p_mkdir, 2);
1055 YAP_UserCPredicate("rmdir", p_rmdir, 2);
1056 YAP_UserCPredicate("dir_separator", dir_separator, 1);
1057 YAP_UserCPredicate("p_environ", p_environ, 2);
1058 YAP_UserCPredicate("exec_command", execute_command, 6);
1059 YAP_UserCPredicate("do_shell", do_shell, 5);
1060 YAP_UserCPredicate("do_system", do_system, 3);
1061 YAP_UserCPredicate("popen", p_popen, 4);
1062 YAP_UserCPredicate("wait", p_wait, 3);
1063 YAP_UserCPredicate("host_name", host_name, 2);
1064 YAP_UserCPredicate("host_id", host_id, 2);
1065 YAP_UserCPredicate("pid", pid, 2);
1066 YAP_UserCPredicate("kill", p_kill, 3);
1067 YAP_UserCPredicate("mktemp", p_mktemp, 3);
1068 YAP_UserCPredicate("tmpnam", p_tmpnam, 2);
1069 YAP_UserCPredicate("tmpdir", p_tmpdir, 2);
1070 YAP_UserCPredicate("rename_file", rename_file, 3);
1071 YAP_UserCPredicate("sleep", p_sleep, 2);
1072 YAP_UserCPredicate("error_message", error_message, 2);
1073 YAP_UserCPredicate("win", win, 0);
1074 }
1075
1076 #ifdef _WIN32
1077
1078 #include <windows.h>
1079
1080 int WINAPI PROTO(win_sys, (HANDLE, DWORD, LPVOID));
1081
1082 int WINAPI win_sys(HANDLE hinst, DWORD reason, LPVOID reserved)
1083 {
1084 switch (reason)
1085 {
1086 case DLL_PROCESS_ATTACH:
1087 break;
1088 case DLL_PROCESS_DETACH:
1089 break;
1090 case DLL_THREAD_ATTACH:
1091 break;
1092 case DLL_THREAD_DETACH:
1093 break;
1094 }
1095 return 1;
1096 }
1097 #endif
1098