ARB
xcmd.cxx
Go to the documentation of this file.
1 // ========================================================= //
2 // //
3 // File : xcmd.cxx //
4 // Purpose : support to run commands in (x)terminal //
5 // //
6 // Coded by Ralf Westram (coder@reallysoft.de) in Sep 25 //
7 // http://www.arb-home.de/ //
8 // //
9 // ========================================================= //
10 
11 #include "xcmd.hxx"
12 #include "dbserver.hxx"
13 
14 #include <arbdb.h>
15 #include <arb_strbuf.h>
16 #include <arb_sleep.h>
17 #include <aw_msg.hxx>
18 
19 using namespace std;
20 
21 // ---------------------------
22 // external commands
23 
24 #define SYNC_STATE_STARTED "started"
25 #define SYNC_STATE_FINISHED "finished"
26 
27 static GB_ERROR wait_for_sync__servingDB(GBDATA *gb_main, const char *sync_id) {
28  bool sync_reached = false;
30 
31  ARB_timeout show_wait(2, SEC);
32  ARB_timeout show_serve_error(500, MS);
33 
34  while (!sync_reached && !error) {
35  GB_ERROR serve_error = serve_db_while_GUI_is_blocked(gb_main);
36  if (serve_error) {
37  if (show_serve_error.passed()) {
38  // Note: this error is unexpected and might indicate a severe problem (deadlock, broken design, ...)
39  fprintf(stderr, "Error serving DB (while waiting for sync '%s'): %s\n", sync_id, serve_error);
40  show_serve_error.restart(1.7);
41  }
42  }
43 
44  GB_transaction ta(gb_main);
45  GB_CSTR value = GB_read_sync_value(gb_main, sync_id);
46  if (value) {
47  if (strcmp(value, SYNC_STATE_FINISHED) == 0) {
48  fprintf(stderr, "reached expected sync on ID '%s': current value is '%s'\n", sync_id, value);
49  sync_reached = true;
50  }
51  else if (strcmp(value, SYNC_STATE_STARTED) != 0) {
52  error = GBS_global_string("sync-ID '%s' has unexpected value '%s'", sync_id, value);
53  }
54  else {
55  if (show_wait.passed()) {
56  fprintf(stderr, "waiting for sync on ID '%s': current value is '%s'\n", sync_id, value);
57  show_wait.restart(1.7);
58  }
59  }
60  }
61  else {
62  error = GB_await_error();
63  }
64  }
65 
66  return error;
67 }
68 
69 GB_ERROR ARB_system(const char *cmd, XCmdType boundExectype) {
70  XCMD_TYPE exectype = boundExectype.get_type();
71  GBDATA *gb_main = boundExectype.get_gb_main();
72 
73  // runs a command in an xterm
74 
75  bool background = exectype & _XCMD__ASYNC; // true -> run asynchronous
76  bool requires_DB_access = exectype & _XCMD__ACCESS_DB; // true -> assume shell process requires DB access
77  bool always_wait_key = exectype & _XCMD__WAITKEY; // true -> always wait for keypress (otherwise only wait if 'cmd' fails)
78  bool hidden = exectype & _XCMD__HIDDEN; // true -> do not use terminal window
79  char *sync_via_ID = NULp;
80 
81  if (!background && requires_DB_access) {
82  if (GB_is_server(gb_main)) {
83  static int sync_counter = 0;
84  sync_via_ID = GBS_global_string_copy("xcmd%i", ++sync_counter);
85 
86  // run shell command asynchronously (synchronisation will be done via database)
87  background = true;
88 
89  fprintf(stderr, "synchronise command using ID '%s'. command=%s\n", sync_via_ID, cmd);
90  }
91  // else: we are a client -> database access is possible from synchronous shell command
92  // (Note: this might fail, if the client itself currently blocks the server)
93  }
94 
95  const int BUFSIZE = 4096;
96  GBS_strstruct system_call(BUFSIZE);
97 
98  system_call.put('(');
99  if (!hidden) system_call.cat(GB_getenvARB_XCMD());
100 
101  {
102  GBS_strstruct bash_command(BUFSIZE);
103 
104  GB_CSTR ldlibpath = GB_getenv("LD_LIBRARY_PATH"); // due to SIP ldlibpath is always NULL under osx
105  // (should not matter because all binaries are linked statically)
106 
107  if (ldlibpath) {
108  bash_command.cat("LD_LIBRARY_PATH=");
109  {
110  char *dquoted_library_path = GBK_doublequote(ldlibpath);
111  bash_command.cat(dquoted_library_path);
112  free(dquoted_library_path);
113  }
114  bash_command.cat(";export LD_LIBRARY_PATH;");
115  }
116 #if !defined(DARWIN)
117  else {
118  // under Linux it normally is a problem if LD_LIBRARY_PATH is undefined
119  // -> warn in terminal to provide a hint:
120  bash_command.cat("echo 'Warning: LD_LIBRARY_PATH is undefined';");
121  }
122 #endif
123 
124  bash_command.cat(" (");
125  bash_command.cat(cmd);
126 
127  {
128  char *sync_command = sync_via_ID ? GBS_global_string_copy("arb_sync --write %s " SYNC_STATE_FINISHED, sync_via_ID) : NULp;
129  const char *wait_commands = hidden ? "sleep 1" : "echo; echo 'Press ENTER to close this window'; read a";
130 
131  if (always_wait_key) {
132  bash_command.cat("; [ $? -ne 0 ] && echo \"Command terminated with failure (exit code $?)\""); // display failure
133  bash_command.cat("; ");
134  }
135  else {
136  bash_command.cat("; xc=$?"); // store exitcode of command
137  if (sync_command) {
138  bash_command.cat("; ");
139  bash_command.cat(sync_command); // sync arb macro execution
140  }
141  bash_command.cat("; [ $xc -ne 0 ] && echo \"Command terminated with failure (exit code $xc)\""); // display failure
142  bash_command.cat("; exit $xc"); // restore exitcode of command
143  bash_command.cat(") || (");
144  }
145  bash_command.cat(wait_commands);
146  if (always_wait_key && sync_command) {
147  bash_command.cat("; ");
148  bash_command.cat(sync_command); // sync arb macro execution
149  }
150  bash_command.put(')');
151 
152  free(sync_command);
153  }
154 
155  char *squoted_bash_command = GBK_singlequote(bash_command.get_data());
156  system_call.cat(" bash -c ");
157  system_call.cat(squoted_bash_command);
158  free(squoted_bash_command);
159  }
160  system_call.cat(" )");
161  if (background) system_call.cat(" &");
162 
163  GB_ERROR error = NULp;
164  if (sync_via_ID) {
165  GB_transaction ta(gb_main);
166  error = GB_write_sync_value(gb_main, sync_via_ID, SYNC_STATE_STARTED);
167  }
168 
169  if (!error) {
170  error = GBK_system(system_call.get_data());
171  // if error occurs here (or before) -> sync value will never change
172  }
173 
174  if (sync_via_ID && !error) {
175  error = wait_for_sync__servingDB(gb_main, sync_via_ID);
176  }
177 
178  freenull(sync_via_ID);
179 
180  return error;
181 }
182 
183 void ARB_system_in_console_cb(AW_window*, const char *command, const XCmdType *exectype) {
184  // like ARB_system, but usable as WindowCallback + displays errors as message.
185  aw_message_if(ARB_system(command, *exectype));
186 }
187 
GB_ERROR GBK_system(const char *system_command)
Definition: arb_msg.cxx:571
const char * GB_ERROR
Definition: arb_core.h:25
bool GB_is_server(GBDATA *gbd)
Definition: adcomm.cxx:1697
char * GBK_doublequote(const char *arg)
Definition: arb_msg.cxx:624
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:203
STL namespace.
void cat(const char *from)
Definition: arb_strbuf.h:199
GB_ERROR ARB_system(const char *cmd, XCmdType boundExectype)
Definition: xcmd.cxx:69
GB_ERROR GB_await_error()
Definition: arb_msg.cxx:342
GB_ERROR serve_db_while_GUI_is_blocked(GBDATA *gb_main)
Definition: dbserver.cxx:304
static void error(const char *msg)
Definition: mkptypes.cxx:96
GB_CSTR GB_read_sync_value(GBDATA *gb_main, const char *id)
Definition: adsocket.cxx:951
GB_ERROR GB_write_sync_value(GBDATA *gb_main, const char *id, const char *value)
Definition: adsocket.cxx:939
#define SYNC_STATE_FINISHED
Definition: xcmd.cxx:25
void ARB_system_in_console_cb(AW_window *, const char *command, const XCmdType *exectype)
Definition: xcmd.cxx:183
GB_CSTR GB_getenv(const char *env)
Definition: adsocket.cxx:710
char * GBK_singlequote(const char *arg)
Definition: arb_msg.cxx:599
Definition: arb_sleep.h:30
void restart(double factor)
Definition: arb_sleep.h:132
static GB_ERROR wait_for_sync__servingDB(GBDATA *gb_main, const char *sync_id)
Definition: xcmd.cxx:27
#define NULp
Definition: cxxforward.h:116
static char * command
Definition: arb_a2ps.c:319
const char * get_data() const
Definition: arb_strbuf.h:120
GBDATA * get_gb_main() const
Definition: xcmd.hxx:64
GB_transaction ta(gb_var)
#define BUFSIZE
GBDATA * gb_main
Definition: adname.cxx:32
bool passed() const
Definition: arb_sleep.h:128
XCMD_TYPE get_type() const
Definition: xcmd.hxx:63
GB_CSTR GB_getenvARB_XCMD(void)
Definition: adsocket.cxx:533
Definition: arb_sleep.h:30
XCMD_TYPE
Definition: xcmd.hxx:21
void aw_message_if(GB_ERROR error)
Definition: aw_msg.hxx:21
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:194
#define SYNC_STATE_STARTED
Definition: xcmd.cxx:24
void put(char c)
Definition: arb_strbuf.h:174