GNU Octave  4.4.1
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 Copyright (C) 2012-2018 John W. Eaton
5 
6 This file is part of Octave.
7 
8 Octave is free software: you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12 
13 Octave is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with Octave; see the file COPYING. If not, see
20 <https://www.gnu.org/licenses/>.
21 
22 */
23 
24 // NOTE: This program is supposed to be a small wrapper that exists
25 // primarily to give up the controlling TTY and then exec Octave with
26 // its GUI. It may also execute Octave without the GUI or the command
27 // line version of Octave that is not linked with GUI libraries. So
28 // that it remains small, it should NOT depend on or be linked with
29 // liboctave or libinterp.
30 
31 #if defined (HAVE_CONFIG_H)
32 # include "config.h"
33 #endif
34 
35 #include <cstdlib>
36 #include <cstring>
37 
38 #include <algorithm>
39 #include <iostream>
40 #include <string>
41 
42 #include "fcntl-wrappers.h"
43 #include "signal-wrappers.h"
44 #include "unistd-wrappers.h"
45 #include "wait-wrappers.h"
46 
47 #if ! defined (OCTAVE_VERSION)
48 # define OCTAVE_VERSION %OCTAVE_VERSION%
49 #endif
50 
51 #if ! defined (OCTAVE_ARCHLIBDIR)
52 # define OCTAVE_ARCHLIBDIR %OCTAVE_ARCHLIBDIR%
53 #endif
54 
55 #if ! defined (OCTAVE_BINDIR)
56 # define OCTAVE_BINDIR %OCTAVE_BINDIR%
57 #endif
58 
59 #if ! defined (OCTAVE_PREFIX)
60 # define OCTAVE_PREFIX %OCTAVE_PREFIX%
61 #endif
62 
63 #if ! defined (OCTAVE_EXEC_PREFIX)
64 # define OCTAVE_EXEC_PREFIX %OCTAVE_EXEC_PREFIX%
65 #endif
66 
67 #include "display-available.h"
68 #include "shared-fcns.h"
69 
70 #if defined (HAVE_OCTAVE_QT_GUI) && ! defined (OCTAVE_USE_WINDOWS_API)
71 
72 // Forward signals to the GUI process.
73 
74 static pid_t gui_pid = 0;
75 
76 static int caught_signal = -1;
77 
78 static void
79 gui_driver_sig_handler (int sig)
80 {
81  if (gui_pid > 0)
82  caught_signal = sig;
83 }
84 
85 static void
86 gui_driver_set_signal_handler (const char *signame,
87  octave_sig_handler *handler)
88 {
89  octave_set_signal_handler_by_name (signame, handler, false);
90 }
91 
92 static void
94 {
95  // FIXME: do we need to handle and forward all the signals that Octave
96  // handles, or is it sufficient to only forward things like SIGINT,
97  // SIGBREAK, SIGABRT, SIGQUIT, and possibly a few others?
98 
99  gui_driver_set_signal_handler ("SIGINT", gui_driver_sig_handler);
100  gui_driver_set_signal_handler ("SIGBREAK", gui_driver_sig_handler);
101  gui_driver_set_signal_handler ("SIGABRT", gui_driver_sig_handler);
102  gui_driver_set_signal_handler ("SIGALRM", gui_driver_sig_handler);
103  gui_driver_set_signal_handler ("SIGBUS", gui_driver_sig_handler);
104 
105  // SIGCHLD
106  // SIGCLD
107  // SIGCONT
108 
109  gui_driver_set_signal_handler ("SIGEMT", gui_driver_sig_handler);
110  gui_driver_set_signal_handler ("SIGFPE", gui_driver_sig_handler);
111  gui_driver_set_signal_handler ("SIGHUP", gui_driver_sig_handler);
112  gui_driver_set_signal_handler ("SIGILL", gui_driver_sig_handler);
113 
114  // SIGINFO
115  // SIGINT
116 
117  gui_driver_set_signal_handler ("SIGIOT", gui_driver_sig_handler);
118  gui_driver_set_signal_handler ("SIGLOST", gui_driver_sig_handler);
119  gui_driver_set_signal_handler ("SIGPIPE", gui_driver_sig_handler);
120  gui_driver_set_signal_handler ("SIGPOLL", gui_driver_sig_handler);
121 
122  // SIGPROF
123  // SIGPWR
124 
125  gui_driver_set_signal_handler ("SIGQUIT", gui_driver_sig_handler);
126  gui_driver_set_signal_handler ("SIGSEGV", gui_driver_sig_handler);
127 
128  // SIGSTOP
129 
130  gui_driver_set_signal_handler ("SIGSYS", gui_driver_sig_handler);
131  gui_driver_set_signal_handler ("SIGTERM", gui_driver_sig_handler);
132  gui_driver_set_signal_handler ("SIGTRAP", gui_driver_sig_handler);
133 
134  // SIGTSTP
135  // SIGTTIN
136  // SIGTTOU
137  // SIGURG
138 
139  gui_driver_set_signal_handler ("SIGUSR1", gui_driver_sig_handler);
140  gui_driver_set_signal_handler ("SIGUSR2", gui_driver_sig_handler);
141  gui_driver_set_signal_handler ("SIGVTALRM", gui_driver_sig_handler);
142  gui_driver_set_signal_handler ("SIGIO", gui_driver_sig_handler);
143 
144  // SIGWINCH
145 
146  gui_driver_set_signal_handler ("SIGXCPU", gui_driver_sig_handler);
147  gui_driver_set_signal_handler ("SIGXFSZ", gui_driver_sig_handler);
148 }
149 
150 #endif
151 
152 static std::string
154 {
155  // Accept value from the environment literally, but substitute
156  // OCTAVE_HOME in the configuration value OCTAVE_BINDIR in case Octave
157  // has been relocated to some installation directory other than the
158  // one originally configured.
159 
160  std::string obd = octave_getenv ("OCTAVE_BINDIR");
161 
162  return obd.empty () ? prepend_octave_exec_home (std::string (OCTAVE_BINDIR)) : obd;
163 }
164 
165 static std::string
167 {
168  // Accept value from the environment literally, but substitute
169  // OCTAVE_HOME in the configuration value OCTAVE_ARCHLIBDIR in case
170  // Octave has been relocated to some installation directory other than
171  // the one originally configured.
172 
173  std::string dir = octave_getenv ("OCTAVE_ARCHLIBDIR");
174 
175  return dir.empty () ? prepend_octave_exec_home (std::string (OCTAVE_ARCHLIBDIR))
176  : dir;
177 }
178 
179 static int
181 {
182  int status = octave_execv_wrapper (file.c_str (), argv);
183 
184  std::cerr << argv[0] << ": failed to exec '" << file << "'" << std::endl;
185 
186  return status;
187 }
188 
189 static char *
190 strsave (const char *s)
191 {
192  if (! s)
193  return nullptr;
194 
195  int len = strlen (s);
196  char *tmp = new char [len+1];
197  tmp = strcpy (tmp, s);
198  return tmp;
199 }
200 
201 int
202 main (int argc, char **argv)
203 {
204  int retval = 0;
205 
206  bool start_gui = false;
207  bool gui_libs = true;
208 
209  set_octave_home ();
210 
211  std::string octave_bindir = get_octave_bindir ();
212  std::string octave_archlibdir = get_octave_archlibdir ();
213  std::string octave_cli
214  = octave_bindir + dir_sep_char + "octave-cli-" OCTAVE_VERSION;
215  std::string octave_gui = octave_archlibdir + dir_sep_char + "octave-gui";
216 
217 #if defined (HAVE_OCTAVE_QT_GUI)
218  // The Octave version number is already embedded in the
219  // octave_archlibdir directory name so we don't need to append it to
220  // the octave-gui filename.
221 
222  std::string file = octave_gui;
223 #else
224  std::string file = octave_cli;
225 #endif
226 
227  // Declaring new_argv static avoids leak warnings when using GCC's
228  // --address-sanitizer option.
229  static char **new_argv = new char * [argc + 1];
230 
231  int k = 1;
232 
233  bool warn_display = true;
234  bool no_display = false;
235 
236  for (int i = 1; i < argc; i++)
237  {
238  if (! strcmp (argv[i], "--no-gui-libs"))
239  {
240  // Run the version of Octave that is not linked with any GUI
241  // libraries. It may not be possible to do plotting or any
242  // ui* calls, but it will be a little faster to start and
243  // require less memory. Don't pass the --no-gui-libs option
244  // on as that option is not recognized by Octave.
245 
246  gui_libs = false;
247  file = octave_cli;
248  }
249  else if (! strcmp (argv[i], "--no-gui"))
250  {
251  // If we see this option, then we can just exec octave; we
252  // don't have to create a child process and wait for it to
253  // exit. But do exec "octave-gui", not "octave-cli", because
254  // even if the --no-gui option is given, we may be asked to do
255  // some plotting or ui* calls.
256 
257  start_gui = false;
258  new_argv[k++] = argv[i];
259  }
260  else if (! strcmp (argv[i], "--gui") || ! strcmp (argv[i], "--force-gui"))
261  {
262  // If we see this option, then we fork and exec octave with
263  // the --gui option, while continuing to handle signals in the
264  // terminal.
265 
266  start_gui = true;
267  new_argv[k++] = argv[i];
268  }
269  else if (! strcmp (argv[i], "--silent") || ! strcmp (argv[i], "--quiet"))
270  {
271  warn_display = false;
272  new_argv[k++] = argv[i];
273  }
274  else if (! strcmp (argv[i], "--no-window-system"))
275  {
276  no_display = true;
277  new_argv[k++] = argv[i];
278  }
279  else if (strlen (argv[i]) > 1 && argv[i][0] == '-' && argv[i][1] != '-')
280  {
281  // Handle all single-letter command line options here; they may
282  // occur alone or may be aggregated into a single argument.
283 
284  size_t len = strlen (argv[i]);
285 
286  for (size_t j = 1; j < len; j++)
287  switch (argv[i][j])
288  {
289  case 'W':
290  no_display = true;
291  break;
292  case 'q':
293  warn_display = false;
294  break;
295  default:
296  break;
297  }
298 
299  new_argv[k++] = argv[i];
300  }
301  else
302  new_argv[k++] = argv[i];
303  }
304 
305  // At this point, gui_libs and start_gui are just about options, not
306  // the environment. Exit if they don't make sense.
307 
308  if (start_gui)
309  {
310  if (! gui_libs)
311  {
312  std::cerr << "octave: conflicting options: --no-gui-libs and --gui"
313  << std::endl;
314  return 1;
315  }
316 
317 #if ! defined (HAVE_OCTAVE_QT_GUI)
318  std::cerr << "octave: GUI features missing or disabled in this build"
319  << std::endl;
320  return 1;
321 #endif
322  }
323 
324  new_argv[k] = nullptr;
325 
326  if (no_display)
327  {
328  start_gui = false;
329  gui_libs = false;
330 
331  file = octave_cli;
332  }
333  else if (gui_libs || start_gui)
334  {
335  int dpy_avail;
336 
337  const char *display_check_err_msg = display_available (&dpy_avail);
338 
339  if (! dpy_avail)
340  {
341  start_gui = false;
342  gui_libs = false;
343 
344  file = octave_cli;
345 
346  if (warn_display)
347  {
348  if (! display_check_err_msg)
349  display_check_err_msg = "graphical display unavailable";
350 
351  std::cerr << "octave: " << display_check_err_msg << std::endl;
352  std::cerr << "octave: disabling GUI features" << std::endl;
353  }
354  }
355  }
356 
357 #if defined (OCTAVE_USE_WINDOWS_API)
358  file += ".exe";
359 #endif
360 
361  new_argv[0] = strsave (file.c_str ());
362 
363  // The Octave interpreter may be multithreaded. If so, we attempt to
364  // ensure that signals are delivered to the main interpreter thread
365  // and no others by blocking signals before we exec the Octave
366  // interpreter executable. When that process starts, it will unblock
367  // signals in the main interpreter thread. When running the GUI as a
368  // subprocess, we also unblock signals that the parent process handles
369  // so we can forward them to the child.
370 
372 
373 #if defined (HAVE_OCTAVE_QT_GUI) && ! defined (OCTAVE_USE_WINDOWS_API)
374 
375  if (gui_libs && start_gui)
376  {
377  // Fork and exec when starting the GUI so that we will call
378  // setsid to give up the controlling terminal (if any) and so that
379  // the GUI process will be in a separate process group.
380  //
381  // The GUI process must be in a separate process group so that we
382  // can send an interrupt signal to all child processes when
383  // interrupting the interpreter. See also bug #49609 and the
384  // function pthread_thread_manager::interrupt in the file
385  // libgui/src/thread-manager.cc.
386 
387  gui_pid = octave_fork_wrapper ();
388 
389  if (gui_pid < 0)
390  {
391  std::cerr << "octave: fork failed!" << std::endl;
392 
393  retval = 1;
394  }
395  else if (gui_pid == 0)
396  {
397  // Child.
398 
399  if (octave_setsid_wrapper () < 0)
400  {
401  std::cerr << "octave: error calling setsid!" << std::endl;
402 
403  retval = 1;
404  }
405  else
406  retval = octave_exec (file, new_argv);
407  }
408  else
409  {
410  // Parent. Forward signals to child while waiting for it to exit.
411 
413 
415 
416  int status;
417 
418  while (true)
419  {
420  octave_waitpid_wrapper (gui_pid, &status, 0);
421 
422  if (caught_signal > 0)
423  {
424  int sig = caught_signal;
425 
426  caught_signal = -1;
427 
428  octave_kill_wrapper (gui_pid, sig);
429  }
430  else if (octave_wifexited_wrapper (status))
431  {
433  break;
434  }
435  else if (octave_wifsignaled_wrapper (status))
436  {
437  std::cerr << "octave exited with signal "
438  << octave_wtermsig_wrapper (status) << std::endl;
439  break;
440  }
441  }
442  }
443  }
444  else
445  {
446  retval = octave_exec (file, new_argv);
447 
448  if (retval < 0)
449  std::cerr << argv[0] << ": " << std::strerror (errno) << std::endl;
450  }
451 
452 #else
453 
454  retval = octave_exec (file, new_argv);
455 
456  if (retval < 0)
457  std::cerr << argv[0] << ": " << std::strerror (errno) << std::endl;
458 
459 #endif
460 
461  return retval;
462 }
static void set_octave_home(void)
Definition: shared-fcns.h:102
bool octave_wifsignaled_wrapper(int status)
For example cd octave end example noindent changes the current working directory to file
Definition: dirfns.cc:124
static std::string prepend_octave_exec_home(const std::string &s)
Definition: shared-fcns.h:186
#define OCTAVE_ARCHLIBDIR
Definition: main.in.cc:52
bool octave_wifexited_wrapper(int status)
int octave_kill_wrapper(pid_t pid, int signum)
int argc
Definition: load-save.cc:646
for large enough k
Definition: lu.cc:617
const char * display_available(int *dpy_avail)
void octave_sig_handler(int)
s
Definition: file-io.cc:2729
static int octave_exec(const std::string &file, char **argv)
Definition: main.in.cc:180
string_vector argv
Definition: load-save.cc:648
#define OCTAVE_VERSION
Definition: main.in.cc:48
#define OCTAVE_BINDIR
Definition: main.in.cc:56
int octave_wtermsig_wrapper(int status)
int main(int argc, char **argv)
Definition: main.in.cc:202
bool strcmp(const T &str_a, const T &str_b)
True if strings are the same.
Definition: oct-string.cc:112
double tmp
Definition: data.cc:6252
octave_value retval
Definition: data.cc:6246
static const char dir_sep_char
Definition: shared-fcns.h:81
pid_t octave_fork_wrapper(void)
pid_t octave_setsid_wrapper(void)
T::size_type strlen(const typename T::value_type *str)
Definition: oct-string.cc:75
int octave_wexitstatus_wrapper(int status)
void octave_unblock_async_signals(void)
static std::string get_octave_bindir(void)
Definition: main.in.cc:153
static char * strsave(const char *s)
Definition: main.in.cc:190
void octave_block_async_signals(void)
static std::string octave_getenv(const std::string &name)
Definition: shared-fcns.h:91
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:54
static std::string get_octave_archlibdir(void)
Definition: main.in.cc:166
for i
Definition: data.cc:5264
octave_sig_handler * octave_set_signal_handler_by_name(const char *signame, octave_sig_handler *handler, bool restart_syscalls)
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:888
void install_signal_handlers(void)
Definition: sighandlers.cc:362