ARB
servercntrl.cxx
Go to the documentation of this file.
1 // ============================================================= //
2 // //
3 // File : servercntrl.cxx //
4 // Purpose : //
5 // //
6 // Institute of Microbiology (Technical University Munich) //
7 // http://www.arb-home.de/ //
8 // //
9 // ============================================================= //
10 
11 #include <servercntrl.h>
12 
13 #include <client_privat.h>
14 #include <client.h>
15 
16 #include <arbdb.h>
17 #include <arb_file.h>
18 #include <arb_sleep.h>
19 #include <ut_valgrinded.h>
20 
21 /* The following lines go to servercntrl.h
22  * edit here, not there!!
23  * call 'make proto' to update
24  */
25 
26 // AISC_MKPT_PROMOTE:#ifndef ARBDB_BASE_H
27 // AISC_MKPT_PROMOTE:#include <arbdb_base.h>
28 // AISC_MKPT_PROMOTE:#endif
29 // AISC_MKPT_PROMOTE:
30 // AISC_MKPT_PROMOTE:struct arb_params {
31 // AISC_MKPT_PROMOTE: char *species_name;
32 // AISC_MKPT_PROMOTE: char *extended_name;
33 // AISC_MKPT_PROMOTE: char *alignment;
34 // AISC_MKPT_PROMOTE: char *default_file;
35 // AISC_MKPT_PROMOTE: char *field;
36 // AISC_MKPT_PROMOTE: const char *field_default;
37 // AISC_MKPT_PROMOTE:
38 // AISC_MKPT_PROMOTE: int read_only;
39 // AISC_MKPT_PROMOTE:
40 // AISC_MKPT_PROMOTE: char *job_server;
41 // AISC_MKPT_PROMOTE: char *db_server;
42 // AISC_MKPT_PROMOTE: char *mgr_server;
43 // AISC_MKPT_PROMOTE: char *pt_server;
44 // AISC_MKPT_PROMOTE:
45 // AISC_MKPT_PROMOTE: char *tcp;
46 // AISC_MKPT_PROMOTE:};
47 // AISC_MKPT_PROMOTE:
48 // AISC_MKPT_PROMOTE:enum SpawnMode {
49 // AISC_MKPT_PROMOTE: WAIT_FOR_TERMINATION,
50 // AISC_MKPT_PROMOTE: SPAWN_ASYNCHRONOUS,
51 // AISC_MKPT_PROMOTE: SPAWN_DAEMONIZED,
52 // AISC_MKPT_PROMOTE:};
53 
54 #define TRIES 1
55 
56 static struct gl_struct {
59 
61  : link(NULp), com(0x10000*1) // faked type id (matches main object, e.g. AN_MAIN or PT_MAIN)
62  { }
64 
65 
66 inline void make_async_call(char*& command) {
67  freeset(command, GBS_global_string_copy("( %s ) &", command));
68 }
69 
70 char *createCallOnSocketHost(const char *host, const char *remotePrefix, const char *command, SpawnMode spawnmode, const char *logfile) {
85  arb_assert((remotePrefix[0] == 0) || (strchr(remotePrefix, 0)[-1] == '/'));
86  arb_assert(correlated(spawnmode == SPAWN_DAEMONIZED, logfile));
87 
88  char *call = NULp;
89  if (host && host[0]) {
90  const char *hostPort = strchr(host, ':');
91  char *hostOnly = ARB_strpartdup(host, hostPort ? hostPort-1 : NULp);
92 
93  if (hostOnly[0] && !GB_host_is_local(hostOnly)) {
94  char *quotedRemoteCommand = GBK_singlequote(GBS_global_string("%s%s", remotePrefix, command));
95  call = GBS_global_string_copy("ssh %s -n %s", hostOnly, quotedRemoteCommand);
96  free(quotedRemoteCommand);
97  }
98  free(hostOnly);
99  }
100 
101  if (!call) {
102  call = ARB_strdup(command);
103  make_valgrinded_call(call); // only on local host
104  }
105 
106  switch (spawnmode) {
108  break;
109 
110  case SPAWN_ASYNCHRONOUS:
111  make_async_call(call);
112  break;
113 
114  case SPAWN_DAEMONIZED: {
115  char *quotedLogfile = GBK_singlequote(logfile);
116  char *quotedDaemonizingCall = GBK_singlequote(GBS_global_string("nohup %s >> %s 2>&1 & disown", call, quotedLogfile));
117 
118  freeset(call, GBS_global_string_copy("bash -c %s", quotedDaemonizingCall));
119 
120  free(quotedDaemonizingCall);
121  free(quotedLogfile);
122  break;
123  }
124  }
125 
126  return call;
127 }
128 
129 GB_ERROR arb_start_server(const char *arb_tcp_env, int do_sleep) {
130  const char *tcp_id;
131  GB_ERROR error = NULp;
132 
133  if (!(tcp_id = GBS_read_arb_tcp(arb_tcp_env))) {
134  error = GB_await_error();
135  }
136  else {
137  const char *server = strchr(tcp_id, 0) + 1;
138  char *serverparams = NULp;
139 
140  /* concatenate all params behind server
141  Note : changed behavior on 2007/Mar/09 -- ralf
142  serverparams now is one space if nothing defined in arb_tcp.dat
143  (previously was same as 'server' - most likely a bug)
144  */
145  {
146  const char *param = strchr(server, 0)+1;
147  size_t plen = strlen(param);
148  size_t alllen = 0;
149 
150  while (plen) {
151  param += plen+1;
152  alllen += plen+1;
153  plen = strlen(param);
154  }
155 
156  ARB_alloc(serverparams, alllen+1);
157  {
158  char *sp = serverparams;
159 
160  param = strchr(server, 0)+1;
161  plen = strlen(param);
162  if (!plen) sp++;
163  else do {
164  memcpy(sp, param, plen);
165  sp[plen] = ' ';
166  sp += plen+1;
167  param += plen+1;
168  plen = strlen(param);
169  } while (plen);
170  sp[-1] = 0;
171  }
172  }
173 
174  {
175  char *command = NULp;
176  const char *port = strchr(tcp_id, ':');
177 
178  if (!port) {
179  error = GB_export_errorf("Error: Missing ':' in socket definition of '%s' in file $(ARBHOME)/lib/arb_tcp.dat", arb_tcp_env);
180  }
181  else {
182  // When arb is called from arb_launcher, ARB_SERVER_LOG gets set to the name of a logfile.
183  // If ARB_SERVER_LOG is set here -> start servers daemonized here (see #492 for motivation)
184 
185  const char *serverlog = GB_getenv("ARB_SERVER_LOG");
186  SpawnMode spawnmode = serverlog ? SPAWN_DAEMONIZED : SPAWN_ASYNCHRONOUS;
187  char *plainCommand = GBS_global_string_copy("%s %s '-T%s'", server, serverparams, port); // Note: quotes around -T added for testing only (remove@will)
188  command = createCallOnSocketHost(tcp_id, "$ARBHOME/bin/", plainCommand, spawnmode, serverlog);
189  free(plainCommand);
190  }
191 
192  if (!error) {
193  error = GBK_system(command);
194  if (do_sleep) ARB_sleep(5, SEC);
195  }
196  free(command);
197  }
198  free(serverparams);
199  }
200  return error;
201 }
202 
203 static GB_ERROR arb_wait_for_server(const char *arb_tcp_env, const char *tcp_id, int magic_number, struct gl_struct *serverctrl, int wait) {
204  GB_ERROR error = NULp;
205  serverctrl->link = aisc_open(tcp_id, serverctrl->com, magic_number, &error);
206 
207  if (!error && !serverctrl->link) { // no server running -> start one
208  error = arb_start_server(arb_tcp_env, 0);
209  while (!error && !serverctrl->link && wait) {
210  ARB_sleep(1, SEC);
211  wait--;
212  if ((wait%10) == 0 && wait>0) {
213  printf("Waiting for server '%s' to come up (%i seconds left)\n", arb_tcp_env, wait);
214  }
215  serverctrl->link = aisc_open(tcp_id, serverctrl->com, magic_number, &error);
216  }
217  }
218 
219  return error;
220 }
221 
222 static GB_ERROR check_server_selected(const char *arb_tcp_env) {
223  // check whether arb_tcp_env (normally created by GBS_ptserver_tag for pt-servers)
224  // indicates that no pt-server has been selected by user.
225  //
226  // if so -> provide simple error to reduce confusion.
227 
228  if (strcmp(arb_tcp_env, "ARB_PT_SERVER-1") == 0) {
229  return "No pt-server has been selected.";
230  }
231  return NULp;
232 }
233 
234 GB_ERROR arb_look_and_start_server(long magic_number, const char *arb_tcp_env) {
236 
237  GB_ERROR error = check_server_selected(arb_tcp_env);
238  if (!error) {
239  const char *tcp_id = GBS_read_arb_tcp(arb_tcp_env);
240  const char *arb_tcp_dat = "$(ARBHOME)/lib/arb_tcp.dat";
241 
242  if (!tcp_id) {
243  error = GBS_global_string("Entry '%s' not found in %s (%s)", arb_tcp_env, arb_tcp_dat, GB_await_error());
244  }
245  else {
246  const char *file = GBS_scan_arb_tcp_param(tcp_id, "-d"); // find parameter behind '-d'
247 
248  if (!file) {
249  error = GBS_global_string("Parameter -d missing for entry '%s' in %s", arb_tcp_env, arb_tcp_dat);
250  }
251  else {
252  if (strcmp(file, "!ASSUME_RUNNING") == 0) {
253  // assume pt-server is running on a host, w/o access to common network drive
254  // i.e. we cannot check for the existence of the database file
255  }
256  else if (GB_size_of_file(file) <= 0) {
257  if (strncmp(arb_tcp_env, "ARB_NAME_SERVER", 15) == 0) {
258  char *dir = ARB_strdup(file);
259  char *lastSlash = strrchr(dir, '/');
260 
261  if (lastSlash) {
262  lastSlash[0] = 0; // cut off file
263  {
264  const char *copy_cmd = GBS_global_string("cp %s/names.dat.template %s", dir, file);
265  error = GBK_system(copy_cmd);
266  }
267  if (!error && GB_size_of_file(file) <= 0) {
268  error = GBS_global_string("Cannot copy nameserver template (%s/names.dat.template missing?)", dir);
269  }
270  }
271  else {
272  error = GBS_global_string("Can't determine directory from '%s'", dir);
273  }
274  free(dir);
275  }
276  else if (strncmp(arb_tcp_env, "ARB_PT_SERVER", 13) == 0) {
277  const char *nameOnly = strrchr(file, '/');
278  if (!nameOnly) nameOnly = file;
279 
280  error = GBS_global_string("PT_server '%s' has not been created yet.\n"
281  " To create it follow these steps:\n"
282  " 1. Start ARB on the whole database you want to use for probe match/design\n"
283  " 2. Go to ARB_NTREE/Probes/PT_SERVER Admin\n"
284  " 3. Select '%s' and press BUILD SERVER\n"
285  " 4. Wait (up to hours, depending on your DB size)\n"
286  " 5. Meanwhile read the help file: PT_SERVER: What Why and How",
287  file, nameOnly);
288  }
289  else {
290  error = GBS_global_string("The file '%s' is missing. \nUnable to start %s", file, arb_tcp_env);
291  }
292  }
293  }
294 
295  if (!error) {
296  error = arb_wait_for_server(arb_tcp_env, tcp_id, magic_number, &glservercntrl, 20);
297 
298  if (!error) {
299  if (!glservercntrl.link) { // couldn't start server
300  error = // |
301  "ARB has problems to start a server! Possible reasons may be one\n"
302  "or several of the following list:\n"
303  "- the tcp_id (socket number) is already used by another program\n"
304  " (doesnt apply to user-specific PTSERVERs; check $ARBHOME/lib/arb_tcp.dat versus /etc/services)\n"
305  "- the server exited with error or has crashed.\n"
306  " In case of PTSERVER, the failure might be caused by:\n"
307  " - missing database in $ARBHOME/lib/pts/* (solution: update ptserver database)\n"
308  " - wrong permissions of $ARBHOME/lib/pts/* (no read access)\n"
309  " If you recently installed a new arb version, arb will continue\n"
310  " to use your previous 'arb_tcp.dat', which might be out-of-date.\n"
311  " Backup and remove it, then restart ARB. If it works now,\n"
312  " compare your old 'arb_tcp.dat' with the new one for changes.\n"
313  "- When using remote servers: login or network problems\n"
314  ;
315  }
316  else {
319  }
320  }
321  }
322  }
323  }
324 
326  return error;
327 }
328 
329 GB_ERROR arb_look_and_kill_server(int magic_number, const char *arb_tcp_env) {
330  GB_ERROR error = check_server_selected(arb_tcp_env);
331  if (!error) {
332  const char *tcp_id = GBS_read_arb_tcp(arb_tcp_env);
333  if (!tcp_id) {
334  error = GB_await_error();
335  }
336  else {
337  const char *server = strchr(tcp_id, 0)+1;
338 
339  glservercntrl.link = aisc_open(tcp_id, glservercntrl.com, magic_number, &error);
340  if (glservercntrl.link) {
343 
344  error = GBK_system(GBS_global_string("%s -kill -T%s &", server, tcp_id));
345  }
346  else {
347  error = "Server is not running";
348  }
349  }
350  }
351  return error;
352 }
353 
355  printf("General server parameters (some maybe unused by this server):\n"
356  " -s<name> sets species name to '<name>'\n"
357  " -e<name> sets extended name to '<name>'\n"
358  " -a<ali> sets alignment to '<ali>'\n"
359  " -d<file> sets default file to '<file>'\n"
360  " -f<field>=<def> sets DB field to '<field>' (using <def> as default)\n"
361  " -r read-only mode\n"
362  " -D<server> sets DB-server to '<server>' [default = ':']\n"
363  " -J<server> sets job-server to '<server>' [default = 'ARB_JOB_SERVER']\n"
364  " -M<server> sets MGR-server to '<server>' [default = 'ARB_MGR_SERVER']\n"
365  " -P<server> sets PT-server to '<server>' [default = 'ARB_PT_SERVER']\n"
366  " -T<[host]:port> sets TCP connection to '<[host]:port>'\n"
367  );
368 }
369 
370 arb_params *arb_trace_argv(int *argc, const char **argv) {
371  arb_params *erg = ARB_calloc<arb_params>(1);
372 
373  erg->db_server = ARB_strdup(":");
374  erg->job_server = ARB_strdup("ARB_JOB_SERVER");
375  erg->mgr_server = ARB_strdup("ARB_MGR_SERVER");
376  erg->pt_server = ARB_strdup("ARB_PT_SERVER");
377 
378  int s, d;
379  for (s=d=0; s<*argc; s++) {
380  if (argv[s][0] == '-') {
381  switch (argv[s][1]) {
382  case 's': erg->species_name = ARB_strdup(argv[s]+2); break;
383  case 'e': erg->extended_name = ARB_strdup(argv[s]+2); break;
384  case 'a': erg->alignment = ARB_strdup(argv[s]+2); break;
385  case 'd': erg->default_file = ARB_strdup(argv[s]+2); break;
386  case 'f': {
387  char *eq;
388  erg->field = ARB_strdup(argv[s]+2);
389 
390  eq = strchr(erg->field, '=');
391  if (eq) {
392  erg->field_default = eq+1;
393  eq[0] = 0;
394  }
395  else {
396  erg->field_default = NULp; // this is illegal - error handling done in caller
397  }
398  break;
399  }
400  case 'r': erg->read_only = 1; break;
401  case 'J': freedup(erg->job_server, argv[s]+2); break;
402  case 'D': freedup(erg->db_server, argv[s]+2); break;
403  case 'M': freedup(erg->mgr_server, argv[s]+2); break;
404  case 'P': freedup(erg->pt_server, argv[s]+2); break;
405  case 'T': {
406  const char *ipport = argv[s]+2;
407  if (ipport[0] == ':' &&
408  ipport[1] >= '0' && ipport[1] <= '9') { // port only -> assume localhost
409  erg->tcp = GBS_global_string_copy("localhost%s", ipport);
410  }
411  else {
412  erg->tcp = ARB_strdup(ipport);
413  }
414  break;
415  }
416  default:
417  argv[d++] = argv[s];
418  break;
419  }
420  }
421  else {
422  argv[d++] = argv[s];
423  }
424  }
425  *argc = d;
426  return erg;
427 }
428 
430  free(params->species_name);
431  free(params->extended_name);
432  free(params->alignment);
433  free(params->default_file);
434  free(params->field);
435  free(params->job_server);
436  free(params->db_server);
437  free(params->mgr_server);
438  free(params->pt_server);
439  free(params->tcp);
440 
441  free(params);
442 }
443 
444 // --------------------------------------------------------------------------------
445 
446 #if defined(UNIT_TESTS) && 0
447 
448 // If you need tests in AISC_COM/C/client.c, put them here instead.
449 
450 #include <test_unit.h>
451 
452 void TEST_servercntrl() {
453  TEST_REJECT(true); // would fail if test gets activated
454 }
455 
456 #endif // UNIT_TESTS
457 
GB_ERROR GBK_system(const char *system_command)
Definition: arb_msg.cxx:512
#define arb_assert(cond)
Definition: arb_assert.h:245
const char * GB_ERROR
Definition: arb_core.h:25
SpawnMode
Definition: servercntrl.h:33
int aisc_close(aisc_com *link, AISC_Object &object)
Definition: client.c:249
char * field
Definition: servercntrl.h:20
char * ARB_strdup(const char *str)
Definition: arb_string.h:27
GB_ERROR arb_look_and_start_server(long magic_number, const char *arb_tcp_env)
GB_ERROR arb_look_and_kill_server(int magic_number, const char *arb_tcp_env)
static GB_ERROR check_server_selected(const char *arb_tcp_env)
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:202
int read_only
Definition: servercntrl.h:23
bool GB_have_error()
Definition: arb_msg.cxx:337
char * ARB_strpartdup(const char *start, const char *end)
Definition: arb_string.h:51
char * alignment
Definition: servercntrl.h:18
AISC_Object com
Definition: servercntrl.cxx:58
long GB_size_of_file(const char *path)
Definition: arb_file.cxx:28
char * db_server
Definition: servercntrl.h:26
GB_ERROR arb_start_server(const char *arb_tcp_env, int do_sleep)
arb_params * arb_trace_argv(int *argc, const char **argv)
char * mgr_server
Definition: servercntrl.h:27
void free_arb_params(arb_params *params)
static ArbTcpDat arb_tcp_dat
Definition: adtcp.cxx:271
GB_ERROR GB_await_error()
Definition: arb_msg.cxx:341
void arb_print_server_params()
char * job_server
Definition: servercntrl.h:25
const char * GBS_read_arb_tcp(const char *env)
Definition: adtcp.cxx:325
char * extended_name
Definition: servercntrl.h:17
TYPE * ARB_alloc(size_t nelem)
Definition: arb_mem.h:56
const char * GBS_scan_arb_tcp_param(const char *ipPort, const char *wantedParam)
Definition: adtcp.cxx:275
char * createCallOnSocketHost(const char *host, const char *remotePrefix, const char *command, SpawnMode spawnmode, const char *logfile)
Definition: servercntrl.cxx:70
char * species_name
Definition: servercntrl.h:16
static GB_ERROR arb_wait_for_server(const char *arb_tcp_env, const char *tcp_id, int magic_number, struct gl_struct *serverctrl, int wait)
#define TEST_REJECT(cond)
Definition: test_unit.h:1315
static void error(const char *msg)
Definition: mkptypes.cxx:96
char * tcp
Definition: servercntrl.h:30
const char * field_default
Definition: servercntrl.h:21
void ARB_sleep(int amount, TimeUnit tu)
Definition: arb_sleep.h:32
aisc_com * link
Definition: servercntrl.cxx:57
GB_CSTR GB_getenv(const char *env)
Definition: adsocket.cxx:709
#define make_valgrinded_call(command)
GB_ERROR GB_export_errorf(const char *templat,...)
Definition: arb_msg.cxx:261
char * GBK_singlequote(const char *arg)
Definition: arb_msg.cxx:540
aisc_com * aisc_open(const char *path, AISC_Object &main_obj, long magic, GB_ERROR *error)
Definition: client.c:205
static struct gl_struct glservercntrl
char * pt_server
Definition: servercntrl.h:28
#define NULp
Definition: cxxforward.h:114
bool GB_host_is_local(const char *hostname)
Definition: adsocket.cxx:746
static char * command
Definition: arb_a2ps.c:319
char * default_file
Definition: servercntrl.h:19
Definition: arb_sleep.h:30
void make_async_call(char *&command)
Definition: servercntrl.cxx:66
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:193
GB_write_int const char s
Definition: AW_awar.cxx:154