ARB
adtcp.cxx
Go to the documentation of this file.
1 // =============================================================== //
2 // //
3 // File : adtcp.cxx //
4 // Purpose : arb_tcp.dat handling //
5 // //
6 // Coded by Ralf Westram (coder@reallysoft.de) in April 2007 //
7 // Institute of Microbiology (Technical University Munich) //
8 // http://www.arb-home.de/ //
9 // //
10 // =============================================================== //
11 
12 #include <ctime>
13 #include <sys/stat.h>
14 
15 #include <arbdbt.h>
16 #include <arb_str.h>
17 
18 #include "gb_local.h"
19 
20 #if defined(DEBUG)
21 // #define DUMP_ATD_ACCESS
22 #endif // DEBUG
23 
24 // ------------------------------------------------------------
25 // Data representing current content of arb_tcp.dat
26 
27 class ArbTcpDat : virtual Noncopyable {
28  GB_ULONG modtime; // modification time of read-in arb_tcp.dat
29  char *filename; // pathname of loaded arb_tcp.dat
30 
31  char **content; /* zero-pointer terminated array of multi-separated strings
32  * (strings have same format as the result of
33  * GBS_read_arb_tcp(), but also contain the first element,
34  * i.e. the server id)
35  */
36  int serverCount;
37 
38 
39  void freeContent() {
40  if (content) {
41  for (int c = 0; content[c]; c++) free(content[c]);
42  freenull(content);
43  }
44  }
45  GB_ERROR read(int *versionFound);
46 
47 public:
48  ArbTcpDat() : modtime(-1) , filename(NULp) , content(NULp), serverCount(-1) { }
49 
51  free(filename);
52  freeContent();
53  }
54 
55  GB_ERROR update();
56 
57  int get_server_count() const { return serverCount; }
58  const char *get_serverID(int idx) const { gb_assert(idx >= 0 && idx<serverCount); return content[idx]; }
59  const char *get_entry(const char *serverID) const;
60  const char *get_filename() const { return filename; }
61 
62 #if defined(DUMP_ATD_ACCESS)
63  void dump();
64 #endif
65 };
66 
67 const char *ArbTcpDat::get_entry(const char *serverID) const {
68  const char *result = NULp;
69  if (content) {
70  int c;
71  for (c = 0; content[c]; c++) {
72  const char *id = content[c];
73 
74  if (strcmp(id, serverID) == 0) {
75  result = strchr(id, 0)+1; // return pointer to first parameter
76  break;
77  }
78  }
79  }
80  return result;
81 }
82 
83 #if defined(DUMP_ATD_ACCESS)
84 void ArbTcpDat::dump() {
85  fprintf(stderr, "filename='%s'\n", filename);
86  fprintf(stderr, "modtime='%lu'\n", modtime);
87  if (content) {
88  int c;
89  for (c = 0; content[c]; c++) {
90  char *data = content[c];
91  char *tok = data;
92  fprintf(stderr, "Entry #%i:\n", c);
93 
94  while (tok[0]) {
95  fprintf(stderr, "- '%s'\n", tok);
96  tok = strchr(tok, 0)+1;
97  }
98  }
99  }
100  else {
101  fprintf(stderr, "No content\n");
102  }
103 }
104 #endif // DUMP_ATD_ACCESS
105 
106 #define MAXLINELEN 512
107 #define MAXTOKENS 10
108 
109 GB_ERROR ArbTcpDat::read(int *versionFound) {
110  // used to read arb_tcp.dat or arb_tcp_org.dat
111  GB_ERROR error = NULp;
112  FILE *in = fopen(filename, "rt");
113 
114  *versionFound = 1; // default to version 1 (old format)
115 
116 #if defined(DUMP_ATD_ACCESS)
117  fprintf(stderr, "(re)reading %s\n", filename);
118 #endif // DUMP_ATD_ACCESS
119 
120  freeContent();
121 
122  if (!in) {
123  error = GBS_global_string("Can't read '%s'", filename);
124  }
125  else {
126  char buffer[MAXLINELEN+1];
127  char *lp;
128  int lineNumber = 0;
129  char **tokens = ARB_alloc<char*>(MAXTOKENS);
130 
131  int entries_allocated = 30;
132  int entries = 0;
133  char **entry = ARB_alloc<char*>(entries_allocated);
134 
135  if (!tokens || !entry) error = "Out of memory";
136 
137  for (lp = fgets(buffer, MAXLINELEN, in);
138  lp && !error;
139  lp = fgets(buffer, MAXLINELEN, in))
140  {
141  char *tok;
142  int tokCount = 0;
143  int t;
144 
145  lineNumber++;
146 
147  while ((tok = strtok(lp, " \t\n"))) {
148  if (tok[0] == '#') break; // EOL comment -> stop
149  if (tokCount >= MAXTOKENS) { error = "Too many tokens"; break; }
150  tokens[tokCount] = tokCount ? GBS_eval_env(tok) : ARB_strdup(tok);
151  if (!tokens[tokCount]) { error = GB_await_error(); break; }
152  tokCount++;
153  lp = NULp;
154  }
155 
156  if (!error && tokCount>0) {
157  if (strcmp(tokens[0], "ARB_TCP_DAT_VERSION") == 0) {
158  if (tokCount>1) *versionFound = atoi(tokens[1]);
159  }
160  else {
161  char *data;
162  {
163  int allsize = 0;
164  int size[MAXTOKENS];
165 
166  for (t = 0; t<tokCount; t++) {
167  size[t] = strlen(tokens[t])+1;
168  allsize += size[t];
169  }
170  allsize++; // additional zero byte
171 
172  data = ARB_alloc<char>(allsize);
173  {
174  char *d = data;
175  for (t = 0; t<tokCount; t++) {
176  memmove(d, tokens[t], size[t]);
177  d += size[t];
178  }
179  d[0] = 0;
180  }
181  }
182 
183  if (entries == entries_allocated) {
184  entries_allocated = (int)(entries_allocated*1.5);
185  ARB_realloc(entry, entries_allocated);
186  }
187  if (!error) {
188  entry[entries++] = data;
189  data = NULp;
190  }
191  free(data);
192  }
193  }
194 
195  if (error) error = GBS_global_string("%s (in line %i of '%s')", error, lineNumber, filename);
196  for (t = 0; t<tokCount; t++) freenull(tokens[t]);
197  }
198 
199  ARB_realloc(entry, entries+1);
200 
201  content = entry;
202  content[entries] = NULp;
203  serverCount = entries;
204 
205  free(tokens);
206  fclose(in);
207  }
208 
209 #if defined(DUMP_ATD_ACCESS)
210  dump();
211 #endif // DUMP_ATD_ACCESS
212  return error;
213 }
214 
216  return GB_lib_file(true, "", "arb_tcp.dat");
217 }
218 
220  // read arb_tcp.dat (once or if changed on disk)
221  GB_ERROR error = NULp;
222 
223  if (!filename) filename = GB_arbtcpdat_path();
224 
225  if (!filename) {
226  error = "File $ARBHOME/lib/arb_tcp.dat missing or unreadable";
227  }
228  else {
229  struct stat st;
230  if (stat(filename, &st) == 0) {
231  GB_ULONG mtime = st.st_mtime;
232  if (modtime != mtime) { // read once or when changed
233  int arb_tcp_version;
234  error = read(&arb_tcp_version);
235 
236  if (!error) {
237  int expected_version = 2;
238  if (arb_tcp_version != expected_version) {
239  error = GBS_global_string("Expected arb_tcp.dat version %i\n"
240  "Your '%s' has version %i\n"
241  "To solve the problem\n"
242  "- either reinstall ARB and do not select\n"
243  " 'Use information of already installed ARB'\n"
244  " (any changes to arb_tcp.dat will be lost)\n"
245  "- or backup your changed %s,\n"
246  " replace it by the contents from $ARBHOME/lib/arb_tcp_org.dat\n"
247  " and edit it to fit your needs.",
248  expected_version,
249  filename, arb_tcp_version,
250  filename);
251  }
252  }
253  modtime = error ? -1 : mtime;
254  }
255  }
256  else {
257  error = GBS_global_string("Can't stat '%s'", filename);
258  }
259  }
260 
261  if (error) {
262  freenull(filename);
263 #if defined(DUMP_ATD_ACCESS)
264  fprintf(stderr, "error=%s\n", error);
265 #endif // DUMP_ATD_ACCESS
266  }
267 
268  return error;
269 }
270 
272 
273 // --------------------------------------------------------------------------------
274 
275 const char *GBS_scan_arb_tcp_param(const char *ipPort, const char *wantedParam) {
276  /* search a specific server parameter in result from GBS_read_arb_tcp()
277  * wantedParam may be sth like '-d' (case is ignored!)
278  */
279  const char *result = NULp;
280  if (ipPort) {
281  const char *exe = strchr(ipPort, 0)+1;
282  const char *param = strchr(exe, 0)+1;
283  size_t plen = strlen(param);
284  size_t wplen = strlen(wantedParam);
285 
286  while (plen) {
287  if (strncasecmp(param, wantedParam, wplen) == 0) { // starts with wantedParam
288  result = param+wplen;
289  break;
290  }
291  param += plen+1; // position behind 0-delimiter
292  plen = strlen(param);
293  }
294  }
295  return result;
296 }
297 
298 // AISC_MKPT_PROMOTE:#ifdef UNIT_TESTS // UT_DIFF
299 // AISC_MKPT_PROMOTE:#define TEST_SERVER_ID (-666)
300 // AISC_MKPT_PROMOTE:#define TEST_GENESERVER_ID (-667)
301 // AISC_MKPT_PROMOTE:#endif
302 
303 const char *GBS_nameserver_tag(const char *add_field) {
304  if (add_field && add_field[0]) {
305  char *tag = GBS_global_string_copy("ARB_NAME_SERVER_%s", add_field);
306  ARB_strupper(tag);
307  RETURN_LOCAL_ALLOC(tag);
308  }
309  return "ARB_NAME_SERVER";
310 }
311 
312 const char *GBS_ptserver_tag(int id) {
313 #ifdef UNIT_TESTS // UT_DIFF
314  if (id == TEST_SERVER_ID) return "ARB_TEST_PT_SERVER";
315  if (id == TEST_GENESERVER_ID) return "ARB_TEST_PT_SERVER_GENE";
316 #endif // UNIT_TESTS
317  gb_assert(id >= 0);
318  const int MAXIDSIZE = 30;
319  static char server_tag[MAXIDSIZE];
320  // ASSERT_RESULT_BELOW(int, sprintf(server_tag, "ARB_PT_SERVER%i", id), MAXIDSIZE);
321  ASSERT_RESULT_PREDICATE(isBelow<int>(MAXIDSIZE), sprintf(server_tag, "ARB_PT_SERVER%i", id));
322  return server_tag;
323 }
324 
325 const char *GBS_read_arb_tcp(const char *env) {
357  const char *result = NULp;
358  GB_ERROR error = NULp;
359 
360  if (strchr(env, ':')) {
361  static char *resBuf = NULp;
362  freedup(resBuf, env);
363  result = resBuf;
364  }
365  else {
366  error = arb_tcp_dat.update(); // load once or reload after change on disk
367  if (!error) {
368  const char *user = GB_getenvUSER();
369  if (!user) {
370  error = "Environment variable 'USER' not defined";
371  }
372  else {
373  char *envuser = GBS_global_string_copy("%s:%s", user, env);
374  result = arb_tcp_dat.get_entry(envuser);
375 
376  if (!result) { // no user-specific entry found
377  result = arb_tcp_dat.get_entry(env);
378  if (!result) {
379  error = GBS_global_string("No such entry '%s' (or '%s') in '%s'",
380  env, envuser, arb_tcp_dat.get_filename());
381  }
382  }
383  free(envuser);
384  }
385  }
386  }
387 
388  gb_assert(result||error);
389  if (error) {
390  GB_export_error(error);
391  result = NULp;
392  }
393  return result;
394 }
395 
396 const char * const *GBS_get_arb_tcp_entries(const char *matching) {
400  static const char **matchingEntries = NULp;
401  static int matchingEntriesSize = 0;
402 
403  GB_ERROR error = arb_tcp_dat.update();
404  if (!error) {
405  int count = arb_tcp_dat.get_server_count();
406 
407  if (matchingEntriesSize != count) {
408  freeset(matchingEntries, ARB_alloc<const char*>(count+1));
409  matchingEntriesSize = count;
410  }
411 
412  int matched = 0;
413  for (int c = 0; c<count; c++) {
414  const char *id = arb_tcp_dat.get_serverID(c);
415 
416  if (!strchr(id, ':')) { // not user-specific
417  if (GBS_string_matches(id, matching, GB_MIND_CASE)) { // matches
418  matchingEntries[matched++] = id;
419  }
420  }
421  }
422  matchingEntries[matched] = NULp; // end of array
423  }
424  if (error) GB_export_error(error);
425  return error ? NULp : matchingEntries;
426 }
427 
428 // ---------------------------
429 // pt server related
430 
431 const char *GBS_ptserver_logname() {
432  RETURN_ONETIME_ALLOC(nulldup(GB_path_in_ARBLIB("pts/ptserver.log")));
433 }
434 
435 void GBS_add_ptserver_logentry(const char *entry) {
436  FILE *log = fopen(GBS_ptserver_logname(), "at");
437  if (log) {
438  chmod(GBS_ptserver_logname(), 0666);
439 
440  char atime[256];
441  time_t t = time(NULp);
442  tm *tms = localtime(&t);
443 
444  strftime(atime, 255, "%Y/%m/%d %k:%M:%S", tms);
445  fprintf(log, "%s %s\n", atime, entry);
446  fclose(log);
447  }
448  else {
449  fprintf(stderr, "Failed to write to '%s'\n", GBS_ptserver_logname());
450  }
451 }
452 
453 char *GBS_ptserver_id_to_choice(int i, int showBuild) {
454  /* Return a readable name for PTserver number 'i'
455  * If 'showBuild' then show build info as well.
456  *
457  * Return NULp in case of error (which was exported then)
458  */
459  const char *ipPort = GBS_read_arb_tcp(GBS_ptserver_tag(i));
460  char *result = NULp;
461 
462  if (ipPort) {
463  const char *file = GBS_scan_arb_tcp_param(ipPort, "-d");
464  const char *nameOnly = strrchr(file, '/');
465 
466  if (nameOnly) nameOnly++; // position behind '/'
467  else nameOnly = file; // otherwise show complete file
468 
469  {
470  char *remote = ARB_strdup(ipPort);
471  char *colon = strchr(remote, ':');
472  if (colon) *colon = 0; // hide port
473 
474  if (strcmp(remote, "localhost") == 0) { // hide localhost
475  result = nulldup(nameOnly);
476  }
477  else {
478  result = GBS_global_string_copy("%s: %s", remote, nameOnly);
479  }
480  free(remote);
481  }
482 
483 
484  if (showBuild) {
485  struct stat st;
486 
487  if (stat(file, &st) == 0) { // xxx.arb present
488  time_t fileMod = st.st_mtime;
489  char *serverDB = GBS_global_string_copy("%s.pt", file);
490  char *newResult = NULp;
491 
492  if (stat(serverDB, &st) == 0) { // pt-database present
493  if (st.st_mtime < fileMod) { // DB is newer than pt-database
494  newResult = GBS_global_string_copy("%s [starting or failed update]", result);
495  }
496  else {
497  char atime[256];
498  tm *tms = localtime(&st.st_mtime);
499 
500  strftime(atime, 255, "%Y/%m/%d %k:%M", tms);
501  newResult = GBS_global_string_copy("%s [%s]", result, atime);
502  }
503  }
504  else { // check for running build
505  char *serverDB_duringBuild = GBS_global_string_copy("%s%%", serverDB);
506  if (stat(serverDB_duringBuild, &st) == 0) {
507  newResult = GBS_global_string_copy("%s [building..]", result);
508  }
509  free(serverDB_duringBuild);
510  }
511 
512  if (newResult) freeset(result, newResult);
513  free(serverDB);
514  }
515  }
516  }
517 
518  return result;
519 }
520 
521 // --------------------------------------------------------------------------------
522 
523 #ifdef UNIT_TESTS
524 
525 #include <test_unit.h>
526 
527 void TEST_GBS_servertags() {
528  TEST_EXPECT_EQUAL(GBS_ptserver_tag(0), "ARB_PT_SERVER0");
529  TEST_EXPECT_EQUAL(GBS_ptserver_tag(7), "ARB_PT_SERVER7");
530 
531  TEST_EXPECT_EQUAL(GBS_nameserver_tag(NULp), "ARB_NAME_SERVER");
532  TEST_EXPECT_EQUAL(GBS_nameserver_tag(""), "ARB_NAME_SERVER");
533  TEST_EXPECT_EQUAL(GBS_nameserver_tag("test"), "ARB_NAME_SERVER_TEST");
534 }
535 
536 #endif // UNIT_TESTS
GB_ERROR update()
Definition: adtcp.cxx:219
const char * GB_ERROR
Definition: arb_core.h:25
#define MAXLINELEN
Definition: adtcp.cxx:106
string result
const char * id
Definition: AliAdmin.cxx:17
char * GB_arbtcpdat_path()
Definition: adtcp.cxx:215
char * ARB_strdup(const char *str)
Definition: arb_string.h:27
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:204
const char * GBS_ptserver_tag(int id)
Definition: adtcp.cxx:312
char buffer[MESSAGE_BUFFERSIZE]
Definition: seq_search.cxx:34
unsigned long GB_ULONG
Definition: arbdb_base.h:42
GB_ERROR GB_export_error(const char *error)
Definition: arb_msg.cxx:259
static ArbTcpDat arb_tcp_dat
Definition: adtcp.cxx:271
GB_ERROR GB_await_error()
Definition: arb_msg.cxx:353
#define ASSERT_RESULT_PREDICATE(Pred, Expr)
Definition: arb_assert.h:341
const char * get_serverID(int idx) const
Definition: adtcp.cxx:58
~ArbTcpDat()
Definition: adtcp.cxx:50
const char * get_filename() const
Definition: adtcp.cxx:60
static void error(const char *msg)
Definition: mkptypes.cxx:96
#define RETURN_ONETIME_ALLOC(allocated)
Definition: smartptr.h:315
#define RETURN_LOCAL_ALLOC(mallocation)
Definition: smartptr.h:310
GB_CSTR GB_path_in_ARBLIB(const char *relative_path)
Definition: adsocket.cxx:1124
char * ARB_strupper(char *s)
Definition: arb_str.h:63
char * GB_lib_file(bool warn_when_not_found, const char *libprefix, const char *filename)
Definition: adfile.cxx:198
#define MAXTOKENS
Definition: adtcp.cxx:107
#define gb_assert(cond)
Definition: arbdbt.h:11
GB_CSTR GB_getenvUSER(void)
Definition: adsocket.cxx:531
int get_server_count() const
Definition: adtcp.cxx:57
void ARB_realloc(TYPE *&tgt, size_t nelem)
Definition: arb_mem.h:43
const char * GBS_ptserver_logname()
Definition: adtcp.cxx:431
const char * get_entry(const char *serverID) const
Definition: adtcp.cxx:67
char * GBS_eval_env(GB_CSTR p)
Definition: adstring.cxx:212
#define NULp
Definition: cxxforward.h:97
const char *const * GBS_get_arb_tcp_entries(const char *matching)
Definition: adtcp.cxx:396
ArbTcpDat()
Definition: adtcp.cxx:48
void GBS_add_ptserver_logentry(const char *entry)
Definition: adtcp.cxx:435
const char * GBS_read_arb_tcp(const char *env)
Definition: adtcp.cxx:325
const char * GBS_nameserver_tag(const char *add_field)
Definition: adtcp.cxx:303
char * GBS_ptserver_id_to_choice(int i, int showBuild)
Definition: adtcp.cxx:453
bool GBS_string_matches(const char *str, const char *expr, GB_CASE case_sens)
Definition: admatch.cxx:193
#define TEST_EXPECT_EQUAL(expr, want)
Definition: test_unit.h:1283
char * GBS_global_string_copy(const char *templat,...)
Definition: arb_msg.cxx:195
const char * GBS_scan_arb_tcp_param(const char *ipPort, const char *wantedParam)
Definition: adtcp.cxx:275