source: tags/arb_5.1/ARBDB/adtcp.c

Last change on this file was 5956, checked in by baderk, 15 years ago

Logfile permissions set to rw-rw-rw (needed for multi-user environments).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.4 KB
Line 
1/* =============================================================== */
2/*                                                                 */
3/*   File      : adtcp.c                                           */
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/*   www.arb-home.de                                               */
9/* =============================================================== */
10
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14#include <time.h>
15#include <sys/stat.h>
16
17#include "adlocal.h"
18#include "arbdbt.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
27static GB_ULONG  ATD_modtime  = -1; /* modification time of read-in arb_tcp.dat */
28static char     *ATD_filename = 0; /* pathname of loaded arb_tcp.dat */
29
30static char **ATD_content = 0; /* zero-pointer terminated array of multi-separated strings
31                                * (strings have same format as the result of
32                                * GBS_read_arb_tcp(), but also contain the first element,
33                                * i.e. the server id)
34                                */
35
36/* ------------------------------------------------------------ */
37
38static const char *get_ATD_entry(const char *serverID) {
39    const char *result = 0;
40    if (ATD_content) {
41        int c;
42        for (c = 0; ATD_content[c]; c++) {
43            const char *id = ATD_content[c];
44
45            if (strcmp(id, serverID) == 0) {
46                result = strchr(id, 0)+1; /* return pointer to first parameter */
47                break;
48            }
49        }
50    }
51    return result;
52}
53
54/* ------------------------------------------------------------ */
55#if defined(DUMP_ATD_ACCESS)
56static void dump_ATD() {
57    printf("ATD_filename='%s'\n", ATD_filename);
58    printf("ATD_modtime='%lu'\n", ATD_modtime);
59    if (ATD_content) {
60        int c;
61        for (c = 0; ATD_content[c]; c++) {
62            char *data = ATD_content[c];
63            char *tok  = data;
64            printf("Entry #%i:\n", c);
65
66            while (tok[0]) {
67                printf("- '%s'\n", tok);
68                tok = strchr(tok, 0)+1;
69            }
70        }
71    }
72    else {
73        printf("No ATD_content\n");
74    }
75}
76#endif /* DUMP_ATD_ACCESS */
77/* ------------------------------------------------------------ */
78
79static void freeContent() {
80    if (ATD_content) {
81        int c;
82        for (c = 0; ATD_content[c]; c++) free(ATD_content[c]);
83        freeset(ATD_content, 0);
84    }
85}
86
87#define MAXLINELEN 512
88#define MAXTOKENS  10
89
90static GB_ERROR read_arb_tcp_dat(const char *filename, int *versionFound) {
91    /* used to read arb_tcp.dat or arb_tcp_org.dat */
92    GB_ERROR  error = 0;
93    FILE     *in    = fopen(filename, "rt");
94
95    *versionFound = 1; // default to version 1 (old format)
96
97#if defined(DUMP_ATD_ACCESS)
98    printf("(re)reading %s\n", filename);
99#endif /* DUMP_ATD_ACCESS */
100
101    freeContent();
102
103    if (!in) {
104        error = GBS_global_string("Can't read '%s'", filename);
105    }
106    else {
107        char   buffer[MAXLINELEN+1];
108        char  *lp;
109        int    lineNumber = 0;
110        char **tokens     = malloc(MAXTOKENS*sizeof(*tokens));
111
112        int    entries_allocated = 30;
113        int    entries           = 0;
114        char **entry             = malloc(entries_allocated*sizeof(*entry));
115
116        if (!tokens || !entry) error = "Out of memory";
117
118        for (lp = fgets(buffer, MAXLINELEN, in);
119             lp && !error;
120             lp = fgets(buffer, MAXLINELEN, in))
121        {
122            char *tok;
123            int   tokCount = 0;
124            int   t;
125
126            lineNumber++;
127
128            while ((tok = strtok(lp, " \t\n"))) {
129                if (tok[0] == '#') break; /* EOL comment -> stop */
130                if (tokCount >= MAXTOKENS) { error = "Too many tokens"; break; }
131                tokens[tokCount] = tokCount ? GBS_eval_env(tok) : strdup(tok);
132                if (!tokens[tokCount]) { error = GB_await_error(); break; }
133                tokCount++;
134                lp = 0;
135            }
136
137            if (!error && tokCount>0) {
138                if (strcmp(tokens[0], "ARB_TCP_DAT_VERSION") == 0) {
139                    if (tokCount>1) *versionFound = atoi(tokens[1]);
140                }
141                else {
142                    char *data;
143                    {
144                        int allsize = 0;
145                        int size[MAXTOKENS];
146
147                        for (t = 0; t<tokCount; t++) {
148                            size[t]  = strlen(tokens[t])+1;
149                            allsize += size[t];
150                        }
151                        allsize++;      /* additional zero byte */
152
153                        data = malloc(allsize);
154                        {
155                            char *d = data;
156                            for (t = 0; t<tokCount; t++) {
157                                memmove(d, tokens[t], size[t]);
158                                d += size[t];
159                            }
160                            d[0] = 0;
161                        }
162                    }
163
164                    if (entries == entries_allocated) {
165                        char **entry2;
166                        entries_allocated = (int)(entries_allocated*1.5);
167                        entry2            = realloc(entry, entries_allocated*sizeof(*entry));
168
169                        if (!entry2) error = "Out of memory";
170                        else entry = entry2;
171                    }
172                    if (!error) {
173                        entry[entries++] = data;
174                        data             = 0;
175                    }
176                    free(data);
177                }
178            }
179
180            if (error) error = GBS_global_string("%s (in line %i of '%s')", error, lineNumber, filename);
181            for (t = 0; t<tokCount; t++) freeset(tokens[t], 0);
182        }
183
184        ATD_content = realloc(entry, (entries+1)*sizeof(*entry));
185        if (!ATD_content) error = "Out of memory";
186        else ATD_content[entries] = 0;
187
188        free(tokens);
189        fclose(in);
190    }
191
192#if defined(DUMP_ATD_ACCESS)
193    dump_ATD();
194#endif /* DUMP_ATD_ACCESS */
195    return error;
196}
197
198static GB_ERROR load_arb_tcp_dat() {
199    /* read arb_tcp.dat (once or if changed on disk) */
200    GB_ERROR  error    = 0;
201    char     *filename = GBS_find_lib_file("arb_tcp.dat","", 1);
202
203    if (!filename) {
204        error = GBS_global_string("File $ARBHOME/lib/arb_tcp.dat not found");
205    }
206    else {
207        struct stat st;
208        if (stat(filename, &st) == 0) {
209            GB_ULONG modtime = st.st_mtime;
210            if (ATD_modtime != modtime) { // read once or when changed
211                int arb_tcp_version;
212
213                error = read_arb_tcp_dat(filename, &arb_tcp_version);
214                if (!error) {
215                    int expected_version = 2;
216                    if (arb_tcp_version != expected_version) {
217                        error = GBS_global_string("Expected arb_tcp.dat version %i\n"
218                                                  "Your '%s' has version %i\n"
219                                                  "To solve the problem\n"
220                                                  "- either reinstall ARB and do not select\n"
221                                                  "  'Use information of already installed ARB'\n"
222                                                  "  (any changes to arb_tcp.dat will be lost)\n"
223                                                  "- or backup your changed %s,\n"
224                                                  "  replace it by the contents from $ARBHOME/lib/arb_tcp_org.dat\n"
225                                                  "  and edit it to fit your needs.",
226                                                  expected_version,
227                                                  filename, arb_tcp_version,
228                                                  filename);
229                    }
230                }
231
232                free(ATD_filename);
233                if (!error) {
234                    ATD_modtime  = modtime;
235                    ATD_filename = filename;
236                    filename     = 0;
237                }
238                else {
239                    ATD_modtime  = -1;
240                    ATD_filename = 0;
241                }
242            }
243        }
244        else {
245            error = GBS_global_string("Can't stat '%s'", filename);
246        }
247    }
248    free(filename);
249
250#if defined(DUMP_ATD_ACCESS)
251    printf("error=%s\n", error);
252#endif /* DUMP_ATD_ACCESS */
253
254    return error;
255}
256
257const char *GBS_scan_arb_tcp_param(const char *ipPort, const char *wantedParam) {
258    /* search a specific server parameter in result from GBS_read_arb_tcp()
259     * wantedParam may be sth like '-d' (case is ignored!)
260     */
261    const char *result = 0;
262    if (ipPort) {
263        const char *exe   = strchr(ipPort, 0)+1;
264        const char *param = strchr(exe, 0)+1;
265        size_t      plen  = strlen(param);
266        size_t      wplen = strlen(wantedParam);
267
268        while (plen) {
269            if (strncasecmp(param, wantedParam, wplen) == 0) { /* starts with wantedParam */
270                result = param+wplen;
271                break;
272            }
273            param += plen+1;    /* position behind 0-delimiter */
274            plen   = strlen(param);
275        }
276    }
277    return result;
278}
279
280/********************************************************************************************
281            Find an entry in the $ARBHOME/lib/arb_tcp.dat file
282********************************************************************************************/
283
284const char *GBS_read_arb_tcp(const char *env) {
285    /* Be aware: GBS_read_arb_tcp returns a quite unusual string containing several string delimiters (0-characters).
286     * It contains all words (separated by space or tab in arb_tcp.dat) of the corresponding line in arb_tcp.dat.
287     * These words get concatenated (separated by 0 characters).
288     *
289     * The first word (which matches the parameter env) is skipped.
290     * The second word (the socket info = "host:port") is returned directly as result.
291     * The third word is the server executable name.
292     * The fourth and following words are parameters to the executable.
293     *
294     * To access these words follow this example:
295     *
296     * const char *ipPort = GBS_read_arb_tcp("ARB_NAME_SERVER");
297     * if (ipPort) {
298     *     const char *serverExe = strchr(ipPort, 0)+1;
299     *     const char *para1     = strchr(serverExe, 0)+1; // always exists!
300     *     const char *para2     = strchr(para1, 0)+1;
301     *     if (para2[0]) {
302     *         // para2 exists
303     *     }
304     * }
305     *
306     * see also GBS_read_arb_tcp_param() above
307     *
308     * Returns NULL on error (which is exported in that case)
309     */
310
311    const char *result = 0;
312    GB_ERROR    error  = 0;
313
314    if (strchr(env,':')){
315        static char *resBuf = 0;
316        freedup(resBuf, env);
317        result = resBuf;
318    }
319    else {
320        error = load_arb_tcp_dat(); /* load once or reload after change on disk */
321        if (!error) {
322            const char *user = GB_getenvUSER();
323            if (!user) {
324                error = "Environment variable 'USER' not defined";
325            }
326            else {
327                char *envuser = GBS_global_string_copy("%s:%s", user, env);
328                result        = get_ATD_entry(envuser);
329
330                if (!result) { /* no user-specific entry found */
331                    result = get_ATD_entry(env);
332                    if (!result) {
333                        error = GBS_global_string("Expected entry '%s' or '%s' in '%s'",
334                                                  env, envuser, ATD_filename);
335                    }
336                }
337                free(envuser);
338            }
339        }
340    }
341
342    ad_assert(result||error);
343    if (error) {
344        GB_export_error(error);
345        result = 0;
346    }
347    return result;
348}
349
350const char * const *GBS_get_arb_tcp_entries(const char *matching) {
351    /* returns a list of all matching non-user-specific entries found in arb_tcp.dat
352     * match is performed by GBS_string_matches (e.g. use "ARB_PT_SERVER*")
353     */
354    static const char **matchingEntries     = 0;
355    static int          matchingEntriesSize = 0;
356
357    GB_ERROR error = 0;
358
359    error = load_arb_tcp_dat();
360    if (!error) {
361        int count   = 0;
362        int matched = 0;
363        int c;
364
365        while (ATD_content[count]) count++;
366
367        if (matchingEntriesSize != count) {
368            freeset(matchingEntries, malloc((count+1)*sizeof(*matchingEntries)));
369            matchingEntriesSize = count;
370        }
371
372        for (c = 0; c<count; c++) {
373            const char *id = ATD_content[c];
374
375            if (strchr(id, ':') == 0) { /* not user-specific */
376                if (GBS_string_matches(id, matching, GB_MIND_CASE)) { /* matches */
377                    matchingEntries[matched++] = id;
378                }
379            }
380        }
381        matchingEntries[matched] = 0; /* end of array */
382    }
383    if (error) GB_export_error(error);
384    return error ? 0 : matchingEntries;
385}
386
387/* --------------------------- */
388/*      pt server related      */
389/* --------------------------- */
390
391const char *GBS_ptserver_logname() {
392    static char *serverlog = 0;
393    if (!serverlog) {
394        serverlog = nulldup(GB_path_in_ARBLIB("pts/ptserver.log", NULL));
395        gb_assert(serverlog);
396    }
397    return serverlog;
398}
399
400void GBS_add_ptserver_logentry(const char *entry) {
401    FILE *log = fopen(GBS_ptserver_logname(), "at");
402    if (log) {
403        chmod(GBS_ptserver_logname(), 0666);
404        char       atime[256];
405        time_t     t   = time(0);
406        struct tm *tms = localtime(&t);
407        strftime(atime, 255, "%Y/%m/%d %k:%M:%S", tms);
408        fprintf(log, "%s %s\n", atime, entry);
409        fclose(log);
410    }
411    else {
412        fprintf(stderr, "Failed to write to '%s'\n", GBS_ptserver_logname());
413    }
414}
415
416char *GBS_ptserver_id_to_choice(int i, int showBuild) {
417    /* Return a readable name for PTserver number 'i'
418     * If 'showBuild' then show build info as well.
419     *
420     * Return NULL in case of error (which was exported then)
421     */
422    char       *serverID = GBS_global_string_copy("ARB_PT_SERVER%i", i);
423    const char *ipPort   = GBS_read_arb_tcp(serverID);
424    char       *result   = 0;
425
426    if (ipPort) {
427        const char *file     = GBS_scan_arb_tcp_param(ipPort, "-d");
428        const char *nameOnly = strrchr(file, '/');
429
430        if (nameOnly) nameOnly++;   /* position behind '/' */
431        else nameOnly = file;       /* otherwise show complete file */
432
433        {
434            char *remote      = strdup(ipPort);
435            char *colon       = strchr(remote, ':');
436            if (colon) *colon = 0; /* hide port */
437
438            if (strcmp(remote, "localhost") == 0) { /* hide localhost */
439                result = nulldup(nameOnly);
440            }
441            else {
442                result = GBS_global_string_copy("%s: %s", remote, nameOnly);
443            }
444            free(remote);
445        }
446
447
448        if (showBuild) {
449            struct stat  st;
450
451            if (stat(file, &st) == 0) { // xxx.arb present
452                time_t  fileMod   = st.st_mtime;
453                char   *serverDB  = GBS_global_string_copy("%s.pt", file);
454                char   *newResult = 0;
455
456                if (stat(serverDB, &st) == 0) { // pt-database present
457                    if (st.st_mtime < fileMod) { // DB is newer than pt-database
458                        newResult = GBS_global_string_copy("%s [starting or failed update]", result);
459                    }
460                    else {
461                        char       atime[256];
462                        struct tm *tms  = localtime(&st.st_mtime);
463
464                        strftime(atime, 255,"%Y/%m/%d %k:%M", tms);
465                        newResult = GBS_global_string_copy("%s [%s]", result, atime);
466                    }
467                }
468                else { // check for running build
469                    char *serverDB_duringBuild = GBS_global_string_copy("%s%%", serverDB);
470                    if (stat(serverDB_duringBuild, &st) == 0) {
471                        newResult = GBS_global_string_copy("%s [building..]", result);
472                    }
473                    free(serverDB_duringBuild);
474                }
475
476                if (newResult) freeset(result, newResult);
477                free(serverDB);
478            }
479        }
480    }
481    free(serverID);
482
483    return result;
484}
485
Note: See TracBrowser for help on using the repository browser.