/* Copyright (C) 1996, 1997 John W. Eaton This file is part of Octave. Octave is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. Octave is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Octave; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // Thomas Baier added the original versions of // the following functions: // // mkfifo unlink waitpid #ifdef HAVE_CONFIG_H #include #endif #include #include #include #ifdef HAVE_UNISTD_H #ifdef HAVE_SYS_TYPES_H #include #endif #include #endif #ifdef HAVE_FCNTL_H #include #endif #include "file-ops.h" #include "file-stat.h" #include "oct-syscalls.h" #include "defun.h" #include "error.h" #include "gripes.h" #include "lo-utils.h" #include "oct-map.h" #include "oct-obj.h" #include "oct-stdstrm.h" #include "oct-stream.h" #include "sysdep.h" #include "syswait.h" #include "utils.h" #include "variables.h" static Octave_map mk_stat_map (const file_stat& fs) { Octave_map m; m["dev"] = static_cast (fs.dev ()); m["ino"] = static_cast (fs.ino ()); m["modestr"] = fs.mode_as_string (); m["nlink"] = static_cast (fs.nlink ()); m["uid"] = static_cast (fs.uid ()); m["gid"] = static_cast (fs.gid ()); #if defined (HAVE_ST_RDEV) m["rdev"] = static_cast (fs.rdev ()); #endif m["size"] = static_cast (fs.size ()); m["atime"] = static_cast (fs.atime ()); m["mtime"] = static_cast (fs.mtime ()); m["ctime"] = static_cast (fs.ctime ()); #if defined (HAVE_ST_BLKSIZE) m["blksize"] = static_cast (fs.blksize ()); #endif #if defined (HAVE_ST_BLOCKS) m["blocks"] = static_cast (fs.blocks ()); #endif return m; } DEFUN (dup2, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {[@var{fid}, @var{msg}] =} dup2 (@var{old}, @var{new})\n\ Duplicate a file descriptor.\n\ \n\ If successful, @var{fid} is greater than zero and contains the new file\n\ ID. Otherwise, @var{fid} is negative and @var{msg} contains a\n\ system-dependent error message.\n\ @end deftypefn") { octave_value_list retval; retval(1) = string (); retval(0) = -1.0; int nargin = args.length (); if (nargin == 2) { octave_stream *old_stream = octave_stream_list::lookup (args(0)); octave_stream *new_stream = octave_stream_list::lookup (args(1)); if (! error_state) { int i_old = old_stream->file_number (); int i_new = new_stream->file_number (); if (i_old >= 0 && i_new >= 0) { string msg; int status = octave_syscalls::dup2 (i_old, i_new, msg); retval(0) = static_cast (status); retval(1) = msg; } else error ("dup2: invalid file id"); } else error ("dup2: invalid stream"); } else print_usage ("dup2"); return retval; } DEFUN (exec, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {[@var{err}, @var{msg}] =} exec (@var{file}, @var{args})\n\ Replace current process with a new process. Calling @code{exec} without\n\ first calling @code{fork} will terminate your current Octave process and\n\ replace it with the program named by @var{file}. For example,\n\ \n\ @example\n\ exec (\"ls\" \"-l\")\n\ @end example\n\ \n\ @noindent\n\ will run @code{ls} and return you to your shell prompt.\n\ \n\ If successful, @code{exec} does not return. If @code{exec} does return,\n\ @var{err} will be nonzero, and @var{msg} will contain a system-dependent\n\ error message.\n\ @end deftypefn") { octave_value_list retval; retval(1) = string (); retval(0) = -1.0; int nargin = args.length (); if (nargin == 1 || nargin == 2) { string exec_file = args(0).string_value (); if (! error_state) { string_vector exec_args; if (nargin == 2) { string_vector tmp = args(1).all_strings (); if (! error_state) { int len = tmp.length (); exec_args.resize (len + 1); exec_args[0] = exec_file; for (int i = 0; i < len; i++) exec_args[i+1] = tmp[i]; } else error ("exec: arguments must be strings"); } else { exec_args.resize (1); exec_args[0] = exec_file; } if (! error_state) { string msg; int status = octave_syscalls::execvp (exec_file, exec_args, msg); retval(0) = static_cast (status); retval(1) = msg; } } else error ("exec: first argument must be a string"); } else print_usage ("exec"); return retval; } DEFUN (fcntl, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {[@var{err}, @var{msg}] =} fcntl (@var{fid}, @var{request}, @var{arg})\n\ Change the properties of the open file @var{fid}. The following values\n\ may be passed as @var{request}:\n\ \n\ @vtable @code\n\ @item F_DUPFD\n\ Return a duplicate file descriptor.\n\ \n\ @item F_GETFD\n\ Return the file descriptor flags for @var{fid}.\n\ \n\ @item F_SETFD\n\ Set the file descriptor flags for @var{fid}.\n\ \n\ @item F_GETFL\n\ Return the file status flags for @var{fid}. The following codes may be\n\ returned (some of the flags may be undefined on some systems).\n\ \n\ @vtable @code\n\ @item O_RDONLY\n\ Open for reading only.\n\ \n\ @item O_WRONLY\n\ Open for writing only.\n\ \n\ @item O_RDWR\n\ Open for reading and writing.\n\ \n\ @item O_APPEND\n\ Append on each write.\n\ \n\ @item O_NONBLOCK\n\ Nonblocking mode.\n\ \n\ @item O_SYNC\n\ Wait for writes to complete.\n\ \n\ @item O_ASYNC\n\ Asynchronous I/O.\n\ @end vtable\n\ \n\ @item F_SETFL\n\ Set the file status flags for @var{fid} to the value specified by\n\ @var{arg}. The only flags that can be changed are @code{O_APPEND} and\n\ @code{O_NONBLOCK}.\n\ @end vtable\n\ \n\ If successful, @var{err} is 0 and @var{msg} is an empty string.\n\ Otherwise, @var{err} is nonzero and @var{msg} contains a\n\ system-dependent error message.\n\ @end deftypefn") { octave_value_list retval; retval(1) = string (); retval(0) = -1.0; int nargin = args.length (); if (nargin == 3) { int fid = args(0).int_value (true); int req = args(1).int_value (true); int arg = args(2).int_value (true); if (! error_state) { // XXX FIXME XXX -- Need better checking here? if (fid < 0) error ("fcntl: invalid file id"); else { string msg; int status = octave_syscalls::fcntl (fid, req, arg, msg); retval(0) = static_cast (status); retval(1) = msg; } } else error ("fcntl: file id, request, and argument must be integers"); } else print_usage ("fcntl"); return retval; } DEFUN (fork, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {[@var{pid}, @var{msg}] =} fork ()\n\ Create a copy of the current process.\n\ \n\ Fork can return one of the following values:\n\ \n\ @table @asis\n\ @item > 0\n\ You are in the parent process. The value returned from @code{fork} is\n\ the process id of the child process. You should probably arrange to\n\ wait for any child processes to exit.\n\ \n\ @item 0\n\ You are in the child process. You can call @code{exec} to start another\n\ process. If that fails, you should probably call @code{exit}.\n\ \n\ @item < 0\n\ The call to @code{fork} failed for some reason. You must take evasive\n\ action. A system dependent error message will be waiting in @var{msg}.\n\ @end table\n\ @end deftypefn") { octave_value_list retval; retval(1) = string (); retval(0) = -1.0; int nargin = args.length (); if (nargin == 0) { string msg; pid_t pid = octave_syscalls::fork (msg); retval(0) = static_cast (pid); retval(1) = msg; } else print_usage ("fork"); return retval; } DEFUN (getpgrp, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {pgid =} getpgrp ()\n\ Return the process group id of the current process.\n\ @end deftypefn") { octave_value_list retval; retval(1) = string (); retval(0) = -1.0; int nargin = args.length (); if (nargin == 0) { string msg; retval(0) = static_cast (octave_syscalls::getpgrp (msg)); retval(1) = msg; } else print_usage ("getpgrp"); return retval; } DEFUN (getpid, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {pid =} getpid ()\n\ Return the process id of the current process.\n\ @end deftypefn") { double retval = -1.0; int nargin = args.length (); if (nargin == 0) retval = octave_syscalls::getpid (); else print_usage ("getpid"); return retval; } DEFUN (getppid, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {pid =} getppid ()\n\ Return the process id of the parent process.\n\ @end deftypefn") { double retval = -1.0; int nargin = args.length (); if (nargin == 0) retval = octave_syscalls::getppid (); else print_usage ("getppid"); return retval; } DEFUN (getegid, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {egid =} getegid ()\n\ Return the effective group id of the current process.\n\ @end deftypefn") { double retval = -1.0; int nargin = args.length (); if (nargin == 0) retval = octave_syscalls::getegid (); else print_usage ("getegid"); return retval; } DEFUN (getgid, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {gid =} getgid ()\n\ Return the real group id of the current process.\n\ @end deftypefn") { double retval = -1.0; int nargin = args.length (); if (nargin == 0) retval = octave_syscalls::getgid (); else print_usage ("getgid"); return retval; } DEFUN (geteuid, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {euid =} geteuid ()\n\ Return the effective user id of the current process.\n\ @end deftypefn") { double retval = -1.0; int nargin = args.length (); if (nargin == 0) retval = octave_syscalls::geteuid (); else print_usage ("geteuid"); return retval; } DEFUN (getuid, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {uid =} getuid ()\n\ Return the real user id of the current process.\n\ @end deftypefn") { double retval = -1.0; int nargin = args.length (); if (nargin == 0) retval = octave_syscalls::getuid (); else print_usage ("getuid"); return retval; } DEFUN (lstat, args, , "See stat.") { octave_value_list retval; if (args.length () == 1) { string fname = file_ops::tilde_expand (args(0).string_value ()); if (! error_state) { file_stat fs (fname, false); if (fs) { retval(2) = string (); retval(1) = 0.0; retval(0) = octave_value (mk_stat_map (fs)); } else { retval(2) = fs.error (); retval(1) = -1.0; retval(0) = Matrix (); } } } else print_usage ("lstat"); return retval; } DEFUN (mkfifo, args, , "@deftypefn {Built-in Function} {[@var{err}, @var{msg}] =} mkfifo (@var{name})\n\ Create a @var{fifo} special file named @var{name} with file mode @var{mode}\n\\n\ \n\ If successful, @var{err} is 0 and @var{msg} is an empty string.\n\ Otherwise, @var{err} is nonzero and @var{msg} contains a\n\ system-dependent error message.\n\ @end deftypefn") { octave_value_list retval; retval(1) = string (); retval(0) = -1.0; int nargin = args.length (); if (nargin == 2) { if (args(0).is_string ()) { string name = args(0).string_value (); if (args(1).is_scalar_type ()) { long mode = static_cast (args(1).double_value ()); string msg; int status = file_ops::mkfifo (name, mode, msg); retval(0) = static_cast (status); if (status < 0) retval(1) = msg; } else error ("mkfifo: MODE must be an integer"); } else error ("mkfifo: file name must be a string"); } else print_usage ("mkfifo"); return retval; } DEFUN (pipe, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {[@var{file_ids}, @var{err}, @var{msg}] =} pipe ()\n\ Create a pipe and return the vector @var{file_ids}, which corresponding\n\ to the reading and writing ends of the pipe.\n\ \n\ If successful, @var{err} is 0 and @var{msg} is an empty string.\n\ Otherwise, @var{err} is nonzero and @var{msg} contains a\n\ system-dependent error message.\n\ @end deftypefn") { octave_value_list retval; retval(2) = string (); retval(1) = -1.0; retval(0) = Matrix (); int nargin = args.length (); if (nargin == 0) { int fid[2]; string msg; int status = octave_syscalls::pipe (fid, msg); if (status < 0) retval(2) = msg; else { FILE *in_file = fdopen (fid[0], "r"); FILE *out_file = fdopen (fid[1], "w"); octave_istdiostream *is = new octave_istdiostream (string (), in_file); octave_ostdiostream *os = new octave_ostdiostream (string (), out_file); octave_value_list file_ids; file_ids(1) = octave_stream_list::insert (os); file_ids(0) = octave_stream_list::insert (is); retval(1) = static_cast (status); retval(0) = octave_value (file_ids); } } else print_usage ("pipe"); return retval; } DEFUN (stat, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {[@var{info}, @var{err}, @var{msg}] =} stat (@var{file})\n\ @deftypefnx {Built-in Function} {[@var{info}, @var{err}, @var{msg}] =} lstat (@var{file})\n\ Return a structure @var{s} containing the following information about\n\ @var{file}.\n\ \n\ @table @code\n\ @item dev\n\ ID of device containing a directory entry for this file.\n\ \n\ @item ino\n\ File number of the file.\n\ \n\ @item modestr\n\ File mode, as a string of ten letters or dashes as would be returned by\n\ @kbd{ls -l}.\n\ \n\ @item nlink\n\ Number of links.\n\ \n\ @item uid\n\ User ID of file's owner.\n\ \n\ @item gid\n\ Group ID of file's group.\n\ \n\ @item rdev\n\ ID of device for block or character special files.\n\ \n\ @item size\n\ Size in bytes.\n\ \n\ @item atime\n\ Time of last access in the same form as time values returned from\n\ @code{time}. @xref{Timing Utilities}.\n\ \n\ @item mtime\n\ Time of last modification in the same form as time values returned from\n\ @code{time}. @xref{Timing Utilities}.\n\ \n\ @item ctime\n\ Time of last file status change in the same form as time values\n\ returned from @code{time}. @xref{Timing Utilities}.\n\ \n\ @item blksize\n\ Size of blocks in the file.\n\ \n\ @item blocks\n\ Number of blocks allocated for file.\n\ @end table\n\ \n\ If the call is successful @var{err} is 0 and @var{msg} is an empty\n\ string. If the file does not exist, or some other error occurs, @var{s}\n\ is an empty matrix, @var{err} is @minus{}1, and @var{msg} contains the\n\ corresponding system error message.\n\ \n\ If @var{file} is a symbolic link, @code{stat} will return information\n\ about the actual file the is referenced by the link. Use @code{lstat}\n\ if you want information about the symbolic link itself.\n\ \n\ For example,\n\ \n\ @example\n\ @group\n\ [s, err, msg] = stat (\"/vmlinuz\")\n\ @result{} s =\n\ @{\n\ atime = 855399756\n\ rdev = 0\n\ ctime = 847219094\n\ uid = 0\n\ size = 389218\n\ blksize = 4096\n\ mtime = 847219094\n\ gid = 6\n\ nlink = 1\n\ blocks = 768\n\ modestr = -rw-r--r--\n\ ino = 9316\n\ dev = 2049\n\ @}\n\ @result{} err = 0\n\ @result{} msg = \n\ @end group\n\ @end example\n\ @end deftypefn") { octave_value_list retval; if (args.length () == 1) { string fname = file_ops::tilde_expand (args(0).string_value ()); if (! error_state) { file_stat fs (fname); if (fs) { retval(2) = string (); retval(1) = 0.0; retval(0) = octave_value (mk_stat_map (fs)); } else { retval(2) = fs.error (); retval(1) = -1.0; retval(0) = Matrix (); } } } else print_usage ("stat"); return retval; } DEFUN (unlink, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {[@var{err}, @var{msg}] =} unlink (@var{file})\n\ Delete the file named @var{file}.\n\ \n\ If successful, @var{err} is 0 and @var{msg} is an empty string.\n\ Otherwise, @var{err} is nonzero and @var{msg} contains a\n\ system-dependent error message.\n\ @end deftypefn") { octave_value_list retval; retval(1) = string (); retval(0) = -1.0; int nargin = args.length (); if (nargin == 1) { if (args(0).is_string ()) { string name = args(0).string_value (); string msg; int status = file_ops::unlink (name, msg); retval(0) = static_cast (status); retval(1) = msg; } else error ("unlink: file name must be a string"); } else print_usage ("unlink"); return retval; } DEFUN (waitpid, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {[@var{pid}, @var{msg}] =} waitpid (@var{pid}, @var{options})\n\ Wait for process @var{pid} to terminate. The @var{pid} argument can be:\n\ \n\ @table @asis\n\ @item @minus{}1\n\ Wait for any child process.\n\ \n\ @item 0\n\ Wait for any child process whose process group ID is equal to that of\n\ the Octave interpreter process.\n\ \n\ @item > 0\n\ Wait for termination of the child process with ID @var{pid}.\n\ @end table\n\ \n\ The @var{options} argument can be:\n\ \n\ @table @asis\n\ @item 0\n\ Wait until signal is received or a child process exits (this is the\n\ default if the @var{options} argument is missing).\n\ \n\ @item 1\n\ Do not hang if status is not immediately available.\n\ \n\ @item 2\n\ Report the status of any child processes that are stopped, and whose\n\ status has not yet been reported since they stopped.\n\ \n\ @item 3\n\ Implies both 1 and 2.\n\ @end table\n\ \n\ If the returned value of @var{pid} is greater than 0, it is the process\n\ ID of the child process that exited. If an error occurs, @var{pid} will\n\ be less than zero and @var{msg} will contain a system-dependent error\n\ message.\n\ @end deftypefn") { octave_value_list retval; retval(1) = string (); retval(0) = -1.0; int nargin = args.length (); if (nargin == 1 || nargin == 2) { pid_t pid = args(0).int_value (true); if (! error_state) { int options = 0; if (args.length () == 2) { options = args(1).int_value (true); if (! error_state) { if (options < 0 || options > 3) error ("waitpid: invalid OPTIONS value specified"); } else error ("waitpid: OPTIONS must be in integer"); } if (! error_state) { string msg; pid_t status = octave_syscalls::waitpid (pid, options, msg); retval(0) = static_cast (status); retval(1) = msg; } } else error ("waitpid: PID must be an integer value"); } else print_usage ("waitpid"); return retval; } #if !defined (O_NONBLOCK) && defined (O_NDELAY) #define O_NONBLOCK O_NDELAY #endif void symbols_of_syscalls (void) { #if defined (F_DUPFD) DEFCONST (F_DUPFD, static_cast (F_DUPFD), ""); #endif #if defined (F_GETFD) DEFCONST (F_GETFD, static_cast (F_GETFD), ""); #endif #if defined (F_GETFL) DEFCONST (F_GETFL, static_cast (F_GETFL), ""); #endif #if defined (F_SETFD) DEFCONST (F_SETFD, static_cast (F_SETFD), ""); #endif #if defined (F_SETFL) DEFCONST (F_SETFL, static_cast (F_SETFL), ""); #endif #if defined (O_APPEND) DEFCONST (O_APPEND, static_cast (O_APPEND), ""); #endif #if defined (O_ASYNC) DEFCONST (O_ASYNC, static_cast (O_ASYNC), ""); #endif #if defined (O_CREAT) DEFCONST (O_CREAT, static_cast (O_CREAT), ""); #endif #if defined (O_EXCL) DEFCONST (O_EXCL, static_cast (O_EXCL), ""); #endif #if defined (O_NONBLOCK) DEFCONST (O_NONBLOCK, static_cast (O_NONBLOCK), ""); #endif #if defined (O_RDONLY) DEFCONST (O_RDONLY, static_cast (O_RDONLY), ""); #endif #if defined (O_RDWR) DEFCONST (O_RDWR, static_cast (O_RDWR), ""); #endif #if defined (O_SYNC) DEFCONST (O_SYNC, static_cast (O_SYNC), ""); #endif #if defined (O_TRUNC) DEFCONST (O_TRUNC, static_cast (O_TRUNC), ""); #endif #if defined (O_WRONLY) DEFCONST (O_WRONLY, static_cast (O_WRONLY), ""); #endif } /* ;;; Local Variables: *** ;;; mode: C++ *** ;;; End: *** */