GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
main.in.cc
Go to the documentation of this file.
1 // %NO_EDIT_WARNING%
2 
3 ////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2012-2021 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 #include "fcntl-wrappers.h"
47 #include "signal-wrappers.h"
48 #include "unistd-wrappers.h"
49 #include "wait-wrappers.h"
50 
51 #if ! defined (OCTAVE_VERSION)
52 # define OCTAVE_VERSION %OCTAVE_VERSION%
53 #endif
54 
55 #if ! defined (OCTAVE_ARCHLIBDIR)
56 # define OCTAVE_ARCHLIBDIR %OCTAVE_ARCHLIBDIR%
57 #endif
58 
59 #if ! defined (OCTAVE_BINDIR)
60 # define OCTAVE_BINDIR %OCTAVE_BINDIR%
61 #endif
62 
63 #if ! defined (OCTAVE_PREFIX)
64 # define OCTAVE_PREFIX %OCTAVE_PREFIX%
65 #endif
66 
67 #if ! defined (OCTAVE_EXEC_PREFIX)
68 # define OCTAVE_EXEC_PREFIX %OCTAVE_EXEC_PREFIX%
69 #endif
70 
71 #include "display-available.h"
72 #include "shared-fcns.h"
73 
74 #if defined (HAVE_OCTAVE_QT_GUI) && ! defined (OCTAVE_USE_WINDOWS_API)
75 
76 // Forward signals to the GUI process.
77 
78 static pid_t gui_pid = 0;
79 
80 static int caught_signal = -1;
81 
82 static void
83 gui_driver_sig_handler (int sig)
84 {
85  if (gui_pid > 0)
86  caught_signal = sig;
87 }
88 
89 static void
90 gui_driver_set_signal_handler (const char *signame,
91  octave_sig_handler *handler)
92 {
93  octave_set_signal_handler_by_name (signame, handler, false);
94 }
95 
96 static void
98 {
99  // FIXME: do we need to handle and forward all the signals that Octave
100  // handles, or is it sufficient to only forward things like SIGINT,
101  // SIGBREAK, SIGABRT, SIGQUIT, and possibly a few others?
102 
103  gui_driver_set_signal_handler ("SIGINT", gui_driver_sig_handler);
104  gui_driver_set_signal_handler ("SIGBREAK", gui_driver_sig_handler);
105  gui_driver_set_signal_handler ("SIGABRT", gui_driver_sig_handler);
106  gui_driver_set_signal_handler ("SIGALRM", gui_driver_sig_handler);
107  gui_driver_set_signal_handler ("SIGBUS", gui_driver_sig_handler);
108 
109  // SIGCHLD
110  // SIGCLD
111  // SIGCONT
112 
113  gui_driver_set_signal_handler ("SIGEMT", gui_driver_sig_handler);
114  gui_driver_set_signal_handler ("SIGFPE", gui_driver_sig_handler);
115  gui_driver_set_signal_handler ("SIGHUP", gui_driver_sig_handler);
116  gui_driver_set_signal_handler ("SIGILL", gui_driver_sig_handler);
117 
118  // SIGINFO
119  // SIGINT
120 
121  gui_driver_set_signal_handler ("SIGIOT", gui_driver_sig_handler);
122  gui_driver_set_signal_handler ("SIGLOST", gui_driver_sig_handler);
123  gui_driver_set_signal_handler ("SIGPIPE", gui_driver_sig_handler);
124  gui_driver_set_signal_handler ("SIGPOLL", gui_driver_sig_handler);
125 
126  // SIGPROF
127  // SIGPWR
128 
129  gui_driver_set_signal_handler ("SIGQUIT", gui_driver_sig_handler);
130  gui_driver_set_signal_handler ("SIGSEGV", gui_driver_sig_handler);
131 
132  // SIGSTOP
133 
134  gui_driver_set_signal_handler ("SIGSYS", gui_driver_sig_handler);
135  gui_driver_set_signal_handler ("SIGTERM", gui_driver_sig_handler);
136  gui_driver_set_signal_handler ("SIGTRAP", gui_driver_sig_handler);
137 
138  // SIGTSTP
139  // SIGTTIN
140  // SIGTTOU
141  // SIGURG
142 
143  gui_driver_set_signal_handler ("SIGUSR1", gui_driver_sig_handler);
144  gui_driver_set_signal_handler ("SIGUSR2", gui_driver_sig_handler);
145  gui_driver_set_signal_handler ("SIGVTALRM", gui_driver_sig_handler);
146  gui_driver_set_signal_handler ("SIGIO", gui_driver_sig_handler);
147 
148  // SIGWINCH
149 
150  gui_driver_set_signal_handler ("SIGXCPU", gui_driver_sig_handler);
151  gui_driver_set_signal_handler ("SIGXFSZ", gui_driver_sig_handler);
152 }
153 
154 #endif
155 
156 static std::string
158 {
159  // Accept value from the environment literally, but substitute
160  // OCTAVE_HOME in the configuration value OCTAVE_BINDIR in case Octave
161  // has been relocated to some installation directory other than the
162  // one originally configured.
163 
164  std::string obd = octave_getenv ("OCTAVE_BINDIR");
165 
166  return obd.empty () ? prepend_octave_exec_home (std::string (OCTAVE_BINDIR))
167  : obd;
168 }
169 
170 static std::string
172 {
173  // Accept value from the environment literally, but substitute
174  // OCTAVE_HOME in the configuration value OCTAVE_ARCHLIBDIR in case
175  // Octave has been relocated to some installation directory other than
176  // the one originally configured.
177 
178  std::string dir = octave_getenv ("OCTAVE_ARCHLIBDIR");
179 
180  return dir.empty () ? prepend_octave_exec_home (std::string (OCTAVE_ARCHLIBDIR))
181  : dir;
182 }
183 
184 static int
185 octave_exec (const std::string& file, char **argv)
186 {
187  int status = octave_execv_wrapper (file.c_str (), argv);
188 
189  std::cerr << argv[0] << ": failed to exec '" << file << "'" << std::endl;
190 
191  return status;
192 }
193 
194 static char *
195 strsave (const char *s)
196 {
197  if (! s)
198  return nullptr;
199 
200  int len = strlen (s);
201  char *tmp = new char [len+1];
202  tmp = strcpy (tmp, s);
203  return tmp;
204 }
205 
206 int
207 main (int argc, char **argv)
208 {
209  int retval = 0;
210 
211  int idx_gui = -1;
212  bool start_gui = false;
213  bool gui_libs = true;
214 
215  bool eval_code = false;
216  bool persist_octave = false;
217 
218  set_octave_home ();
219 
220  std::string octave_bindir = get_octave_bindir ();
221  std::string octave_archlibdir = get_octave_archlibdir ();
222  std::string octave_cli
223  = octave_bindir + dir_sep_char + "octave-cli-" OCTAVE_VERSION;
224  std::string octave_gui = octave_archlibdir + dir_sep_char + "octave-gui";
225 
226 #if defined (HAVE_OCTAVE_QT_GUI)
227  // The Octave version number is already embedded in the
228  // octave_archlibdir directory name so we don't need to append it to
229  // the octave-gui filename.
230 
231  std::string file = octave_gui;
232 #else
233  std::string file = octave_cli;
234 #endif
235 
236  // Declaring new_argv static avoids leak warnings when using GCC's
237  // --address-sanitizer option.
238  static char **new_argv = new char * [argc + 2];
239 
240  int k = 1;
241 
242  bool warn_display = true;
243  bool no_display = false;
244 
245  for (int i = 1; i < argc; i++)
246  {
247  if (! strcmp (argv[i], "--no-gui-libs"))
248  {
249  // Run the version of Octave that is not linked with any GUI
250  // libraries. It may not be possible to do plotting or any
251  // ui* calls, but it will be a little faster to start and
252  // require less memory. Don't pass the --no-gui-libs option
253  // on as that option is not recognized by Octave.
254 
255  gui_libs = false;
256  file = octave_cli;
257  }
258  else if (! strcmp (argv[i], "--no-gui"))
259  {
260  // If we see this option, then we can just exec octave; we
261  // don't have to create a child process and wait for it to
262  // exit. But do exec "octave-gui", not "octave-cli", because
263  // even if the --no-gui option is given, we may be asked to do
264  // some plotting or ui* calls.
265 
266  start_gui = false;
267  new_argv[k++] = argv[i];
268  }
269  else if (! strcmp (argv[i], "--gui") || ! strcmp (argv[i], "--force-gui"))
270  {
271  // If we see this option, then we fork and exec octave with
272  // the --gui option, while continuing to handle signals in the
273  // terminal.
274  // Do not copy the arg now, since we still not know if the
275  // gui should really be launched. Just store the index.
276 
277  start_gui = true;
278  idx_gui = i;
279  }
280  else if (! strcmp (argv[i], "--persist"))
281  {
282  // FIXME: How can we reliably detect if this option appears
283  // after a FILE argument. In this case octave ignores
284  // the option, but the GUI might still be launched if
285  // --gui is also given.
286 
287  persist_octave = true;
288  new_argv[k++] = argv[i];
289  }
290  else if (! strcmp (argv[i], "--eval") ||
291  (strlen (argv[i]) > 0 && argv[i][0] != '-'))
292  {
293  eval_code = true;
294  new_argv[k++] = argv[i];
295  }
296  else if (! strcmp (argv[i], "--silent") || ! strcmp (argv[i], "--quiet"))
297  {
298  warn_display = false;
299  new_argv[k++] = argv[i];
300  }
301  else if (! strcmp (argv[i], "--no-window-system"))
302  {
303  no_display = true;
304  new_argv[k++] = argv[i];
305  }
306  else if (strlen (argv[i]) > 1 && argv[i][0] == '-' && argv[i][1] != '-')
307  {
308  // Handle all single-letter command line options here; they may
309  // occur alone or may be aggregated into a single argument.
310 
311  size_t len = strlen (argv[i]);
312 
313  for (size_t j = 1; j < len; j++)
314  switch (argv[i][j])
315  {
316  case 'W':
317  no_display = true;
318  break;
319  case 'q':
320  warn_display = false;
321  break;
322  default:
323  break;
324  }
325 
326  new_argv[k++] = argv[i];
327  }
328  else
329  new_argv[k++] = argv[i];
330  }
331 
332  if (start_gui && eval_code && ! persist_octave)
333  start_gui = false;
334 
335  // At this point, we definitely know whether the gui has to
336  // be launched or not.
337  // gui_libs and start_gui are just about options, not
338  // the environment. Exit if they don't make sense.
339  if (start_gui)
340  {
341  // GUI should be started
342  if (! gui_libs)
343  {
344  std::cerr << "octave: conflicting options: --no-gui-libs and --gui"
345  << std::endl;
346  return 1;
347  }
348 
349 #if ! defined (HAVE_OCTAVE_QT_GUI)
350  std::cerr << "octave: GUI features missing or disabled in this build"
351  << std::endl;
352  return 1;
353 #endif
354 
355  // Finally, add --gui to the command line options. We can not
356  // just append it since options after a given file are ignored.
357  for (int j = k; j > 1; j--)
358  new_argv[j] = new_argv[j-1];
359 
360  new_argv[1] = argv[idx_gui];
361  k++;
362  }
363 
364  new_argv[k] = nullptr;
365 
366  if (no_display)
367  {
368  start_gui = false;
369  gui_libs = false;
370 
371  file = octave_cli;
372  }
373  else if (gui_libs || start_gui)
374  {
375  int dpy_avail;
376 
377  const char *display_check_err_msg = display_available (&dpy_avail);
378 
379  if (! dpy_avail)
380  {
381  start_gui = false;
382  gui_libs = false;
383 
384  file = octave_cli;
385 
386  if (warn_display)
387  {
388  if (! display_check_err_msg)
389  display_check_err_msg = "graphical display unavailable";
390 
391  std::cerr << "octave: " << display_check_err_msg << std::endl;
392  std::cerr << "octave: disabling GUI features" << std::endl;
393  }
394  }
395  }
396 
397 #if defined (OCTAVE_USE_WINDOWS_API)
398  file += ".exe";
399 #endif
400 
401  new_argv[0] = strsave (file.c_str ());
402 
403  // The Octave interpreter may be multithreaded. If so, we attempt to
404  // ensure that signals are delivered to the main interpreter thread
405  // and no others by blocking signals before we exec the Octave
406  // interpreter executable. When that process starts, it will unblock
407  // signals in the main interpreter thread. When running the GUI as a
408  // subprocess, we also unblock signals that the parent process handles
409  // so we can forward them to the child.
410 
412  octave_block_signal_by_name ("SIGTSTP");
413 
414 #if defined (HAVE_OCTAVE_QT_GUI) && ! defined (OCTAVE_USE_WINDOWS_API)
415 
416  if (gui_libs && start_gui)
417  {
418  // Fork and exec when starting the GUI so that we will call
419  // setsid to give up the controlling terminal (if any) and so that
420  // the GUI process will be in a separate process group.
421  //
422  // The GUI process must be in a separate process group so that we
423  // can send an interrupt signal to all child processes when
424  // interrupting the interpreter. See also bug #49609 and the
425  // function pthread_thread_manager::interrupt in the file
426  // libgui/src/thread-manager.cc.
427 
428  gui_pid = octave_fork_wrapper ();
429 
430  if (gui_pid < 0)
431  {
432  std::cerr << "octave: fork failed!" << std::endl;
433 
434  retval = 1;
435  }
436  else if (gui_pid == 0)
437  {
438  // Child.
439 
440  if (octave_setsid_wrapper () < 0)
441  {
442  std::cerr << "octave: error calling setsid!" << std::endl;
443 
444  retval = 1;
445  }
446  else
447  retval = octave_exec (file, new_argv);
448  }
449  else
450  {
451  // Parent. Forward signals to child while waiting for it to exit.
452 
454 
456  octave_unblock_signal_by_name ("SIGTSTP");
457 
458  int status;
459 
460  while (true)
461  {
462  octave_waitpid_wrapper (gui_pid, &status, 0);
463 
464  if (caught_signal > 0)
465  {
466  int sig = caught_signal;
467 
468  caught_signal = -1;
469 
470  octave_kill_wrapper (gui_pid, sig);
471  }
472  else if (octave_wifexited_wrapper (status))
473  {
475  break;
476  }
477  else if (octave_wifsignaled_wrapper (status))
478  {
479  std::cerr << "octave exited with signal "
480  << octave_wtermsig_wrapper (status) << std::endl;
481  break;
482  }
483  }
484  }
485  }
486  else
487  {
488  retval = octave_exec (file, new_argv);
489 
490  if (retval < 0)
491  std::cerr << argv[0] << ": " << std::strerror (errno) << std::endl;
492  }
493 
494 #else
495 
496  retval = octave_exec (file, new_argv);
497 
498  if (retval < 0)
499  std::cerr << argv[0] << ": " << std::strerror (errno) << std::endl;
500 
501 #endif
502 
503  return retval;
504 }
const char * display_available(int *dpy_avail)
#define OCTAVE_BINDIR
Definition: main.in.cc:60
#define OCTAVE_ARCHLIBDIR
Definition: main.in.cc:56
static char * strsave(const char *s)
Definition: main.in.cc:195
static std::string get_octave_archlibdir(void)
Definition: main.in.cc:171
int main(int argc, char **argv)
Definition: main.in.cc:207
#define OCTAVE_VERSION
Definition: main.in.cc:52
static int octave_exec(const std::string &file, char **argv)
Definition: main.in.cc:185
static std::string get_octave_bindir(void)
Definition: main.in.cc:157
bool strcmp(const T &str_a, const T &str_b)
True if strings are the same.
Definition: oct-string.cc:122
void install_signal_handlers(void)
Definition: sighandlers.cc:361
T::size_type strlen(const typename T::value_type *str)
Definition: oct-string.cc:85
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811
static void set_octave_home(void)
Definition: shared-fcns.h:105
static std::string prepend_octave_exec_home(const std::string &s)
Definition: shared-fcns.h:189
static const char dir_sep_char
Definition: shared-fcns.h:84
static std::string octave_getenv(const std::string &name)
Definition: shared-fcns.h:94
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)
void octave_unblock_async_signals(void)
void octave_block_async_signals(void)
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:57
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