00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "xsb_config.h"
00027
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <signal.h>
00031 #include <string.h>
00032 #include <sys/types.h>
00033 #include <sys/stat.h>
00034 #include <errno.h>
00035 #include <ctype.h>
00036
00037 #ifdef WIN_NT
00038 #include <windows.h>
00039 #include <direct.h>
00040 #include <io.h>
00041 #include <process.h>
00042 #include <winbase.h>
00043 #else
00044 #include <unistd.h>
00045 #include <stddef.h>
00046 #include <sys/wait.h>
00047 #include <dirent.h>
00048 #endif
00049
00050 #include <fcntl.h>
00051
00052 #include "auxlry.h"
00053 #include "cell_xsb.h"
00054 #include "error_xsb.h"
00055 #include "cinterf.h"
00056 #include "syscall_xsb.h"
00057 #include "io_builtins_xsb.h"
00058
00059 #include "wind2unix.h"
00060 #include "system_xsb.h"
00061 #include "system_defs_xsb.h"
00062 #include "register.h"
00063 #include "psc_xsb.h"
00064 #include "memory_xsb.h"
00065
00066 #define MAX_CMD_LEN 1024
00067
00068 static int xsb_spawn (char *prog, char *arg[], int callno,
00069 int pipe1[], int pipe2[], int pipe3[],
00070 FILE *toprocess_fptr, FILE *fromprocess_fptr,
00071 FILE *fromproc_stderr_fptr);
00072 static void concat_array(char *array[], char *separator,
00073 char *result_str, int maxsize);
00074 static int get_free_process_cell(void);
00075 static void init_process_table(void);
00076 static int process_status(int pid);
00077 static void split_command_arguments(char *string, char *params[], char *callname);
00078 static char *get_next_command_argument(char **buffptr, char **cmdlineprt);
00079 static int file_copy(char *, char *);
00080 static int copy_file_chunk(FILE *, FILE *, unsigned long);
00081 #ifndef WIN_NT
00082 static char *xreadlink(const char *, int *);
00083 #endif
00084
00085 static struct proc_table_t {
00086 int search_idx;
00087 struct proc_array_t {
00088 int pid;
00089 int to_stream;
00090 int from_stream;
00091 int stderr_stream;
00092 char cmdline[MAX_CMD_LEN];
00093 } process[MAX_SUBPROC_NUMBER];
00094 } xsb_process_table;
00095
00096 static xsbBool file_stat(CTXTdeclc int callno, char *file);
00097
00098 static int xsb_find_first_file(CTXTdeclc prolog_term, char*, prolog_term);
00099 static int xsb_find_next_file(CTXTdeclc prolog_term, char*, prolog_term);
00100
00101 int sys_syscall(CTXTdeclc int callno)
00102 {
00103 int result=-1;
00104 struct stat stat_buff;
00105
00106 switch (callno) {
00107 case SYS_exit: {
00108 int exit_code;
00109 exit_code = ptoc_int(CTXTc 3);
00110 xsb_mesg("\nXSB exited with exit code: %d", exit_code);
00111 exit(exit_code); break;
00112 }
00113 #if (!defined(WIN_NT))
00114 case SYS_getpid : result = getpid(); break;
00115 case SYS_link : result = link(ptoc_longstring(CTXTc 3), ptoc_longstring(CTXTc 4)); break;
00116 #endif
00117 case SYS_mkdir: {
00118 #ifndef WIN_NT
00119
00120 result = mkdir(ptoc_longstring(CTXTc 3), 0700);
00121 #else
00122 result = _mkdir(ptoc_longstring(CTXTc 3));
00123 #endif
00124 break;
00125 }
00126 case SYS_rmdir: {
00127 #ifndef WIN_NT
00128 result = rmdir(ptoc_longstring(CTXTc 3));
00129 #else
00130 result = _rmdir(ptoc_longstring(CTXTc 3));
00131 #endif
00132 break;
00133 }
00134 case SYS_unlink: result = unlink(ptoc_longstring(CTXTc 3)); break;
00135 case SYS_chdir : result = chdir(ptoc_longstring(CTXTc 3)); break;
00136 case SYS_access: {
00137 switch(*ptoc_string(CTXTc 4)) {
00138 case 'r':
00139 result = access(ptoc_longstring(CTXTc 3), R_OK_XSB);
00140 break;
00141 case 'w':
00142 result = access(ptoc_longstring(CTXTc 3), W_OK_XSB);
00143 break;
00144 case 'x':
00145 result = access(ptoc_longstring(CTXTc 3), X_OK_XSB);
00146 break;
00147 default:
00148 result = -1;
00149 }
00150 break;
00151 }
00152 case SYS_stat : {
00153
00154
00155
00156 result = stat(ptoc_longstring(CTXTc 3), &stat_buff);
00157 break;
00158 }
00159 case SYS_rename:
00160 result = rename(ptoc_longstring(CTXTc 3), ptoc_longstring(CTXTc 4));
00161 break;
00162 case SYS_cwd: {
00163 char current_dir[MAX_CMD_LEN];
00164
00165 result = (getcwd(current_dir, MAX_CMD_LEN-1) == NULL);
00166 if (result == 0)
00167 ctop_string(CTXTc 3,string_find(current_dir,1));
00168 break;
00169 }
00170 case SYS_filecopy: {
00171 char *from = ptoc_longstring(CTXTc 3);
00172 char *to = ptoc_longstring(CTXTc 4);
00173 result = file_copy(from,to);
00174 break;
00175 }
00176 case SYS_create: {
00177 result = open(ptoc_longstring(CTXTc 3),O_CREAT|O_EXCL,S_IREAD|S_IWRITE);
00178 if (result >= 0) close(result);
00179 break;
00180 }
00181
00182 default: xsb_abort("[SYS_SYSCALL] Unknown system call number, %d", callno);
00183 }
00184 return result;
00185 }
00186
00187 xsbBool sys_system(CTXTdeclc int callno)
00188 {
00189 int pid;
00190
00191 switch (callno) {
00192 case PLAIN_SYSTEM_CALL:
00193
00194 ctop_int(CTXTc 3, system(ptoc_string(CTXTc 2)));
00195 return TRUE;
00196 case SLEEP_FOR_SECS:
00197 #ifdef WIN_NT
00198 Sleep(ptoc_int(CTXTc 2) * 1000);
00199 #else
00200 sleep(ptoc_int(CTXTc 2));
00201 #endif
00202 return TRUE;
00203 case GET_TMP_FILENAME:
00204 ctop_string(CTXTc 2,string_find(tmpnam(NULL),1));
00205 return TRUE;
00206 case IS_PLAIN_FILE:
00207 case IS_DIRECTORY:
00208 case STAT_FILE_TIME:
00209 case STAT_FILE_SIZE:
00210 return file_stat(CTXTc callno, ptoc_longstring(CTXTc 2));
00211 case EXEC: {
00212 #ifdef HAVE_EXECVP
00213
00214 char *params[MAX_SUBPROC_PARAMS+2];
00215 prolog_term cmdspec_term;
00216 int index = 0;
00217
00218 cmdspec_term = reg_term(CTXTc 2);
00219 if (islist(cmdspec_term)) {
00220 prolog_term temp, head;
00221 char *string_head=NULL;
00222
00223 if (isnil(cmdspec_term))
00224 xsb_abort("[exec] Arg 1 must not be an empty list.");
00225
00226 temp = cmdspec_term;
00227 do {
00228 head = p2p_car(temp);
00229 temp = p2p_cdr(temp);
00230 if (isstring(head))
00231 string_head = string_val(head);
00232 else
00233 xsb_abort("[exec] non-string argument passed in list.");
00234
00235 params[index++] = string_head;
00236 if (index > MAX_SUBPROC_PARAMS)
00237 xsb_abort("[exec] Too many arguments.");
00238 } while (!isnil(temp));
00239 params[index] = NULL;
00240 } else if (isstring(cmdspec_term)) {
00241 char *string = string_val(cmdspec_term);
00242 split_command_arguments(string, params, "exec");
00243 } else
00244 xsb_abort("[exec] 1st argument should be term or list of strings.");
00245
00246 if (execvp(params[0], params))
00247 xsb_abort("[exec] Exec call failed.");
00248 #else
00249 xsb_abort("[exec] builtin not supported in this architecture.");
00250 #endif
00251 }
00252
00253 case SHELL:
00254
00255
00256 case SPAWN_PROCESS: {
00257
00258
00259
00260 static int pipe_to_proc[2], pipe_from_proc[2], pipe_from_stderr[2];
00261 int toproc_stream=-1, fromproc_stream=-1, fromproc_stderr_stream=-1;
00262 int pid_or_status;
00263 FILE *toprocess_fptr=NULL,
00264 *fromprocess_fptr=NULL, *fromproc_stderr_fptr=NULL;
00265 char *params[MAX_SUBPROC_PARAMS+2];
00266
00267 prolog_term cmdspec_term, cmdlist_temp_term;
00268 prolog_term cmd_or_arg_term;
00269 xsbBool toproc_needed=FALSE, fromproc_needed=FALSE, fromstderr_needed=FALSE;
00270 char *cmd_or_arg=NULL, *shell_cmd=NULL;
00271 int idx = 0, tbl_pos;
00272 char *callname=NULL;
00273 xsbBool params_are_in_a_list=FALSE;
00274
00275 init_process_table();
00276
00277 if (callno == SPAWN_PROCESS)
00278 callname = "SPAWN_PROCESS";
00279 else
00280 callname = "SHELL";
00281
00282 cmdspec_term = reg_term(CTXTc 2);
00283 if (islist(cmdspec_term))
00284 params_are_in_a_list = TRUE;
00285 else if (isstring(cmdspec_term))
00286 shell_cmd = string_val(cmdspec_term);
00287 else
00288 xsb_abort("[%s] Arg 1 must be an atom or a list [command, arg, ...]",
00289 callname);
00290
00291
00292
00293 if (isref(reg_term(CTXTc 3)))
00294 toproc_needed = TRUE;
00295 if (isref(reg_term(CTXTc 4)))
00296 fromproc_needed = TRUE;
00297 if (isref(reg_term(CTXTc 5)))
00298 fromstderr_needed = TRUE;
00299
00300
00301
00302 if (isinteger(reg_term(CTXTc 3))|isboxedinteger(reg_term(CTXTc 3))) {
00303 SET_FILEPTR(toprocess_fptr, int_val(reg_term(CTXTc 3)));
00304 }
00305 if (isinteger(reg_term(CTXTc 4))|isboxedinteger(reg_term(CTXTc 4))) {
00306 SET_FILEPTR(fromprocess_fptr, int_val(reg_term(CTXTc 4)));
00307 }
00308 if (isinteger(reg_term(CTXTc 5))|isboxedinteger(reg_term(CTXTc 5))) {
00309 SET_FILEPTR(fromproc_stderr_fptr, int_val(reg_term(CTXTc 5)));
00310 }
00311
00312 if (!isref(reg_term(CTXTc 6)))
00313 xsb_abort("[%s] Arg 5 (process id) must be a variable", callname);
00314
00315 if (params_are_in_a_list) {
00316
00317 if (isnil(cmdspec_term))
00318 xsb_abort("[%s] Arg 1 must not be an empty list", callname);
00319
00320 cmdlist_temp_term = cmdspec_term;
00321 do {
00322 cmd_or_arg_term = p2p_car(cmdlist_temp_term);
00323 cmdlist_temp_term = p2p_cdr(cmdlist_temp_term);
00324 if (isstring(cmd_or_arg_term)) {
00325 cmd_or_arg = string_val(cmd_or_arg_term);
00326 }
00327 else
00328 xsb_abort("[%s] Non string list member in the Arg",
00329 callname);
00330
00331 params[idx++] = cmd_or_arg;
00332 if (idx > MAX_SUBPROC_PARAMS)
00333 xsb_abort("[%s] Too many arguments passed to subprocess",
00334 callname);
00335
00336 } while (!isnil(cmdlist_temp_term));
00337
00338 params[idx] = NULL;
00339
00340 } else {
00341 if (callno == SPAWN_PROCESS)
00342 split_command_arguments(shell_cmd, params, callname);
00343 else {
00344
00345 params[0] = shell_cmd;
00346 params[1] = NULL;
00347 }
00348 }
00349
00350
00351 if ((tbl_pos = get_free_process_cell()) < 0) {
00352 xsb_warn("Can't create subprocess because XSB process table is full");
00353 return FALSE;
00354 }
00355
00356
00357 pid_or_status = xsb_spawn(params[0], params, callno,
00358 (toproc_needed ? pipe_to_proc : NULL),
00359 (fromproc_needed ? pipe_from_proc : NULL),
00360 (fromstderr_needed ? pipe_from_stderr : NULL),
00361 toprocess_fptr, fromprocess_fptr,
00362 fromproc_stderr_fptr);
00363
00364 if (pid_or_status < 0) {
00365 xsb_warn("[%s] Subprocess creation failed", callname);
00366 return FALSE;
00367 }
00368
00369 if (toproc_needed) {
00370 toprocess_fptr = fdopen(pipe_to_proc[1], "w");
00371 toproc_stream = xsb_intern_fileptr(toprocess_fptr,callname,"pipe","w");
00372 ctop_int(CTXTc 3, toproc_stream);
00373 }
00374 if (fromproc_needed) {
00375 fromprocess_fptr = fdopen(pipe_from_proc[0], "r");
00376 fromproc_stream = xsb_intern_fileptr(fromprocess_fptr,callname,"pipe","r");
00377 ctop_int(CTXTc 4, fromproc_stream);
00378 }
00379 if (fromstderr_needed) {
00380 fromproc_stderr_fptr = fdopen(pipe_from_stderr[0], "r");
00381 fromproc_stderr_stream
00382 = xsb_intern_fileptr(fromproc_stderr_fptr,callname,"pipe","r");
00383 ctop_int(CTXTc 5, fromproc_stderr_stream);
00384 }
00385 ctop_int(CTXTc 6, pid_or_status);
00386
00387 xsb_process_table.process[tbl_pos].pid = pid_or_status;
00388 xsb_process_table.process[tbl_pos].to_stream = toproc_stream;
00389 xsb_process_table.process[tbl_pos].from_stream = fromproc_stream;
00390 xsb_process_table.process[tbl_pos].stderr_stream = fromproc_stderr_stream;
00391 concat_array(params, " ",
00392 xsb_process_table.process[tbl_pos].cmdline,MAX_CMD_LEN);
00393
00394 return TRUE;
00395 }
00396
00397 case GET_PROCESS_TABLE: {
00398
00399 int i;
00400 prolog_term table_term_tail, listHead;
00401 prolog_term table_term=reg_term(CTXTc 2);
00402
00403 init_process_table();
00404
00405 if (!isref(table_term))
00406 xsb_abort("[GET_PROCESS_TABLE] Arg 1 must be a variable");
00407
00408 table_term_tail = table_term;
00409 for (i=0; i<MAX_SUBPROC_NUMBER; i++) {
00410 if (!FREE_PROC_TABLE_CELL(xsb_process_table.process[i].pid)) {
00411 c2p_list(CTXTc table_term_tail);
00412 listHead = p2p_car(table_term_tail);
00413
00414 c2p_functor(CTXTc "process", 5, listHead);
00415 c2p_int(CTXTc xsb_process_table.process[i].pid, p2p_arg(listHead,1));
00416 c2p_int(CTXTc xsb_process_table.process[i].to_stream, p2p_arg(listHead,2));
00417 c2p_int(CTXTc xsb_process_table.process[i].from_stream, p2p_arg(listHead,3));
00418 c2p_int(CTXTc xsb_process_table.process[i].stderr_stream,
00419 p2p_arg(listHead,4));
00420 c2p_string(CTXTc xsb_process_table.process[i].cmdline, p2p_arg(listHead,5));
00421
00422 table_term_tail = p2p_cdr(table_term_tail);
00423 }
00424 }
00425 c2p_nil(CTXTc table_term_tail);
00426 return p2p_unify(CTXTc table_term, reg_term(CTXTc 2));
00427 }
00428
00429 case PROCESS_STATUS: {
00430 prolog_term pid_term=reg_term(CTXTc 2), status_term=reg_term(CTXTc 3);
00431
00432 init_process_table();
00433
00434 if (!(isinteger(pid_term)|isboxedinteger(pid_term)))
00435 xsb_abort("[PROCESS_STATUS] Arg 1 (process id) must be an integer");
00436 pid = int_val(pid_term);
00437
00438 if (!isref(status_term))
00439 xsb_abort("[PROCESS_STATUS] Arg 2 (process status) must be a variable");
00440
00441 switch (process_status(pid)) {
00442 case RUNNING:
00443 c2p_string(CTXTc "running", status_term);
00444 break;
00445 case STOPPED:
00446 c2p_string(CTXTc "stopped", status_term);
00447 break;
00448 case EXITED_NORMALLY:
00449 c2p_string(CTXTc "exited_normally", status_term);
00450 break;
00451 case EXITED_ABNORMALLY:
00452 c2p_string(CTXTc "exited_abnormally", status_term);
00453 break;
00454 case ABORTED:
00455 c2p_string(CTXTc "aborted", status_term);
00456 break;
00457 case INVALID:
00458 c2p_string(CTXTc "invalid", status_term);
00459 break;
00460 default:
00461 c2p_string(CTXTc "unknown", status_term);
00462 }
00463 return TRUE;
00464 }
00465
00466 case PROCESS_CONTROL: {
00467
00468 int status;
00469 prolog_term pid_term=reg_term(CTXTc 2), signal_term=reg_term(CTXTc 3);
00470
00471 init_process_table();
00472
00473 if (!(isinteger(pid_term)|isboxedinteger(pid_term)))
00474 xsb_abort("[PROCESS_CONTROL] Arg 1 (process id) must be an integer");
00475 pid = int_val(pid_term);
00476
00477 if (isstring(signal_term) && strcmp(string_val(signal_term), "kill")==0) {
00478 if (KILL_FAILED(pid))
00479 return FALSE;
00480 #ifdef WIN_NT
00481 CloseHandle((HANDLE) pid);
00482 #endif
00483 return TRUE;
00484 }
00485 if (isconstr(signal_term)
00486 && strcmp(p2c_functor(signal_term),"wait") == 0
00487 && p2c_arity(signal_term)==1) {
00488 int exit_status;
00489
00490 if (WAIT(pid, status) < 0)
00491 return FALSE;
00492
00493 #ifdef WIN_NT
00494 exit_status = status;
00495 #else
00496 if (WIFEXITED(status))
00497 exit_status = WEXITSTATUS(status);
00498 else
00499 exit_status = -1;
00500 #endif
00501
00502 p2p_unify(CTXTc p2p_arg(signal_term,1), makeint(exit_status));
00503 return TRUE;
00504 }
00505
00506 xsb_warn("[PROCESS_CONTROL] Arg 2: Invalid signal specification. Must be `kill' or `wait(Var)'");
00507 return FALSE;
00508 }
00509
00510 case LIST_DIRECTORY: {
00511
00512 prolog_term handle = reg_term(CTXTc 2);
00513 char *dir_name = ptoc_longstring(CTXTc 3);
00514 prolog_term filename = reg_term(CTXTc 4);
00515
00516 if (is_var(handle))
00517 return xsb_find_first_file(CTXTc handle,dir_name,filename);
00518 else
00519 return xsb_find_next_file(CTXTc handle,dir_name,filename);
00520 }
00521
00522 default:
00523 xsb_abort("[SYS_SYSTEM] Wrong call number (an XSB bug)");
00524 }
00525 return TRUE;
00526 }
00527
00528
00529
00530
00531
00532
00533
00534 static int xsb_spawn (char *progname, char *argv[], int callno,
00535 int pipe_to_proc[],
00536 int pipe_from_proc[],int pipe_from_stderr[],
00537 FILE *toprocess_fptr, FILE *fromprocess_fptr,
00538 FILE *fromproc_stderr_fptr)
00539 {
00540 int pid;
00541 int stdin_saved, stdout_saved, stderr_saved;
00542 static char shell_command[MAX_CMD_LEN];
00543
00544 if ( (pipe_to_proc != NULL) && PIPE(pipe_to_proc) < 0 ) {
00545
00546 xsb_warn("[SPAWN_PROCESS] Can't open pipe for subprocess input");
00547 return PIPE_TO_PROC_FAILED;
00548 }
00549 if ( (pipe_from_proc != NULL) && PIPE(pipe_from_proc) < 0 ) {
00550
00551 xsb_warn("[SPAWN_PROCESS] Can't open pipe for subprocess output");
00552 return PIPE_FROM_PROC_FAILED;
00553 }
00554 if ( (pipe_from_stderr != NULL) && PIPE(pipe_from_stderr) < 0 ) {
00555
00556 xsb_warn("[SPAWN_PROCESS] Can't open pipe for subprocess errors");
00557 return PIPE_FROM_PROC_FAILED;
00558 }
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572 stdin_saved = dup(fileno(stdin));
00573 stdout_saved = dup(fileno(stdout));
00574 stderr_saved = dup(fileno(stderr));
00575 if ((fileno(stdin) < 0) || (stdin_saved < 0))
00576 xsb_warn("[SPAWN_PROCESS] Bad stdin=%d; stdin closed by mistake?",
00577 fileno(stdin));
00578 if ((fileno(stdout) < 0) || (stdout_saved < 0))
00579 xsb_warn("[SPAWN_PROCESS] Bad stdout=%d; stdout closed by mistake?",
00580 fileno(stdout));
00581 if ((fileno(stderr) < 0) || (stderr_saved < 0))
00582 xsb_warn("[SPAWN_PROCESS] Bad stderr=%d; stderr closed by mistake?",
00583 fileno(stderr));
00584
00585 if (pipe_to_proc != NULL) {
00586
00587 if (dup2(pipe_to_proc[0], fileno(stdin)) < 0) {
00588 xsb_warn("[SPAWN_PROCESS] Can't connect pipe %d to subprocess stdin",
00589 pipe_to_proc[0]);
00590 return PIPE_TO_PROC_FAILED;
00591 }
00592 close(pipe_to_proc[0]);
00593 }
00594
00595 if (toprocess_fptr != NULL)
00596 if (dup2(fileno(toprocess_fptr), fileno(stdin)) < 0) {
00597 xsb_warn("[SPAWN_PROCESS] Can't connect stream %d to subprocess stdin",
00598 fileno(toprocess_fptr));
00599 return PIPE_TO_PROC_FAILED;
00600 }
00601
00602 if (pipe_from_proc != NULL) {
00603
00604 if (dup2(pipe_from_proc[1], fileno(stdout)) < 0) {
00605 xsb_warn("[SPAWN_PROCESS] Can't connect subprocess stdout to pipe %d",
00606 pipe_from_proc[1]);
00607 return PIPE_TO_PROC_FAILED;
00608 }
00609 close(pipe_from_proc[1]);
00610 }
00611
00612 if (fromprocess_fptr != NULL)
00613 if (dup2(fileno(fromprocess_fptr), fileno(stdout)) < 0) {
00614 xsb_warn("[SPAWN_PROCESS] Can't connect subprocess stdout to stream %d",
00615 fileno(fromprocess_fptr));
00616 return PIPE_TO_PROC_FAILED;
00617 }
00618
00619 if (pipe_from_stderr != NULL) {
00620
00621 if (dup2(pipe_from_stderr[1], fileno(stderr)) < 0) {
00622 xsb_warn("[SPAWN_PROCESS] Can't connect subprocess stderr to pipe %d",
00623 pipe_from_stderr[1]);
00624 return PIPE_TO_PROC_FAILED;
00625 }
00626 close(pipe_from_stderr[1]);
00627 }
00628
00629 if (fromproc_stderr_fptr != NULL)
00630 if (dup2(fileno(fromproc_stderr_fptr), fileno(stderr)) < 0) {
00631 xsb_warn("[SPAWN_PROCESS] Can't connect subprocess stderr to stream %d",
00632 fileno(fromproc_stderr_fptr));
00633 return PIPE_TO_PROC_FAILED;
00634 }
00635
00636 if (callno == SPAWN_PROCESS) {
00637 #ifdef WIN_NT
00638
00639 static char bufQuoted[MAX_CMD_LEN + 2*(MAX_SUBPROC_PARAMS + 2)];
00640 const char * argvQuoted[MAX_SUBPROC_PARAMS + 2];
00641 char * argq = bufQuoted;
00642 char * arge = bufQuoted + sizeof(bufQuoted);
00643 char ** argp = argv;
00644 size_t len = 0;
00645 int i;
00646
00647 for (i = 0; i < MAX_SUBPROC_PARAMS + 2; ++i) {
00648 if (*argp && (argq + (len = strlen(*argp)) + 4 < arge)) {
00649 argvQuoted[i] = argq;
00650 *argq++ = '"';
00651 strncpy(argq, *argp, len);
00652 argq += len;
00653 *argq++ = '"';
00654 *argq++ = '\0';
00655 ++argp;
00656 } else {
00657 *argq = '\0';
00658 argvQuoted[i] = 0;
00659 break;
00660 }
00661 }
00662 pid = spawnvp(P_NOWAIT, progname, argvQuoted);
00663 #else
00664 pid = fork();
00665 #endif
00666
00667 if (pid < 0) {
00668
00669 xsb_warn("[SPAWN_PROCESS] Can't fork off subprocess");
00670 return pid;
00671 } else if (pid == 0) {
00672
00673
00674
00675
00676 if (pipe_to_proc != NULL) close(pipe_to_proc[1]);
00677
00678 if (pipe_from_proc != NULL) close(pipe_from_proc[0]);
00679 if (pipe_from_stderr != NULL) close(pipe_from_stderr[0]);
00680
00681 #ifndef WIN_NT
00682 execvp(progname, argv);
00683
00684
00685 exit(SUB_PROC_FAILED);
00686 #endif
00687 }
00688 } else {
00689
00690 concat_array(argv, "", shell_command, MAX_CMD_LEN);
00691 pid = system(shell_command);
00692 }
00693
00694
00695
00696
00697 if (dup2(stdin_saved, fileno(stdin)) < 0) {
00698 perror("SPAWN_PROCESS");
00699 close(stdin_saved); close(stdout_saved); close(stderr_saved);
00700 return PIPE_TO_PROC_FAILED;
00701 }
00702 if (dup2(stdout_saved, fileno(stdout)) < 0) {
00703 perror("SPAWN_PROCESS");
00704 close(stdin_saved); close(stdout_saved); close(stderr_saved);
00705 return PIPE_TO_PROC_FAILED;
00706 }
00707 if (dup2(stderr_saved, fileno(stderr)) < 0) {
00708 perror("SPAWN_PROCESS");
00709 close(stdin_saved); close(stdout_saved); close(stderr_saved);
00710 return PIPE_TO_PROC_FAILED;
00711 }
00712
00713 close(stdin_saved); close(stdout_saved); close(stderr_saved);
00714 return pid;
00715 }
00716
00717
00718 static void concat_array(char *array[], char *separator,
00719 char *result_str, int maxsize)
00720 {
00721 int space_left = maxsize-1, separator_size = strlen(separator);
00722 char *current_pos=result_str;
00723 int idx=0, len;
00724
00725
00726 *current_pos='\0';
00727
00728
00729 while ((array[idx] != NULL) && (space_left > 0)) {
00730 len = strlen(array[idx]);
00731
00732 strncat(current_pos, array[idx], space_left);
00733 current_pos = current_pos + (len < space_left ? len : space_left);
00734 *current_pos='\0';
00735 space_left = space_left - len;
00736
00737 strncat(current_pos, separator, space_left);
00738 current_pos += separator_size;
00739 *current_pos='\0';
00740 space_left -= separator_size;
00741 idx++;
00742 }
00743 }
00744
00745
00746 static int get_free_process_cell(void)
00747 {
00748 int possible_free_cell = xsb_process_table.search_idx;
00749 int pid;
00750
00751 do {
00752 pid = xsb_process_table.process[possible_free_cell].pid;
00753 if (FREE_PROC_TABLE_CELL(pid)) {
00754
00755 xsb_process_table.search_idx =
00756 (possible_free_cell + 1) % MAX_SUBPROC_NUMBER;
00757 return possible_free_cell;
00758 }
00759 possible_free_cell = (possible_free_cell + 1) % MAX_SUBPROC_NUMBER;
00760 } while (possible_free_cell != xsb_process_table.search_idx);
00761
00762
00763 return -1;
00764 }
00765
00766
00767 static void init_process_table(void)
00768 {
00769 static xsbBool process_table_initted = FALSE;
00770 int i;
00771
00772 if (!process_table_initted) {
00773 for (i=0; i<MAX_SUBPROC_NUMBER; i++) {
00774 xsb_process_table.process[i].pid = -1;
00775 }
00776 xsb_process_table.search_idx = 0;
00777 process_table_initted = TRUE;
00778 }
00779 }
00780
00781
00782
00783 int process_status(int pid)
00784 {
00785 #ifdef WIN_NT
00786 long status;
00787 if (GetExitCodeProcess((HANDLE) pid, &status)) {
00788 if (status == STILL_ACTIVE)
00789 return RUNNING;
00790 else if (status == 0)
00791 return EXITED_NORMALLY;
00792 else
00793 return EXITED_ABNORMALLY;
00794 } else
00795 return INVALID;
00796 #else
00797 int retcode;
00798 int status;
00799
00800 retcode = waitpid(pid, &status, WNOHANG | WUNTRACED);
00801
00802 if (retcode == 0) return RUNNING;
00803 if (retcode < 0) return INVALID;
00804 if (WIFSTOPPED(status)) return STOPPED;
00805 if (WIFEXITED(status)) {
00806 if (WEXITSTATUS(status))
00807 return EXITED_ABNORMALLY;
00808 else
00809 return EXITED_NORMALLY;
00810 }
00811 if (WIFSIGNALED(status)) return ABORTED;
00812
00813 return UNKNOWN;
00814 #endif
00815 }
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827 static void split_command_arguments(char *string, char *params[], char *callname)
00828 {
00829 int buflen = strlen(string);
00830 int idx = 0;
00831 char *buf_ptr, *arg_ptr;
00832 static char buffer[MAX_CMD_LEN];
00833
00834 if (buflen > MAX_CMD_LEN - 1)
00835 xsb_abort("[%s] Command string too long, %s", callname, string);
00836
00837 buf_ptr = buffer;
00838
00839
00840
00841
00842 do {
00843 arg_ptr = get_next_command_argument(&buf_ptr,&string);
00844 params[idx] = arg_ptr;
00845
00846
00847
00848 idx++;
00849 } while (arg_ptr != NULL && idx <= MAX_SUBPROC_PARAMS);
00850
00851
00852 return;
00853 }
00854
00855
00856
00857
00858
00859
00860
00861
00862 static char *get_next_command_argument(char **buffptr, char **cmdlineprt)
00863 {
00864 short escaped=FALSE;
00865 char quoted = '\0';
00866 char *returnptr = *buffptr;
00867
00868
00869 while (isspace(**cmdlineprt))
00870 (*cmdlineprt)++;
00871
00872
00873
00874 while ((!isspace(**cmdlineprt) || quoted) && **cmdlineprt != '\0') {
00875 if (escaped) {
00876 switch (**cmdlineprt) {
00877 case 'b': **buffptr='\b'; break;
00878 case 'f': **buffptr='\f'; break;
00879 case 'n': **buffptr='\n'; break;
00880 case 'r': **buffptr='\r'; break;
00881 case 't': **buffptr='\t'; break;
00882 case 'v': **buffptr='\v'; break;
00883 default:
00884 **buffptr=**cmdlineprt;
00885 }
00886 (*buffptr)++;
00887 (*cmdlineprt)++;
00888 escaped=FALSE;
00889 continue;
00890 }
00891 switch (**cmdlineprt) {
00892 case '"':
00893 case '\'':
00894 if (!quoted) {
00895
00896 quoted = **cmdlineprt;
00897 } else if (quoted == **cmdlineprt) {
00898
00899 quoted = '\0';
00900 } else {
00901
00902 **buffptr=**cmdlineprt;
00903 (*buffptr)++;
00904 }
00905 (*cmdlineprt)++;
00906 break;
00907 #ifndef WIN_NT
00908 case '\\':
00909 escaped = TRUE;
00910 (*cmdlineprt)++;
00911 break;
00912 #endif
00913 default:
00914 **buffptr=**cmdlineprt;
00915 (*buffptr)++;
00916 (*cmdlineprt)++;
00917 }
00918 }
00919
00920 if (returnptr==*buffptr)
00921 return NULL;
00922
00923 **buffptr='\0';
00924 (*buffptr)++;
00925 return returnptr;
00926 }
00927
00928
00929
00930
00931
00932 xsbBool file_stat(CTXTdeclc int callno, char *file)
00933 {
00934 struct stat stat_buff;
00935 int retcode = stat(file, &stat_buff);
00936
00937 switch (callno) {
00938 case IS_PLAIN_FILE: {
00939 if (retcode == 0 && S_ISREG(stat_buff.st_mode))
00940 return TRUE;
00941 else return FALSE;
00942 }
00943 case IS_DIRECTORY: {
00944 if (retcode == 0 && S_ISDIR(stat_buff.st_mode))
00945 return TRUE;
00946 else return FALSE;
00947 }
00948 case STAT_FILE_TIME: {
00949
00950
00951
00952
00953
00954
00955 int functor_arg3 = isconstr(reg_term(CTXTc 3));
00956 if (!retcode && functor_arg3) {
00957
00958 c2p_int(CTXTc stat_buff.st_mtime >> 24,p2p_arg(reg_term(CTXTc 3),1));
00959 c2p_int(CTXTc 0xFFFFFF & stat_buff.st_mtime,p2p_arg(reg_term(CTXTc 3),2));
00960 } else if (!retcode) {
00961
00962 xsb_warn("Arg 3 (the time argument) must be of the form time(X,Y)");
00963 ctop_int(CTXTc 3, (0x7FFFFFF & stat_buff.st_mtime));
00964 } else if (functor_arg3) {
00965
00966 c2p_int(CTXTc 0, p2p_arg(reg_term(CTXTc 3),2));
00967 c2p_int(CTXTc 0, p2p_arg(reg_term(CTXTc 3),1));
00968 } else {
00969
00970 xsb_warn("Arg 3 (the time argument) must be of the form time(X,Y)");
00971 ctop_int(CTXTc 3, 0);
00972 }
00973 return TRUE;
00974 }
00975 case STAT_FILE_SIZE: {
00976
00977
00978
00979 prolog_term size_lst = p2p_new(CTXT);
00980 prolog_term elt1, elt2, tail;
00981 if (!retcode) {
00982
00983 c2p_list(CTXTc size_lst);
00984 elt1 = p2p_car(size_lst);
00985 tail = p2p_cdr(size_lst);
00986 c2p_list(CTXTc tail);
00987 elt2 = p2p_car(tail);
00988 tail = p2p_cdr(tail); c2p_nil(CTXTc tail);
00989 c2p_int(CTXTc stat_buff.st_size >> 24, elt1);
00990 c2p_int(CTXTc 0xFFFFFF & stat_buff.st_size, elt2);
00991 p2p_unify(CTXTc size_lst,reg_term(CTXTc 3));
00992 return TRUE;
00993 } else
00994 return FALSE;
00995 }
00996 default:
00997 xsb_abort("Unsupported file_stat code: %d\n", callno);
00998 return FALSE;
00999 }
01000 }
01001
01002 static int xsb_find_first_file(CTXTdeclc prolog_term handle,
01003 char *dir,
01004 prolog_term file)
01005 {
01006 #ifdef WIN_NT
01007 WIN32_FIND_DATA filedata;
01008 HANDLE filehandle;
01009
01010 filehandle = FindFirstFile(dir,&filedata);
01011 if (filehandle == INVALID_HANDLE_VALUE)
01012 return FALSE;
01013 c2p_int(CTXTc (Integer)filehandle,handle);
01014 c2p_string(CTXTc filedata.cFileName,file);
01015 return TRUE;
01016 #else
01017 DIR *dirhandle;
01018 struct dirent *dir_entry;
01019
01020 dirhandle = opendir(dir);
01021 if (!dirhandle)
01022 return FALSE;
01023 dir_entry = readdir(dirhandle);
01024 if (!dir_entry) {
01025 closedir(dirhandle);
01026 return FALSE;
01027 }
01028 c2p_int(CTXTc (Integer)dirhandle,handle);
01029 c2p_string(CTXTc dir_entry->d_name,file);
01030 return TRUE;
01031 #endif
01032 }
01033
01034 static int xsb_find_next_file(CTXTdeclc prolog_term handle,
01035 char *dir,
01036 prolog_term file)
01037 {
01038 #ifdef WIN_NT
01039 WIN32_FIND_DATA filedata;
01040 HANDLE filehandle;
01041
01042 filehandle = (HANDLE) p2c_int(handle);
01043 if (!FindNextFile(filehandle,&filedata)) {
01044 FindClose(filehandle);
01045 return FALSE;
01046 }
01047 c2p_string(CTXTc filedata.cFileName,file);
01048 return TRUE;
01049 #else
01050 DIR *dirhandle = (DIR *) p2c_int(handle);
01051 struct dirent *dir_entry;
01052
01053 dir_entry = readdir(dirhandle);
01054 if (!dir_entry) {
01055 closedir(dirhandle);
01056 return FALSE;
01057 }
01058 c2p_string(CTXTc dir_entry->d_name,file);
01059 return TRUE;
01060 #endif
01061 }
01062
01063
01064 static int file_copy(char *source, char *dest)
01065 {
01066 struct stat source_stat;
01067 struct stat dest_stat;
01068 int dest_exists = 0;
01069 int status = 1;
01070
01071 if (stat(source, &source_stat) < 0) {
01072 xsb_warn("[file_copy] Source file not found: %s\n",
01073 source);
01074 return 0;
01075 }
01076
01077 #ifndef WIN_NT
01078 if (lstat(dest, &dest_stat) < 0) {
01079 #else
01080 if (stat(dest, &dest_stat) < 0) {
01081 #endif
01082 if (errno != ENOENT) {
01083 xsb_warn("[file_copy] Unable to stat destination: %s\n", dest);
01084 return 0;
01085 }
01086 } else {
01087 #ifdef WIN_NT
01088 if (!strcmp(source,dest)) {
01089 xsb_warn("[file_copy] %s and %s are the same file.\n", source,dest);
01090 return 0;
01091 }
01092 #else
01093 if (source_stat.st_dev == dest_stat.st_dev &&
01094 source_stat.st_ino == dest_stat.st_ino) {
01095 xsb_warn("[file_copy] %s and %s are the same file.\n", source,dest);
01096 return 0;
01097 }
01098 #endif
01099 dest_exists = 1;
01100 }
01101
01102 if (S_ISDIR(source_stat.st_mode)) {
01103 xsb_warn("[file_copy] Source is a directory: %s\n",source);
01104 return 0;
01105 } else if (S_ISREG(source_stat.st_mode)) {
01106 FILE *sfp, *dfp=NULL;
01107 if ((sfp = fopen(source, "r")) == NULL) {
01108 xsb_warn("[file_copy] Unable to open source file: %s\n", source);
01109 return 0;
01110 }
01111
01112 if (dest_exists) {
01113 if ((dfp = fopen(dest, "w")) == NULL) {
01114 if (unlink(dest) < 0) {
01115 xsb_warn("[file_copy] Unable to remove destination: %s\n",
01116 dest);
01117 fclose (sfp);
01118 return 0;
01119 }
01120 dest_exists = 0;
01121 }
01122 }
01123
01124 if (!dest_exists) {
01125 int fd;
01126
01127 if ((fd = open(dest, O_WRONLY|O_CREAT, source_stat.st_mode)) < 0 ||
01128 (dfp = fdopen(fd, "w")) == NULL) {
01129 if (fd >= 0)
01130 close(fd);
01131 xsb_warn("[file_copy] Unable to open destination: %s\n",dest);
01132 fclose (sfp);
01133 return 0;
01134 }
01135 }
01136
01137 if (copy_file_chunk(sfp, dfp, -1) < 0)
01138 status = 0;
01139
01140 if (fclose(dfp) < 0) {
01141 xsb_warn("[file_copy] Unable to close destination: %s\n", dest);
01142 status = 0;
01143 }
01144
01145 if (fclose(sfp) < 0) {
01146 xsb_warn("[file_copy] Unable to close source: %s\n", source);
01147 status = 0;
01148 }
01149 }
01150 #ifndef WIN_NT
01151 else if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode)
01152 || S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode)
01153 || S_ISLNK(source_stat.st_mode)
01154 ) {
01155
01156 if (dest_exists && unlink(dest) < 0) {
01157 xsb_warn("[file_copy] Unable to remove destination: %s\n", dest);
01158 return 0;
01159 }
01160 }
01161 #endif
01162 else {
01163 xsb_warn("[file_copy] Unrecognized source file type: %s\n", source);
01164 return 0;
01165 }
01166 #ifndef WIN_NT
01167 if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) ||
01168 S_ISSOCK(source_stat.st_mode)) {
01169 if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) {
01170 xsb_warn("[file_copy] Unable to create destination: %s\n", dest);
01171 return 0;
01172 }
01173 } else if (S_ISFIFO(source_stat.st_mode)) {
01174 if (mkfifo(dest, source_stat.st_mode) < 0) {
01175 xsb_warn("[file_copy] Unable to create FIFO: %s\n", dest);
01176 return 0;
01177 }
01178 } else if (S_ISLNK(source_stat.st_mode)) {
01179 char *lpath;
01180 int lpath_len;
01181
01182 lpath = xreadlink(source,&lpath_len);
01183 if (symlink(lpath, dest) < 0) {
01184 xsb_warn("[file_copy] Cannot create symlink %s", dest);
01185 return 0;
01186 }
01187 mem_dealloc(lpath,lpath_len,OTHER_SPACE);
01188 return 1;
01189 }
01190 #endif
01191 return status;
01192 }
01193
01194
01195
01196 static int copy_file_chunk(FILE *src_file, FILE *dst_file, unsigned long chunksize)
01197 {
01198 size_t nread, nwritten, size;
01199 char buffer[BUFSIZ];
01200
01201 while (chunksize != 0) {
01202 if (chunksize > BUFSIZ)
01203 size = BUFSIZ;
01204 else
01205 size = chunksize;
01206
01207 nread = fread (buffer, 1, size, src_file);
01208
01209 if (nread != size && ferror (src_file)) {
01210 xsb_warn("[file_copy] Internal error: read.\n");
01211 return -1;
01212 } else if (nread == 0) {
01213 if (chunksize != -1) {
01214 xsb_warn("[file_copy] Internal error: Unable to read all data.\n");
01215 return -1;
01216 }
01217 return 0;
01218 }
01219
01220 nwritten = fwrite (buffer, 1, nread, dst_file);
01221
01222 if (nwritten != nread) {
01223 if (ferror (dst_file))
01224 xsb_warn("[file_copy] Internal error: write.\n");
01225 else
01226 xsb_warn("[file_copy] Internal error: Unable to write all data.\n");
01227 return -1;
01228 }
01229
01230 if (chunksize != -1)
01231 chunksize -= nwritten;
01232 }
01233
01234 return 0;
01235 }
01236
01237 #ifndef WIN_NT
01238 static char *xreadlink(const char *path, int *bufsize)
01239 {
01240 static const int GROWBY = 80;
01241
01242 char *buf = NULL;
01243 int readsize = 0;
01244 *bufsize = 0;
01245
01246 do {
01247 buf = mem_realloc(buf, *bufsize, *bufsize + GROWBY,OTHER_SPACE);
01248 *bufsize += GROWBY;
01249 readsize = readlink(path, buf, *bufsize);
01250 if (readsize == -1) {
01251 xsb_warn("[file_copy] Internal error: xreadlink.\n");
01252 return NULL;
01253 }
01254 }
01255 while (*bufsize < readsize + 1);
01256
01257 buf[readsize] = '\0';
01258
01259 return buf;
01260 }
01261 #endif