GNU Octave  8.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
main.in.cc
Go to the documentation of this file.
1 // %NO_EDIT_WARNING%
2 
3 ////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2012-2023 The Octave Project Developers
6 //
7 // See the file COPYRIGHT.md in the top-level directory of this
8 // distribution or <https://octave.org/copyright/>.
9 //
10 // This file is part of Octave.
11 //
12 // Octave is free software: you can redistribute it and/or modify it
13 // under the terms of the GNU General Public License as published by
14 // the Free Software Foundation, either version 3 of the License, or
15 // (at your option) any later version.
16 //
17 // Octave is distributed in the hope that it will be useful, but
18 // WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with Octave; see the file COPYING. If not, see
24 // <https://www.gnu.org/licenses/>.
25 //
26 ////////////////////////////////////////////////////////////////////////
27 
28 // NOTE: This program is supposed to be a small wrapper that exists
29 // primarily to give up the controlling TTY and then exec Octave with
30 // its GUI. It may also execute Octave without the GUI or the command
31 // line version of Octave that is not linked with GUI libraries. So
32 // that it remains small, it should NOT depend on or be linked with
33 // liboctave or libinterp.
34 
35 #if defined (HAVE_CONFIG_H)
36 # include "config.h"
37 #endif
38 
39 #include <cstdlib>
40 #include <cstring>
41 
42 #include <algorithm>
43 #include <iostream>
44 #include <string>
45 
46 #if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE)
47 # include <vector>
48 # include <locale>
49 # include <codecvt>
50 #endif
51 
52 // We are linking against static libs so do not decorate with dllimport.
53 // FIXME: This should be done by the build system.
54 #undef OCTAVE_API
55 #define OCTAVE_API
56 #include "fcntl-wrappers.h"
57 #include "getopt-wrapper.h"
58 #include "signal-wrappers.h"
59 #include "unistd-wrappers.h"
60 #include "wait-wrappers.h"
61 
62 #if ! defined (OCTAVE_VERSION)
63 # define OCTAVE_VERSION %OCTAVE_VERSION%
64 #endif
65 
66 #if ! defined (OCTAVE_ARCHLIBDIR)
67 # define OCTAVE_ARCHLIBDIR %OCTAVE_ARCHLIBDIR%
68 #endif
69 
70 #if ! defined (OCTAVE_BINDIR)
71 # define OCTAVE_BINDIR %OCTAVE_BINDIR%
72 #endif
73 
74 #if ! defined (OCTAVE_PREFIX)
75 # define OCTAVE_PREFIX %OCTAVE_PREFIX%
76 #endif
77 
78 #if ! defined (OCTAVE_EXEC_PREFIX)
79 # define OCTAVE_EXEC_PREFIX %OCTAVE_EXEC_PREFIX%
80 #endif
81 
82 #include "display-available.h"
83 #include "options.h"
84 #include "shared-fcns.h"
85 
86 #if defined (HAVE_OCTAVE_QT_GUI) && ! defined (OCTAVE_USE_WINDOWS_API)
87 static bool fork_and_exec = true;
88 #else
89 static bool fork_and_exec = false;
90 #endif
91 
92 // If we fork and exec, we'll need the following signal handling code to
93 // forward signals to the GUI process.
94 
95 static pid_t gui_pid = 0;
96 
97 static int caught_signal = -1;
98 
99 static void
101 {
102  if (gui_pid > 0)
103  caught_signal = sig;
104 }
105 
106 static void
107 gui_driver_set_signal_handler (const char *signame,
108  octave_sig_handler *handler)
109 {
110  octave_set_signal_handler_by_name (signame, handler, false);
111 }
112 
113 static void
115 {
116  // FIXME: do we need to handle and forward all the signals that Octave
117  // handles, or is it sufficient to only forward things like SIGINT,
118  // SIGBREAK, SIGABRT, SIGQUIT, and possibly a few others?
119 
125 
126  // SIGCHLD
127  // SIGCLD
128  // SIGCONT
129 
134 
135  // SIGINFO
136  // SIGINT
137 
142 
143  // SIGPROF
144  // SIGPWR
145 
148 
149  // SIGSTOP
150 
154 
155  // SIGTSTP
156  // SIGTTIN
157  // SIGTTOU
158  // SIGURG
159 
164 
165  // SIGWINCH
166 
169 }
170 
171 static std::string
173 {
174  // Accept value from the environment literally, but substitute
175  // OCTAVE_HOME in the configuration value OCTAVE_BINDIR in case Octave
176  // has been relocated to some installation directory other than the
177  // one originally configured.
178 
179  std::string obd = octave_getenv ("OCTAVE_BINDIR");
180 
181  return obd.empty () ? prepend_octave_exec_home (std::string (OCTAVE_BINDIR))
182  : obd;
183 }
184 
185 static std::string
187 {
188  // Accept value from the environment literally, but substitute
189  // OCTAVE_HOME in the configuration value OCTAVE_ARCHLIBDIR in case
190  // Octave has been relocated to some installation directory other than
191  // the one originally configured.
192 
193  std::string dir = octave_getenv ("OCTAVE_ARCHLIBDIR");
194 
195  return dir.empty () ? prepend_octave_exec_home (std::string (OCTAVE_ARCHLIBDIR))
196  : dir;
197 }
198 
199 static int
200 octave_exec (const std::string& file, char **argv)
201 {
202  int status = octave_execv_wrapper (file.c_str (), argv);
203 
204 #if defined (OCTAVE_USE_WINDOWS_API)
205  // The above wrapper uses spawn(P_WAIT,...) instead of exec on Windows.
206  if (status == -1)
207 #endif
208  std::cerr << argv[0] << ": failed to exec '" << file << "'" << std::endl;
209 
210  return status;
211 }
212 
213 static char *
214 strsave (const char *s)
215 {
216  if (! s)
217  return nullptr;
218 
219  int len = strlen (s);
220  char *tmp = new char [len+1];
221  tmp = strcpy (tmp, s);
222  return tmp;
223 }
224 
225 #if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE)
226 extern "C"
227 int
228 wmain (int argc, wchar_t **wargv)
229 {
230  static char **argv = new char * [argc + 1];
231  std::vector<std::string> argv_str;
232 
233  // convert wide character strings to multibyte UTF-8 strings
234  std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wchar_conv;
235  for (int i_arg = 0; i_arg < argc; i_arg++)
236  argv_str.push_back (wchar_conv.to_bytes (wargv[i_arg]));
237 
238  // Get pointers to C strings not before vector is stable.
239  for (int i_arg = 0; i_arg < argc; i_arg++)
240  argv[i_arg] = &argv_str[i_arg][0];
241  argv[argc] = nullptr;
242 
243 #else
244 int
245 main (int argc, char **argv)
246 {
247 #endif
248  int retval = 0;
249 
250  int idx_gui = -1;
251  bool server = false;
252  bool start_gui = false;
253  bool gui_libs = true;
254 
255  bool eval_code = false;
256  bool persist_octave = false;
257 
258  set_octave_home ();
259 
260  std::string octave_bindir = get_octave_bindir ();
261  std::string octave_archlibdir = get_octave_archlibdir ();
262  std::string octave_cli
263  = octave_bindir + dir_sep_char + "octave-cli-" OCTAVE_VERSION;
264  std::string octave_gui = octave_archlibdir + dir_sep_char + "octave-gui";
265 
266 #if defined (HAVE_OCTAVE_QT_GUI)
267  // The Octave version number is already embedded in the
268  // octave_archlibdir directory name so we don't need to append it to
269  // the octave-gui filename.
270 
271  std::string file = octave_gui;
272 #else
273  std::string file = octave_cli;
274 #endif
275 
276  // Declaring new_argv static avoids leak warnings when using GCC's
277  // --address-sanitizer option.
278  static char **new_argv = new char * [argc + 2];
279 
280  int next_optind = 1;
281  int k = 1;
282 
283  bool warn_display = true;
284  bool no_display = false;
285 
286  // Disable error reporting in getopt. We want to silently recognize
287  // and process a few special arguments here and pass everything on to
288  // the real Octave program where incorrect usage errors may be
289  // reported.
290 
292 
293  while (true)
294  {
295  int long_idx;
296 
297  int optc = octave_getopt_long_wrapper (argc, argv, short_opts, long_opts,
298  &long_idx);
299  int old_optind = next_optind;
300  next_optind = octave_optind_wrapper ();
301 
302  if (optc < 0)
303  break;
304 
305  switch (optc)
306  {
307  case NO_GUI_LIBS_OPTION:
308  // Run the version of Octave that is not linked with any GUI
309  // libraries. It may not be possible to do plotting or any ui*
310  // calls, but it will be a little faster to start and require less
311  // memory. Don't pass the --no-gui-libs option on as that option
312  // is not recognized by Octave.
313  gui_libs = false;
314  file = octave_cli;
315  break;
316 
317  case NO_GUI_OPTION:
318  // If we see this option, then we can just exec octave; we don't
319  // have to create a child process and wait for it to exit. But do
320  // exec "octave-gui", not "octave-cli", because even if the
321  // --no-gui option is given, we may be asked to do some plotting or
322  // ui* calls.
323  start_gui = false;
324  new_argv[k++] = argv[old_optind];
325  break;
326 
327  case GUI_OPTION:
328  // If we see this option, then we fork and exec octave with the
329  // --gui option, while continuing to handle signals in the
330  // terminal.
331  // Do not copy the arg now, since we still not know if the gui
332  // should really be launched. Just store the index.
333  start_gui = true;
334  idx_gui = old_optind;
335  break;
336 
338  // If we see this option, then we don't fork and exec.
339  fork_and_exec = false;
340  new_argv[k++] = argv[old_optind];
341  break;
342 
343  case PERSIST_OPTION:
344  // FIXME: How can we reliably detect if this option appears after
345  // a FILE argument. In this case octave ignores the option,
346  // but the GUI might still be launched if --gui is also
347  // given.
348  persist_octave = true;
349  new_argv[k++] = argv[old_optind];
350  break;
351 
352  case SERVER_OPTION:
353  server = true;
354  new_argv[k++] = argv[old_optind];
355  break;
356 
357  case EVAL_OPTION:
358  eval_code = true;
359  for (int i = old_optind; i < next_optind; i++)
360  new_argv[k++] = argv[i];
361  break;
362 
363  case 'q':
364  // options "--silent" or "--quiet"
365  warn_display = false;
366  new_argv[k++] = argv[old_optind];
367  break;
368 
369  case 'W':
370  // option "--no-window-system"
371  no_display = true;
372  new_argv[k++] = argv[old_optind];
373  break;
374 
375  default:
376  for (int i = old_optind; i < next_optind; i++)
377  new_argv[k++] = argv[i];
378  break;
379  }
380  }
381 
382  // Treat trailing arguments as commands to be executed
383  if (next_optind < argc)
384  {
385  eval_code = true;
386  for (int i = next_optind; i < argc; i++)
387  new_argv[k++] = argv[i];
388  }
389 
390  if (start_gui && eval_code && ! persist_octave)
391  start_gui = false;
392 
393  // At this point, we definitely know whether the gui has to
394  // be launched or not.
395  // gui_libs and start_gui are just about options, not
396  // the environment. Exit if they don't make sense.
397  if (start_gui)
398  {
399  // GUI should be started
400  if (! gui_libs)
401  {
402  std::cerr << "octave: conflicting options: --no-gui-libs and --gui"
403  << std::endl;
404  return 1;
405  }
406 
407  if (server)
408  {
409  std::cerr << "octave: conflicting options: --server and --gui"
410  << std::endl;
411  return 1;
412  }
413 
414 #if ! defined (HAVE_OCTAVE_QT_GUI)
415  std::cerr << "octave: GUI features missing or disabled in this build"
416  << std::endl;
417  return 1;
418 #endif
419 
420  // Finally, add --gui to the command line options. We can not
421  // just append it since options after a given file are ignored.
422  for (int j = k; j > 1; j--)
423  new_argv[j] = new_argv[j-1];
424 
425  new_argv[1] = argv[idx_gui];
426  k++;
427  }
428 
429  new_argv[k] = nullptr;
430 
431  if (no_display)
432  {
433  start_gui = false;
434  gui_libs = false;
435 
436  file = octave_cli;
437  }
438  else if (gui_libs || start_gui)
439  {
440  int dpy_avail;
441 
442  const char *display_check_err_msg = display_available (&dpy_avail);
443 
444  if (! dpy_avail)
445  {
446  start_gui = false;
447  gui_libs = false;
448 
449  file = octave_cli;
450 
451  if (warn_display)
452  {
453  if (! display_check_err_msg)
454  display_check_err_msg = "graphical display unavailable";
455 
456  std::cerr << "octave: " << display_check_err_msg << std::endl;
457  std::cerr << "octave: disabling GUI features" << std::endl;
458  }
459  }
460  }
461 
462 #if defined (OCTAVE_USE_WINDOWS_API)
463  file += ".exe";
464 #endif
465 
466  new_argv[0] = strsave (file.c_str ());
467 
468  // The Octave interpreter may be multithreaded. If so, we attempt to
469  // ensure that signals are delivered to the main interpreter thread
470  // and no others by blocking signals before we exec the Octave
471  // interpreter executable. When that process starts, it will unblock
472  // signals in the main interpreter thread. When running the GUI as a
473  // subprocess, we also unblock signals that the parent process handles
474  // so we can forward them to the child.
475 
477  octave_block_signal_by_name ("SIGTSTP");
478 
479  if (fork_and_exec && gui_libs && start_gui)
480  {
481  // Fork and exec when starting the GUI so that we will call
482  // setsid to give up the controlling terminal (if any) and so that
483  // the GUI process will be in a separate process group.
484  //
485  // The GUI process must be in a separate process group so that we
486  // can send an interrupt signal to all child processes when
487  // interrupting the interpreter. See also bug #49609 and the
488  // function pthread_thread_manager::interrupt in the file
489  // libgui/src/thread-manager.cc.
490 
492 
493  if (gui_pid < 0)
494  {
495  std::cerr << "octave: fork failed!" << std::endl;
496 
497  retval = 1;
498  }
499  else if (gui_pid == 0)
500  {
501  // Child.
502 
503  if (octave_setsid_wrapper () < 0)
504  {
505  std::cerr << "octave: error calling setsid!" << std::endl;
506 
507  retval = 1;
508  }
509  else
510  retval = octave_exec (file, new_argv);
511  }
512  else
513  {
514  // Parent. Forward signals to child while waiting for it to exit.
515 
517 
519  octave_unblock_signal_by_name ("SIGTSTP");
520 
521  int status;
522 
523  while (true)
524  {
525  octave_waitpid_wrapper (gui_pid, &status, 0);
526 
527  if (caught_signal > 0)
528  {
529  int sig = caught_signal;
530 
531  caught_signal = -1;
532 
534  }
535  else if (octave_wifexited_wrapper (status))
536  {
537  retval = octave_wexitstatus_wrapper (status);
538  break;
539  }
540  else if (octave_wifsignaled_wrapper (status))
541  {
542  std::cerr << "octave exited with signal "
543  << octave_wtermsig_wrapper (status) << std::endl;
544  break;
545  }
546  }
547  }
548  }
549  else
550  {
551  retval = octave_exec (file, new_argv);
552 
553  if (retval < 0)
554  std::cerr << argv[0] << ": " << std::strerror (errno) << std::endl;
555  }
556 
557 
558  return retval;
559 }
void octave_unblock_async_signals(void)
void octave_block_async_signals(void)
const char * display_available(int *dpy_avail)
int octave_getopt_long_wrapper(int argc, char **argv, const char *shortopts, const struct octave_getopt_options *longopts, int *longind)
int octave_optind_wrapper(void)
int octave_set_opterr_wrapper(int val)
#define OCTAVE_BINDIR
Definition: main.in.cc:71
static pid_t gui_pid
Definition: main.in.cc:95
#define OCTAVE_ARCHLIBDIR
Definition: main.in.cc:67
static bool fork_and_exec
Definition: main.in.cc:89
static void gui_driver_set_signal_handler(const char *signame, octave_sig_handler *handler)
Definition: main.in.cc:107
static char * strsave(const char *s)
Definition: main.in.cc:214
static void gui_driver_sig_handler(int sig)
Definition: main.in.cc:100
static std::string get_octave_archlibdir(void)
Definition: main.in.cc:186
int main(int argc, char **argv)
Definition: main.in.cc:245
#define OCTAVE_VERSION
Definition: main.in.cc:63
static void install_signal_handlers(void)
Definition: main.in.cc:114
static int caught_signal
Definition: main.in.cc:97
static int octave_exec(const std::string &file, char **argv)
Definition: main.in.cc:200
static std::string get_octave_bindir(void)
Definition: main.in.cc:172
T::size_type strlen(const typename T::value_type *str)
Definition: oct-string.cc:85
#define NO_GUI_OPTION
Definition: options.h:50
static const char * short_opts
Definition: options.h:36
#define NO_GUI_LIBS_OPTION
Definition: options.h:51
#define SERVER_OPTION
Definition: options.h:57
#define GUI_OPTION
Definition: options.h:45
#define EXPERIMENTAL_TERMINAL_WIDGET_OPTION
Definition: options.h:44
struct octave_getopt_options long_opts[]
Definition: options.h:60
#define PERSIST_OPTION
Definition: options.h:56
#define EVAL_OPTION
Definition: options.h:42
static void set_octave_home(void)
Definition: shared-fcns.h:111
static std::string prepend_octave_exec_home(const std::string &s)
Definition: shared-fcns.h:195
static const char dir_sep_char
Definition: shared-fcns.h:90
static std::string octave_getenv(const std::string &name)
Definition: shared-fcns.h:100
void octave_block_signal_by_name(const char *signame)
void octave_unblock_signal_by_name(const char *signame)
int octave_kill_wrapper(pid_t pid, int signum)
octave_sig_handler * octave_set_signal_handler_by_name(const char *signame, octave_sig_handler *handler, bool restart_syscalls)
void octave_sig_handler(int)
pid_t octave_setsid_wrapper(void)
pid_t octave_fork_wrapper(void)
int octave_execv_wrapper(const char *file, char *const *argv)
pid_t octave_waitpid_wrapper(pid_t pid, int *statusp, int options)
Definition: wait-wrappers.c:61
bool octave_wifsignaled_wrapper(int status)
int octave_wexitstatus_wrapper(int status)
bool octave_wifexited_wrapper(int status)
int octave_wtermsig_wrapper(int status)
F77_RET_T len
Definition: xerbla.cc:61