Mercurial > octave
view libinterp/corefcn/syscalls.cc @ 30920:47cbc69e66cd
eliminate direct access to call stack from evaluator
The call stack is an internal implementation detail of the evaluator.
Direct access to it outside of the evlauator should not be needed.
* pt-eval.h (tree_evaluator::get_call_stack): Delete.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Fri, 08 Apr 2022 15:19:22 -0400 |
parents | 32d2b6604a9f |
children | 0a2bf14dd400 |
line wrap: on
line source
//////////////////////////////////////////////////////////////////////// // // Copyright (C) 1996-2022 The Octave Project Developers // // See the file COPYRIGHT.md in the top-level directory of this // distribution or <https://octave.org/copyright/>. // // 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 3 of the License, 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, see // <https://www.gnu.org/licenses/>. // //////////////////////////////////////////////////////////////////////// // Thomas Baier <baier@ci.tuwien.ac.at> added the original versions of // the following functions: // // mkfifo unlink waitpid #if defined (HAVE_CONFIG_H) # include "config.h" #endif #include <cstdio> #include <cstring> #include "cmd-hist.h" #include "fcntl-wrappers.h" #include "file-ops.h" #include "file-stat.h" #include "lo-utils.h" #include "oct-env.h" #include "oct-syscalls.h" #include "oct-uname.h" #include "defun.h" #include "error.h" #include "errwarn.h" #include "event-manager.h" #include "input.h" #include "interpreter.h" #include "oct-hist.h" #include "oct-map.h" #include "oct-stdstrm.h" #include "oct-stream.h" #include "ovl.h" #include "sysdep.h" #include "utils.h" #include "variables.h" OCTAVE_NAMESPACE_BEGIN static octave_scalar_map mk_stat_map (const sys::base_file_stat& fs) { static bool have_rdev = sys::base_file_stat::have_struct_stat_st_rdev (); static bool have_blksize = sys::base_file_stat::have_struct_stat_st_blksize (); static bool have_blocks = sys::base_file_stat::have_struct_stat_st_blocks (); static double nan = numeric_limits<double>::NaN (); octave_scalar_map m; m.assign ("dev", static_cast<double> (fs.dev ())); m.assign ("ino", fs.ino ()); m.assign ("mode", fs.mode ()); m.assign ("modestr", fs.mode_as_string ()); m.assign ("nlink", fs.nlink ()); m.assign ("uid", fs.uid ()); m.assign ("gid", fs.gid ()); m.assign ("rdev", have_rdev ? static_cast<double> (fs.rdev ()) : nan); m.assign ("size", fs.size ()); m.assign ("atime", fs.atime ()); m.assign ("mtime", fs.mtime ()); m.assign ("ctime", fs.ctime ()); if (have_blksize) m.assign ("blksize", fs.blksize ()); else m.assign ("blksize", nan); if (have_blocks) m.assign ("blocks", fs.blocks ()); else m.assign ("blocks", nan); return m; } static octave_value_list mk_stat_result (const sys::base_file_stat& fs) { if (fs) return ovl (octave_value (mk_stat_map (fs)), 0, ""); else return ovl (Matrix (), -1, fs.error ()); } DEFMETHODX ("dup2", Fdup2, interp, args, , doc: /* -*- texinfo -*- @deftypefn {} {[@var{fid}, @var{msg}] =} dup2 (@var{old}, @var{new}) Duplicate a file descriptor. If successful, @var{fid} is greater than zero and contains the new file ID@. Otherwise, @var{fid} is negative and @var{msg} contains a system-dependent error message. @seealso{fopen, fclose, fcntl} @end deftypefn */) { if (args.length () != 2) print_usage (); stream_list& streams = interp.get_stream_list (); stream old_stream = streams.lookup (args(0), "dup2"); stream new_stream = streams.lookup (args(1), "dup2"); int i_old = old_stream.file_number (); int i_new = new_stream.file_number (); if (i_old >= 0 && i_new >= 0) { std::string msg; int status = sys::dup2 (i_old, i_new, msg); return ovl (status, msg); } else return ovl (-1, ""); } DEFMETHODX ("exec", Fexec, interp, args, , doc: /* -*- texinfo -*- @deftypefn {} {[@var{err}, @var{msg}] =} exec (@var{file}, @var{args}) Replace current process with a new process. Calling @code{exec} without first calling @code{fork} will terminate your current Octave process and replace it with the program named by @var{file}. For example, @example exec ("ls", "-l") @end example @noindent will run @code{ls} and return you to your shell prompt. If successful, @code{exec} does not return. If @code{exec} does return, @var{err} will be nonzero, and @var{msg} will contain a system-dependent error message. @end deftypefn */) { int nargin = args.length (); if (nargin < 1 || nargin > 2) print_usage (); std::string exec_file = args(0).xstring_value ("exec: FILE must be a string"); string_vector exec_args; if (nargin == 2) { string_vector tmp = args(1).xstring_vector_value ("exec: all arguments must be strings"); int len = tmp.numel (); exec_args.resize (len + 1); exec_args[0] = exec_file; for (int i = 0; i < len; i++) exec_args[i+1] = tmp[i]; } else { exec_args.resize (1); exec_args[0] = exec_file; } history_system& history_sys = interp.get_history_system (); history_sys.write_timestamp (); if (! command_history::ignoring_entries ()) command_history::clean_up_and_save (); std::string msg; int status = sys::execvp (exec_file, exec_args, msg); return ovl (status, msg); } DEFMETHODX ("popen2", Fpopen2, interp, args, , doc: /* -*- texinfo -*- @deftypefn {} {[@var{in}, @var{out}, @var{pid}] =} popen2 (@var{command}, @var{args}) Start a subprocess with two-way communication. The name of the process is given by @var{command}, and @var{args} is an array or cell array of strings containing options for the command. The file identifiers for the input and output streams of the subprocess are returned in @var{in} and @var{out}. If execution of the command is successful, @var{pid} contains the process ID of the subprocess. Otherwise, @var{pid} is @minus{}1. For example: @example [in, out, pid] = popen2 ("sort", "-r"); fputs (in, "these\nare\nsome\nstrings\n"); fclose (in); EAGAIN = errno ("EAGAIN"); done = false; do s = fgets (out); if (ischar (s)) fputs (stdout, s); elseif (errno () == EAGAIN) pause (0.1); fclear (out); else done = true; endif until (done) fclose (out); waitpid (pid); @print{} these @print{} strings @print{} some @print{} are @end example Note that @code{popen2}, unlike @code{popen}, will not @nospell{"reap"} the child process. If you don't use @code{waitpid} to check the child's exit status, it will linger until Octave exits. @seealso{popen, waitpid} @end deftypefn */) { int nargin = args.length (); if (nargin < 1 || nargin > 3) print_usage (); std::string exec_file = args(0).xstring_value ("popen2: COMMAND argument must be a string"); string_vector arg_list; if (nargin >= 2) { string_vector tmp = args(1).xstring_vector_value ("popen2: all arguments must be strings"); int len = tmp.numel (); arg_list.resize (len + 1); arg_list[0] = exec_file; for (int i = 0; i < len; i++) arg_list[i+1] = tmp[i]; } else { arg_list.resize (1); arg_list[0] = exec_file; } bool sync_mode = (nargin == 3 ? args(2).bool_value () : false); int filedesc[2]; std::string msg; pid_t pid; pid = sys::popen2 (exec_file, arg_list, sync_mode, filedesc, msg); if (pid < 0) error ("%s", msg.c_str ()); FILE *ifile = fdopen (filedesc[1], "r"); FILE *ofile = fdopen (filedesc[0], "w"); stream is = stdiostream::create (exec_file + "-in", ifile, std::ios::in); stream os = stdiostream::create (exec_file + "-out", ofile, std::ios::out); stream_list& streams = interp.get_stream_list (); return ovl (streams.insert (os), streams.insert (is), pid); } /* %!test # UNIX-style test %! if (isunix () || ismac ()) %! [in, out, pid] = popen2 ("sort", "-r"); %! EAGAIN = errno ("EAGAIN"); %! fputs (in, "these\nare\nsome\nstrings\n"); %! fclose (in); %! done = false; %! str = {}; %! idx = 0; %! errs = 0; %! do %! if (ismac ()) # FIXME: Is this necessary? %! errno (0); %! endif %! s = fgets (out); %! if (ischar (s)) %! idx++; %! str{idx} = s; %! elseif (errno () == EAGAIN) %! fclear (out); %! pause (0.1); %! if (++errs == 100) %! done = true; %! endif %! else %! done = true; %! endif %! until (done) %! fclose (out); %! waitpid (pid); %! assert (str, {"these\n","strings\n","some\n","are\n"}); %! endif %!test # Windows-style test %! if (ispc () && ! isunix ()) %! [in, out, pid] = popen2 ('C:\Windows\system32\sort.exe', "/R"); %! EAGAIN = errno ("EINVAL"); %! fputs (in, "these\r\nare\r\nsome\r\nstrings\r\n"); %! fclose (in); %! done = false; %! str = {}; %! idx = 0; %! errs = 0; %! do %! errno (0); %! s = fgets (out); %! if (ischar (s)) %! idx++; %! str{idx} = s; %! elseif (errno () == EAGAIN) %! fclear (out); %! pause (0.1); %! if (++errs == 100) %! done = true; %! endif %! else %! done = true; %! endif %! until (done) %! fclose (out); %! waitpid (pid); %! assert (str, {"these\r\n","strings\r\n","some\r\n","are\r\n"}); %! endif */ DEFMETHODX ("fcntl", Ffcntl, interp, args, nargout, doc: /* -*- texinfo -*- @deftypefn {} {} fcntl (@var{fid}, @var{request}, @var{arg}) @deftypefnx {} {[@var{status}, @var{msg}] =} fcntl (@var{fid}, @var{request}, @var{arg}) Change the properties of the open file @var{fid}. The following values may be passed as @var{request}: @vtable @code @item F_DUPFD Return a duplicate file descriptor. @item F_GETFD Return the file descriptor flags for @var{fid}. @item F_SETFD Set the file descriptor flags for @var{fid}. @item F_GETFL Return the file status flags for @var{fid}. The following codes may be returned (some of the flags may be undefined on some systems). @vtable @code @item O_RDONLY Open for reading only. @item O_WRONLY Open for writing only. @item O_RDWR Open for reading and writing. @item O_APPEND Append on each write. @item O_CREAT Create the file if it does not exist. @item O_NONBLOCK Non-blocking mode. @item O_SYNC Wait for writes to complete. @item O_ASYNC Asynchronous I/O. @end vtable @item F_SETFL Set the file status flags for @var{fid} to the value specified by @var{arg}. The only flags that can be changed are @w{@code{O_APPEND}} and @w{@code{O_NONBLOCK}}. @end vtable If successful, @var{status} is 0 and @var{msg} is an empty string. Otherwise, @var{status} is -1 and @var{msg} contains a system-dependent error message. @seealso{fopen, dup2} @end deftypefn */) { if (args.length () != 3) print_usage (); stream_list& streams = interp.get_stream_list (); stream strm = streams.lookup (args(0), "fcntl"); int fid = strm.file_number (); // FIXME: Do we want to use xint_value and throw a warning message // if input validation fails? int req = args(1).int_value (true); int arg = args(2).int_value (true); // FIXME: Need better checking here? if (fid < 0) error ("fcntl: invalid file id"); octave_value_list retval; std::string msg; int status = sys::fcntl (fid, req, arg, msg); if (nargout == 0) { if (status < 0) error ("fcntl: operation failed: %s", msg.c_str ()); } else { if (status < 0) retval = ovl (-1.0, msg); else retval = ovl (0.0, ""); } return retval; } DEFMETHODX ("fork", Ffork, interp, args, , doc: /* -*- texinfo -*- @deftypefn {} {[@var{pid}, @var{msg}] =} fork () Create a copy of the current process. Fork can return one of the following values: @table @asis @item > 0 You are in the parent process. The value returned from @code{fork} is the process id of the child process. You should probably arrange to wait for any child processes to exit. @item 0 You are in the child process. You can call @code{exec} to start another process. If that fails, you should probably call @code{exit}. @item < 0 The call to @code{fork} failed for some reason. You must take evasive action. A system dependent error message will be waiting in @var{msg}. @end table @end deftypefn */) { if (args.length () != 0) print_usage (); if (interp.at_top_level ()) error ("fork: cannot be called from command line"); std::string msg; pid_t pid = sys::fork (msg); return ovl (pid, msg); } DEFUNX ("getpgrp", Fgetpgrp, args, , doc: /* -*- texinfo -*- @deftypefn {} {pgid =} getpgrp () Return the process group id of the current process. @end deftypefn */) { if (args.length () != 0) print_usage (); std::string msg; pid_t pid = sys::getpgrp (msg); return ovl (pid, msg); } DEFUNX ("getpid", Fgetpid, args, , doc: /* -*- texinfo -*- @deftypefn {} {pid =} getpid () Return the process id of the current process. @seealso{getppid} @end deftypefn */) { if (args.length () != 0) print_usage (); return ovl (sys::getpid ()); } DEFUNX ("getppid", Fgetppid, args, , doc: /* -*- texinfo -*- @deftypefn {} {pid =} getppid () Return the process id of the parent process. @seealso{getpid} @end deftypefn */) { if (args.length () != 0) print_usage (); return ovl (sys::getppid ()); } DEFUNX ("getegid", Fgetegid, args, , doc: /* -*- texinfo -*- @deftypefn {} {egid =} getegid () Return the effective group id of the current process. @seealso{getgid} @end deftypefn */) { if (args.length () != 0) print_usage (); return ovl (sys::getegid ()); } DEFUNX ("getgid", Fgetgid, args, , doc: /* -*- texinfo -*- @deftypefn {} {gid =} getgid () Return the real group id of the current process. @seealso{getegid} @end deftypefn */) { if (args.length () != 0) print_usage (); return ovl (sys::getgid ()); } DEFUNX ("geteuid", Fgeteuid, args, , doc: /* -*- texinfo -*- @deftypefn {} {euid =} geteuid () Return the effective user id of the current process. @seealso{getuid} @end deftypefn */) { if (args.length () != 0) print_usage (); return ovl (sys::geteuid ()); } DEFUNX ("getuid", Fgetuid, args, , doc: /* -*- texinfo -*- @deftypefn {} {uid =} getuid () Return the real user id of the current process. @seealso{geteuid} @end deftypefn */) { if (args.length () != 0) print_usage (); return ovl (sys::getuid ()); } DEFUNX ("kill", Fkill, args, nargout, doc: /* -*- texinfo -*- @deftypefn {} {} kill (@var{pid}, @var{sig}) @deftypefnx {} {[@var{status}, @var{msg}] =} kill (@var{pid}, @var{sig}) Send signal @var{sig} to process @var{pid}. If @var{pid} is positive, then signal @var{sig} is sent to @var{pid}. If @var{pid} is 0, then signal @var{sig} is sent to every process in the process group of the current process. If @var{pid} is -1, then signal @var{sig} is sent to every process except process 1. If @var{pid} is less than -1, then signal @var{sig} is sent to every process in the process group @var{-pid}. If @var{sig} is 0, then no signal is sent, but error checking is still performed. If successful, @var{status} is 0 and @var{msg} is an empty string. Otherwise, @var{status} is -1 and @var{msg} contains a system-dependent error message. @end deftypefn */) { if (args.length () != 2) print_usage (); pid_t pid = args(0).int_value (true); int sig = args(1).int_value (true); octave_value_list retval; std::string msg; int status = sys::kill (pid, sig, msg); if (nargout == 0) { if (status < 0) error ("kill: operation failed: %s", msg.c_str ()); } else { if (status < 0) retval = ovl (-1.0, msg); else retval = ovl (0.0, ""); } return retval; } DEFUNX ("lstat", Flstat, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{info} =} lstat (@var{symlink}) @deftypefnx {} {[@var{info}, @var{err}, @var{msg}] =} lstat (@var{symlink}) Return a structure @var{info} containing information about the symbolic link @var{symlink}. The function outputs are described in the documentation for @code{stat}. @seealso{stat, symlink} @end deftypefn */) { if (args.length () != 1) print_usage (); std::string fname = args(0).xstring_value ("lstat: NAME must be a string"); sys::file_stat fs (fname, false); return mk_stat_result (fs); } // FIXME: This routine also exists verbatim in file-io.cc. // Maybe change to be a general utility routine. static int convert (int x, int ibase, int obase) { int retval = 0; int tmp = x % obase; if (tmp > ibase - 1) error ("mkfifo: invalid digit"); retval = tmp; int mult = ibase; while ((x = (x - tmp) / obase)) { tmp = x % obase; if (tmp > ibase - 1) error ("mkfifo: invalid digit"); retval += mult * tmp; mult *= ibase; } return retval; } DEFUNX ("mkfifo", Fmkfifo, args, nargout, doc: /* -*- texinfo -*- @deftypefn {} {} mkfifo (@var{name}, @var{mode}) @deftypefnx {} {[@var{status}, @var{msg}] =} mkfifo (@var{name}, @var{mode}) Create a FIFO special file named @var{name} with file mode @var{mode}. @var{mode} is interpreted as an octal number and is subject to umask processing. The final calculated mode is @code{@var{mode} - @var{umask}}. If successful, @var{status} is 0 and @var{msg} is an empty string. Otherwise, @var{status} is -1 and @var{msg} contains a system-dependent error message. @seealso{pipe, umask} @end deftypefn */) { if (args.length () != 2) print_usage (); std::string name = args(0).xstring_value ("mkfifo: FILE must be a string"); int octal_mode = args(1).xint_value ("mkfifo: MODE must be an integer"); if (octal_mode < 0) error ("mkfifo: MODE must be a positive integer value"); int mode = convert (octal_mode, 8, 10); octave_value_list retval; std::string msg; int status = sys::mkfifo (name, mode, msg); if (nargout == 0) { if (status < 0) error ("mkfifo: operation failed: %s", msg.c_str ()); } else { if (status < 0) retval = ovl (-1.0, msg); else retval = ovl (0.0, ""); } return retval; } /* ## Test input validation %!error mkfifo () %!error mkfifo ("abc") %!error mkfifo ("abc", 777, 123) %!error <FILE must be a string> mkfifo (123, 456) ## FIXME: These tests should work, but lasterr is not being set correctly. #%!error <MODE must be an integer> mkfifo ("abc", {456}) #%!error <MODE must be a positive integer value> mkfifo ("abc", -1) */ DEFMETHODX ("pipe", Fpipe, interp, args, , doc: /* -*- texinfo -*- @deftypefn {} {[@var{read_fd}, @var{write_fd}, @var{err}, @var{msg}] =} pipe () Create a pipe and return the reading and writing ends of the pipe into @var{read_fd} and @var{write_fd} respectively. If successful, @var{err} is 0 and @var{msg} is an empty string. Otherwise, @var{err} is nonzero and @var{msg} contains a system-dependent error message. @seealso{mkfifo} @end deftypefn */) { if (args.length () != 0) print_usage (); int fid[2]; std::string msg; int status = sys::pipe (fid, msg); if (status < 0) return ovl (-1, -1, -1, msg); else { FILE *ifile = fdopen (fid[0], "r"); FILE *ofile = fdopen (fid[1], "w"); stream is = stdiostream::create ("pipe-in", ifile, std::ios::in); stream os = stdiostream::create ("pipe-out", ofile, std::ios::out); stream_list& streams = interp.get_stream_list (); return ovl (streams.insert (is), streams.insert (os), status, msg); } } DEFMETHODX ("stat", Fstat, interp, args, , doc: /* -*- texinfo -*- @deftypefn {} {[@var{info}, @var{err}, @var{msg}] =} stat (@var{file}) @deftypefnx {} {[@var{info}, @var{err}, @var{msg}] =} stat (@var{fid}) @deftypefnx {} {[@var{info}, @var{err}, @var{msg}] =} lstat (@var{file}) @deftypefnx {} {[@var{info}, @var{err}, @var{msg}] =} lstat (@var{fid}) Return a structure @var{info} containing the following information about @var{file} or file identifier @var{fid}. @table @code @item dev ID of device containing a directory entry for this file. @item ino File number of the file. @item mode File mode, as an integer. Use the functions @w{@code{S_ISREG}}, @w{@code{S_ISDIR}}, @w{@code{S_ISCHR}}, @w{@code{S_ISBLK}}, @w{@code{S_ISFIFO}}, @w{@code{S_ISLNK}}, or @w{@code{S_ISSOCK}} to extract information from this value. @item modestr File mode, as a string of ten letters or dashes as would be returned by @kbd{ls -l}. @item nlink Number of links. @item uid User ID of file's owner. @item gid Group ID of file's group. @item rdev ID of device for block or character special files. @item size Size in bytes. @item atime Time of last access in the same form as time values returned from @code{time}. @xref{Timing Utilities}. @item mtime Time of last modification in the same form as time values returned from @code{time}. @xref{Timing Utilities}. @item ctime Time of last file status change in the same form as time values returned from @code{time}. @xref{Timing Utilities}. @item blksize Size of blocks in the file. @item blocks Number of blocks allocated for file. @end table If the call is successful @var{err} is 0 and @var{msg} is an empty string. If the file does not exist, or some other error occurs, @var{info} is an empty matrix, @var{err} is @minus{}1, and @var{msg} contains the corresponding system error message. If @var{file} is a symbolic link, @code{stat} will return information about the actual file that is referenced by the link. Use @code{lstat} if you want information about the symbolic link itself. For example: @example [info, err, msg] = stat ("/vmlinuz") @result{} info = @{ atime = 855399756 rdev = 0 ctime = 847219094 uid = 0 size = 389218 blksize = 4096 mtime = 847219094 gid = 6 nlink = 1 blocks = 768 mode = -rw-r--r-- modestr = -rw-r--r-- ino = 9316 dev = 2049 @} @result{} err = 0 @result{} msg = @end example @seealso{lstat, ls, dir, isfile, isfolder} @end deftypefn */) { if (args.length () != 1) print_usage (); octave_value_list retval; if (args(0).is_scalar_type ()) { stream_list& streams = interp.get_stream_list (); int fid = streams.get_file_number (args(0)); sys::file_fstat fs (fid); retval = mk_stat_result (fs); } else { std::string fname = args(0).xstring_value ("stat: NAME must be a string"); sys::file_stat fs (fname); retval = mk_stat_result (fs); } return retval; } DEFUNX ("S_ISREG", FS_ISREG, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{tf} =} S_ISREG (@var{mode}) Return true if @var{mode} corresponds to a regular file. The value of @var{mode} is assumed to be returned from a call to @code{stat}. @seealso{stat, lstat} @end deftypefn */) { if (args.length () != 1) print_usage (); double mode = args(0).xdouble_value ("S_ISREG: invalid MODE value"); return ovl (sys::file_stat::is_reg (static_cast<mode_t> (mode))); } DEFUNX ("S_ISDIR", FS_ISDIR, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{tf} =} S_ISDIR (@var{mode}) Return true if @var{mode} corresponds to a directory. The value of @var{mode} is assumed to be returned from a call to @code{stat}. @seealso{stat, lstat} @end deftypefn */) { if (args.length () != 1) print_usage (); double mode = args(0).xdouble_value ("S_ISDIR: invalid MODE value"); return ovl (sys::file_stat::is_dir (static_cast<mode_t> (mode))); } DEFUNX ("S_ISCHR", FS_ISCHR, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{tf} =} S_ISCHR (@var{mode}) Return true if @var{mode} corresponds to a character device. The value of @var{mode} is assumed to be returned from a call to @code{stat}. @seealso{stat, lstat} @end deftypefn */) { if (args.length () != 1) print_usage (); double mode = args(0).xdouble_value ("S_ISCHR: invalid MODE value"); return ovl (sys::file_stat::is_chr (static_cast<mode_t> (mode))); } DEFUNX ("S_ISBLK", FS_ISBLK, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{tf} =} S_ISBLK (@var{mode}) Return true if @var{mode} corresponds to a block device. The value of @var{mode} is assumed to be returned from a call to @code{stat}. @seealso{stat, lstat} @end deftypefn */) { if (args.length () != 1) print_usage (); double mode = args(0).xdouble_value ("S_ISBLK: invalid MODE value"); return ovl (sys::file_stat::is_blk (static_cast<mode_t> (mode))); } DEFUNX ("S_ISFIFO", FS_ISFIFO, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{tf} =} S_ISFIFO (@var{mode}) Return true if @var{mode} corresponds to a fifo. The value of @var{mode} is assumed to be returned from a call to @code{stat}. @seealso{stat, lstat} @end deftypefn */) { if (args.length () != 1) print_usage (); double mode = args(0).xdouble_value ("S_ISFIFO: invalid MODE value"); return ovl (sys::file_stat::is_fifo (static_cast<mode_t> (mode))); } DEFUNX ("S_ISLNK", FS_ISLNK, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{tf} =} S_ISLNK (@var{mode}) Return true if @var{mode} corresponds to a symbolic link. The value of @var{mode} is assumed to be returned from a call to @code{stat}. @seealso{stat, lstat} @end deftypefn */) { if (args.length () != 1) print_usage (); double mode = args(0).xdouble_value ("S_ISLNK: invalid MODE value"); return ovl (sys::file_stat::is_lnk (static_cast<mode_t> (mode))); } DEFUNX ("S_ISSOCK", FS_ISSOCK, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{tf} =} S_ISSOCK (@var{mode}) Return true if @var{mode} corresponds to a socket. The value of @var{mode} is assumed to be returned from a call to @code{stat}. @seealso{stat, lstat} @end deftypefn */) { if (args.length () != 1) print_usage (); double mode = args(0).xdouble_value ("S_ISSOCK: invalid MODE value"); return ovl (sys::file_stat::is_sock (static_cast<mode_t> (mode))); } DEFUN (gethostname, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{name} =} gethostname () Return the hostname of the system where Octave is running. @end deftypefn */) { if (args.length () != 0) print_usage (); return ovl (sys::env::get_host_name ()); } DEFUN (uname, args, , doc: /* -*- texinfo -*- @deftypefn {} {[@var{uts}, @var{err}, @var{msg}] =} uname () Return system information in the structure. For example: @example @group uname () @result{} @{ sysname = x86_64 nodename = segfault release = 2.6.15-1-amd64-k8-smp version = Linux machine = #2 SMP Thu Feb 23 04:57:49 UTC 2006 @} @end group @end example If successful, @var{err} is 0 and @var{msg} is an empty string. Otherwise, @var{err} is nonzero and @var{msg} contains a system-dependent error message. @end deftypefn */) { if (args.length () != 0) print_usage (); sys::uname sysinfo; octave_scalar_map m; m.assign ("sysname", sysinfo.sysname ()); m.assign ("nodename", sysinfo.nodename ()); m.assign ("release", sysinfo.release ()); m.assign ("version", sysinfo.version ()); m.assign ("machine", sysinfo.machine ()); return ovl (m, sysinfo.error (), sysinfo.message ()); } /* %!test <*51869> %! [info, status, msg] = uname (); %! if (status == 0) %! assert (isstruct (info)) %! assert (ischar (msg) && isempty (msg)) %! endif */ DEFMETHODX ("unlink", Funlink, interp, args, nargout, doc: /* -*- texinfo -*- @deftypefn {} {} unlink (@var{file}) @deftypefnx {} {[@var{status}, @var{msg}] =} unlink (@var{file}) Delete the file named @var{file}. If successful, @var{status} is 0 and @var{msg} is an empty string. Otherwise, @var{status} is -1 and @var{msg} contains a system-dependent error message. @seealso{delete, rmdir} @end deftypefn */) { if (args.length () != 1) print_usage (); std::string name = args(0).xstring_value ("unlink: FILE must be a string"); octave_value_list retval; std::string msg; event_manager& evmgr = interp.get_event_manager (); evmgr.file_remove (name, ""); int status = sys::unlink (name, msg); evmgr.file_renamed (status == 0); if (nargout == 0) { if (status < 0) error ("unlink: operation failed: %s", msg.c_str ()); } else { if (status < 0) retval = ovl (-1.0, msg); else retval = ovl (0.0, ""); } return retval; } /* %!test %! file = tempname (); %! fid = fopen (file, "wt"); %! if (fid < 0) %! error ("Could not open temporary file for unlink BIST test"); %! endif %! fdisp (fid, pi); %! fclose (fid); %! [status, msg] = unlink (file); %! assert (status, 0); %! assert (msg, ""); ## Test input validation %!error <Invalid call> unlink () %!error <Invalid call> unlink ("a", "b") %!error <FILE must be a string> unlink (123) */ DEFUNX ("waitpid", Fwaitpid, args, , doc: /* -*- texinfo -*- @deftypefn {} {[@var{pid}, @var{status}, @var{msg}] =} waitpid (@var{pid}, @var{options}) Wait for process @var{pid} to terminate. The @var{pid} argument can be: @table @asis @item @minus{}1 Wait for any child process. @item 0 Wait for any child process whose process group ID is equal to that of the Octave interpreter process. @item > 0 Wait for termination of the child process with ID @var{pid}. @end table The @var{options} argument can be a bitwise OR of zero or more of the following constants: @table @code @item 0 Wait until signal is received or a child process exits (this is the default if the @var{options} argument is missing). @item WNOHANG Do not hang if status is not immediately available. @item WUNTRACED Report the status of any child processes that are stopped, and whose status has not yet been reported since they stopped. @item WCONTINUE Return if a stopped child has been resumed by delivery of @code{SIGCONT}. This value may not be meaningful on all systems. @end table If the returned value of @var{pid} is greater than 0, it is the process ID of the child process that exited. If an error occurs, @var{pid} will be less than zero and @var{msg} will contain a system-dependent error message. The value of @var{status} contains additional system-dependent information about the subprocess that exited. @seealso{WCONTINUE, WCOREDUMP, WEXITSTATUS, WIFCONTINUED, WIFSIGNALED, WIFSTOPPED, WNOHANG, WSTOPSIG, WTERMSIG, WUNTRACED} @end deftypefn */) { int nargin = args.length (); if (nargin != 1 && nargin != 2) print_usage (); pid_t pid = args(0).xint_value ("waitpid: OPTIONS must be an integer"); int options = 0; if (nargin == 2) options = args(1).xint_value ("waitpid: PID must be an integer value"); std::string msg; int status; pid_t result = sys::waitpid (pid, &status, options, msg); return ovl (result, status, msg); } DEFUNX ("WIFEXITED", FWIFEXITED, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{tf} =} WIFEXITED (@var{status}) Given @var{status} from a call to @code{waitpid}, return true if the child terminated normally. @seealso{waitpid, WEXITSTATUS, WIFSIGNALED, WTERMSIG, WCOREDUMP, WIFSTOPPED, WSTOPSIG, WIFCONTINUED} @end deftypefn */) { if (args.length () != 1) print_usage (); int status = args(0).xint_value ("WIFEXITED: STATUS must be an integer"); return ovl (sys::wifexited (status)); } DEFUNX ("WEXITSTATUS", FWEXITSTATUS, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{tf} =} WEXITSTATUS (@var{status}) Given @var{status} from a call to @code{waitpid}, return the exit status of the child. This function should only be employed if @code{WIFEXITED} returned true. @seealso{waitpid, WIFEXITED, WIFSIGNALED, WTERMSIG, WCOREDUMP, WIFSTOPPED, WSTOPSIG, WIFCONTINUED} @end deftypefn */) { if (args.length () != 1) print_usage (); int status = args(0).xint_value ("WEXITSTATUS: STATUS must be an integer"); return ovl (sys::wexitstatus (status)); } DEFUNX ("WIFSIGNALED", FWIFSIGNALED, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{tf} =} WIFSIGNALED (@var{status}) Given @var{status} from a call to @code{waitpid}, return true if the child process was terminated by a signal. @seealso{waitpid, WIFEXITED, WEXITSTATUS, WTERMSIG, WCOREDUMP, WIFSTOPPED, WSTOPSIG, WIFCONTINUED} @end deftypefn */) { if (args.length () != 1) print_usage (); int status = args(0).xint_value ("WIFSIGNALED: STATUS must be an integer"); return ovl (sys::wifsignaled (status)); } DEFUNX ("WTERMSIG", FWTERMSIG, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{tf} =} WTERMSIG (@var{status}) Given @var{status} from a call to @code{waitpid}, return the number of the signal that caused the child process to terminate. This function should only be employed if @code{WIFSIGNALED} returned true. @seealso{waitpid, WIFEXITED, WEXITSTATUS, WIFSIGNALED, WCOREDUMP, WIFSTOPPED, WSTOPSIG, WIFCONTINUED} @end deftypefn */) { if (args.length () != 1) print_usage (); int status = args(0).xint_value ("WTERMSIG: STATUS must be an integer"); return ovl (sys::wtermsig (status)); } DEFUNX ("WCOREDUMP", FWCOREDUMP, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{tf} =} WCOREDUMP (@var{status}) Given @var{status} from a call to @code{waitpid}, return true if the child produced a core dump. This function should only be employed if @code{WIFSIGNALED} returned true. The macro used to implement this function is not specified in POSIX.1-2001 and is not available on some Unix implementations (e.g., @nospell{AIX, SunOS}). @seealso{waitpid, WIFEXITED, WEXITSTATUS, WIFSIGNALED, WTERMSIG, WIFSTOPPED, WSTOPSIG, WIFCONTINUED} @end deftypefn */) { if (args.length () != 1) print_usage (); int status = args(0).xint_value ("WCOREDUMP: STATUS must be an integer"); return ovl (sys::wcoredump (status)); } DEFUNX ("WIFSTOPPED", FWIFSTOPPED, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{tf} =} WIFSTOPPED (@var{status}) Given @var{status} from a call to @code{waitpid}, return true if the child process was stopped by delivery of a signal. This is only possible if the call was done using @code{WUNTRACED} or when the child is being traced (see ptrace(2)). @seealso{waitpid, WIFEXITED, WEXITSTATUS, WIFSIGNALED, WTERMSIG, WCOREDUMP, WSTOPSIG, WIFCONTINUED} @end deftypefn */) { if (args.length () != 1) print_usage (); int status = args(0).xint_value ("WIFSTOPPED: STATUS must be an integer"); return ovl (sys::wifstopped (status)); } DEFUNX ("WSTOPSIG", FWSTOPSIG, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{tf} =} WSTOPSIG (@var{status}) Given @var{status} from a call to @code{waitpid}, return the number of the signal which caused the child to stop. This function should only be employed if @code{WIFSTOPPED} returned true. @seealso{waitpid, WIFEXITED, WEXITSTATUS, WIFSIGNALED, WTERMSIG, WCOREDUMP, WIFSTOPPED, WIFCONTINUED} @end deftypefn */) { if (args.length () != 1) print_usage (); int status = args(0).xint_value ("WSTOPSIG: STATUS must be an integer"); return ovl (sys::wstopsig (status)); } DEFUNX ("WIFCONTINUED", FWIFCONTINUED, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{tf} =} WIFCONTINUED (@var{status}) Given @var{status} from a call to @code{waitpid}, return true if the child process was resumed by delivery of @code{SIGCONT}. @seealso{waitpid, WIFEXITED, WEXITSTATUS, WIFSIGNALED, WTERMSIG, WCOREDUMP, WIFSTOPPED, WSTOPSIG} @end deftypefn */) { if (args.length () != 1) print_usage (); int status = args(0).xint_value ("WIFCONTINUED: STATUS must be an integer"); return ovl (sys::wifcontinued (status)); } DEFUNX ("canonicalize_file_name", Fcanonicalize_file_name, args, , doc: /* -*- texinfo -*- @deftypefn {} {[@var{cname}, @var{status}, @var{msg}] =} canonicalize_file_name (@var{fname}) Return the canonical name of file @var{fname}. If the file does not exist the empty string ("") is returned. No tilde expansion of @var{fname} is performed. @seealso{make_absolute_filename, is_absolute_filename, is_rooted_relative_filename, is_same_file, tilde_expand} @end deftypefn */) { if (args.length () != 1) print_usage (); std::string name = args(0).xstring_value ("canonicalize_file_name: NAME must be a string"); std::string msg; std::string result = sys::canonicalize_file_name (name, msg); return ovl (result, msg.empty () ? 0 : -1, msg); } static inline octave_value const_value (const octave_value_list& args, int val) { if (args.length () != 0) print_usage (); return octave_value (val); } DEFUNX ("F_DUPFD", FF_DUPFD, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{v} =} F_DUPFD () Return the numerical value to pass to @code{fcntl} to return a duplicate file descriptor. @seealso{fcntl, F_GETFD, F_GETFL, F_SETFD, F_SETFL} @end deftypefn */) { static int val = octave_f_dupfd_wrapper (); if (val < 0) err_disabled_feature ("F_DUPFD", "F_DUPFD"); return const_value (args, val); } DEFUNX ("F_GETFD", FF_GETFD, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{v} =} F_GETFD () Return the numerical value to pass to @code{fcntl} to return the file descriptor flags. @seealso{fcntl, F_DUPFD, F_GETFL, F_SETFD, F_SETFL} @end deftypefn */) { static int val = octave_f_getfd_wrapper (); if (val < 0) err_disabled_feature ("F_GETFD", "F_GETFD"); return const_value (args, val); } DEFUNX ("F_GETFL", FF_GETFL, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{v} =} F_GETFL () Return the numerical value to pass to @code{fcntl} to return the file status flags. @seealso{fcntl, F_DUPFD, F_GETFD, F_SETFD, F_SETFL} @end deftypefn */) { static int val = octave_f_getfl_wrapper (); if (val < 0) err_disabled_feature ("F_GETFL", "F_GETFL"); return const_value (args, val); } DEFUNX ("F_SETFD", FF_SETFD, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{v} =} F_SETFD () Return the numerical value to pass to @code{fcntl} to set the file descriptor flags. @seealso{fcntl, F_DUPFD, F_GETFD, F_GETFL, F_SETFL} @end deftypefn */) { static int val = octave_f_setfd_wrapper (); if (val < 0) err_disabled_feature ("F_SETFD", "F_SETFD"); return const_value (args, val); } DEFUNX ("F_SETFL", FF_SETFL, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{v} =} F_SETFL () Return the numerical value to pass to @code{fcntl} to set the file status flags. @seealso{fcntl, F_DUPFD, F_GETFD, F_GETFL, F_SETFD} @end deftypefn */) { static int val = octave_f_setfl_wrapper (); if (val < 0) err_disabled_feature ("F_SETFL", "F_SETFL"); return const_value (args, val); } DEFUNX ("O_APPEND", FO_APPEND, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{v} =} O_APPEND () Return the numerical value of the @code{O_APPEND} macro. @code{O_APPEND} is file status flag that may be returned by @code{fcntl} to indicate each write operation appends, or that may be passed to @code{fcntl} to set the write mode to append. @seealso{fcntl, O_ASYNC, O_CREAT, O_EXCL, O_NONBLOCK, O_RDONLY, O_RDWR, O_SYNC, O_TRUNC, O_WRONLY} @end deftypefn */) { static int val = octave_o_append_wrapper (); if (val < 0) err_disabled_feature ("O_APPEND", "O_APPEND"); return const_value (args, val); } DEFUNX ("O_ASYNC", FO_ASYNC, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{v} =} O_ASYNC () Return the numerical value of the @code{O_ASYNC} macro. @code{O_ASYNC} is the file status flag that may be returned by @code{fcntl} to indicate asynchronous I/O. @seealso{fcntl, O_APPEND, O_CREAT, O_EXCL, O_NONBLOCK, O_RDONLY, O_RDWR, O_SYNC, O_TRUNC, O_WRONLY} @end deftypefn */) { static int val = octave_o_async_wrapper (); if (val < 0) err_disabled_feature ("O_ASYNC", "O_ASYNC"); return const_value (args, val); } DEFUNX ("O_CREAT", FO_CREAT, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{v} =} O_CREAT () Return the numerical value of the @code{O_CREAT}. @code{O_CREAT} is the file status flag that may be returned by @code{fcntl} to indicate that a file should be created if it does not exist. @seealso{fcntl, O_APPEND, O_ASYNC, O_EXCL, O_NONBLOCK, O_RDONLY, O_RDWR, O_SYNC, O_TRUNC, O_WRONLY} @end deftypefn */) { static int val = octave_o_creat_wrapper (); if (val < 0) err_disabled_feature ("O_CREAT", "O_CREAT"); return const_value (args, val); } DEFUNX ("O_EXCL", FO_EXCL, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{v} =} O_EXCL () Return the numerical value of the @code{O_EXCL}. @code{O_EXCL} is the file status flag that may be returned by @code{fcntl} to indicate that file locking is used. @seealso{fcntl, O_APPEND, O_ASYNC, O_CREAT, O_NONBLOCK, O_RDONLY, O_RDWR, O_SYNC, O_TRUNC, O_WRONLY} @end deftypefn */) { static int val = octave_o_excl_wrapper (); if (val < 0) err_disabled_feature ("O_EXCL", "O_EXCL"); return const_value (args, val); } DEFUNX ("O_NONBLOCK", FO_NONBLOCK, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{v} =} O_NONBLOCK () Return the numerical value of the @code{O_NONBLOCK}. @code{O_NONBLOCK} is the file status flag that may be returned by @code{fcntl} to indicate that non-blocking I/O is in use, or that may be passsed to @code{fcntl} to set non-blocking I/O. @seealso{fcntl, O_APPEND, O_ASYNC, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_SYNC, O_TRUNC, O_WRONLY} @end deftypefn */) { static int val = octave_o_nonblock_wrapper (); if (val < 0) err_disabled_feature ("O_NONBLOCK", "O_NONBLOCK"); return const_value (args, val); } DEFUNX ("O_RDONLY", FO_RDONLY, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{v} =} O_RDONLY () Return the numerical value of the @code{O_RDONLY}. @code{O_RDONLY} is the file status flag that may be returned by @code{fcntl} to indicate that a file is open for reading only. @seealso{fcntl, O_APPEND, O_ASYNC, O_CREAT, O_EXCL, O_NONBLOCK, O_RDWR, O_SYNC, O_TRUNC, O_WRONLY} @end deftypefn */) { static int val = octave_o_rdonly_wrapper (); if (val < 0) err_disabled_feature ("O_RDONLY", "O_RDONLY"); return const_value (args, val); } DEFUNX ("O_RDWR", FO_RDWR, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{v} =} O_RDWR () Return the numerical value of the @code{O_RDWR}. @code{O_RDWR} is the file status flag that may be returned by @code{fcntl} to indicate that a file is open for both reading and writing. @seealso{fcntl, O_APPEND, O_ASYNC, O_CREAT, O_EXCL, O_NONBLOCK, O_RDONLY, O_SYNC, O_TRUNC, O_WRONLY} @end deftypefn */) { static int val = octave_o_rdwr_wrapper (); if (val < 0) err_disabled_feature ("O_RDWR", "O_RDWR"); return const_value (args, val); } DEFUNX ("O_SYNC", FO_SYNC, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{v} =} O_SYNC () Return the numerical value of the @code{O_SYNC}. @code{O_SYNC} is the file status flag that may be returned by @code{fcntl} to indicate that a file is open for synchronous I/O @seealso{fcntl, O_APPEND, O_ASYNC, O_CREAT, O_EXCL, O_NONBLOCK, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY} @end deftypefn */) { static int val = octave_o_sync_wrapper (); if (val < 0) err_disabled_feature ("O_SYNC", "O_SYNC"); return const_value (args, val); } DEFUNX ("O_TRUNC", FO_TRUNC, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{v} =} O_TRUNC () Return the numerical value of the @code{O_TRUNC}. @code{O_TRUNC} is the file status flag that may be returned by @code{fcntl} to indicate that if file exists, it should be truncated when writing. @seealso{fcntl, O_APPEND, O_ASYNC, O_CREAT, O_EXCL, O_NONBLOCK, O_RDONLY, O_RDWR, O_SYNC, O_WRONLY} @end deftypefn */) { static int val = octave_o_trunc_wrapper (); if (val < 0) err_disabled_feature ("O_TRUNC", "O_TRUNC"); return const_value (args, val); } DEFUNX ("O_WRONLY", FO_WRONLY, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{v} =} O_WRONLY () Return the numerical value of the @code{O_WRONLY}. @code{O_WRONLY} is the file status flag that may be returned by @code{fcntl} to indicate that a file is open for writing only @seealso{fcntl, O_APPEND, O_ASYNC, O_CREAT, O_EXCL, O_NONBLOCK, O_RDONLY, O_RDWR, O_SYNC, O_TRUNC} @end deftypefn */) { static int val = octave_o_wronly_wrapper (); if (val < 0) err_disabled_feature ("O_WRONLY", "O_WRONLY"); return const_value (args, val); } DEFUNX ("WNOHANG", FWNOHANG, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{v} =} WNOHANG () Return the numerical value of the @code{WNOHANG} macro. @code{WNOHANG} is the option argument that may be passed to @code{waitpid} to indicate that it should return its status immediately instead of waiting for a process to exit. @seealso{waitpid, WUNTRACED, WCONTINUE} @end deftypefn */) { return const_value (args, sys::wnohang ()); } DEFUNX ("WUNTRACED", FWUNTRACED, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{v} =} WUNTRACED () Return the numerical value of the @code{WUNTRACED} macro. @code{WUNTRACED} is the option argument that may be passed to @code{waitpid} to indicate that it should also return if the child process has stopped but is not traced via the @code{ptrace} system call @seealso{waitpid, WNOHANG, WCONTINUE} @end deftypefn */) { return const_value (args, sys::wuntraced ()); } DEFUNX ("WCONTINUE", FWCONTINUE, args, , doc: /* -*- texinfo -*- @deftypefn {} {@var{v} =} WCONTINUE () Return the numerical value of the @code{WCONTINUE} macro. @code{WCONTINUE} is the option argument that may be passed to @code{waitpid} to indicate that it should also return if a stopped child has been resumed by delivery of a @code{SIGCONT} signal. @seealso{waitpid, WNOHANG, WUNTRACED} @end deftypefn */) { return const_value (args, sys::wcontinue ()); } OCTAVE_NAMESPACE_END