Loading [MathJax]/extensions/TeX/AMSsymbols.js
LALMetaIO 4.0.6.1-b246709
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
processtable.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2007-2012 Duncan Brown, Jolien Creighton, Kipp Cannon,
3 * Reinhard Prix, Bernd Machenschalk
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with with program; see the file COPYING. If not, write to the Free
17 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301 USA
19 */
20
21
22#define _GNU_SOURCE
23
24
25#include <config.h>
26
27#include <ctype.h>
28#include <pwd.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <sys/types.h>
33#include <time.h>
34#include <unistd.h>
35
36
37#include <metaio.h>
38
39
40#include <lal/Date.h>
41#include <lal/LALMalloc.h>
42#include <lal/LIGOLwXML.h>
43#include <lal/LIGOLwXMLRead.h>
44#include <lal/LIGOMetadataTables.h>
45#include <lal/LIGOMetadataUtils.h>
46#include <lal/XLALError.h>
47
48
49/**
50 * Create a ProcessTable structure.
51 */
53{
54 ProcessTable *new = XLALMalloc(sizeof(*new));
55
56 if(!new)
58
59 new->next = NULL;
60 memset(new->program, 0, sizeof(new->program));
61 memset(new->version, 0, sizeof(new->version));
62 memset(new->cvs_repository, 0, sizeof(new->cvs_repository));
63 XLALGPSSet(&new->cvs_entry_time, 0, 0);
64 memset(new->comment, 0, sizeof(new->comment));
65 new->is_online = 0;
66 memset(new->node, 0, sizeof(new->node));
67 memset(new->username, 0, sizeof(new->username));
68 XLALGPSSet(&new->start_time, 0, 0);
69 XLALGPSSet(&new->end_time, 0, 0);
70 new->jobid = 0;
71 memset(new->domain, 0, sizeof(new->domain));
72 new->unix_procid = 0;
73 memset(new->ifos, 0, sizeof(new->ifos));
74 new->process_id = -1; /* impossible */
75
76 return new;
77}
78
79
80/**
81 * Destroy a ProcessTable structure.
82 */
84{
85 ProcessTable *next = row ? row->next : NULL;
86 XLALFree(row);
87 return next;
88}
89
90
91/**
92 * Destroy a ProcessTable linked list.
93 */
95{
96 while(head)
97 head = XLALDestroyProcessTableRow(head);
98}
99
100
101/**
102 * Return the next available process ID.
103 */
105{
106 long highest = -1;
107 for(; head; head = head->next)
108 if(head->process_id > highest)
109 highest = head->process_id;
110 return highest + 1;
111}
112
113
114/**
115 * Count and return the number of rows in the linked list.
116 */
118{
119 int length;
120
121 for(length = 0; head; head = head->next)
122 length++;
123
124 return length;
125}
126
127
128#ifndef _WIN32
129/**
130 * Parses a cvs keyword string in the form $keyword:value$, returning a
131 * newly-malloc()'ed string containing just the value. Leading and
132 * trailing whitespace is removed from the value string. Returns NULL on
133 * parse or malloc() failure.
134 */
135static char *cvs_get_keyword_value(const char *cvs_string)
136{
137 const char *value_start;
138 const char *value_end;
139 char *value;
140
141 /*
142 * check for input
143 */
144
145 if(!cvs_string)
146 return NULL;
147
148 /*
149 * string must start with '$'
150 */
151
152 value_start = strchr(cvs_string, '$');
153 if(!value_start)
154 return NULL;
155
156 /*
157 * keyword ends at ':'
158 */
159
160 value_end = strchr(value_start, ':');
161 if(!value_end) {
162 /*
163 * allow for unset keyword
164 */
165 value_start = strchr(value_start, '$');
166 if(!value_start)
167 return NULL;
168 else
169 --value_start;
170 } else {
171 value_start = value_end;
172 }
173
174 /*
175 * skip leading white space
176 */
177
178 while(isspace(*++value_start));
179 if(!*value_start)
180 return NULL;
181
182 /*
183 * string must end with '$'
184 */
185
186 value_end = strchr(value_start, '$');
187 if(!value_end)
188 return NULL;
189
190 /*
191 * skip trailing white space
192 */
193
194 while(isspace(*--value_end));
195 value_end++;
196 if(value_end - value_start < 0)
197 value_end = value_start;
198
199 /*
200 * extract value. +1 for the '\0' to be added
201 */
202
203 value = malloc((value_end - value_start + 1) * sizeof(*value));
204 if(!value)
205 return NULL;
206 memcpy(value, value_start, (value_end - value_start) * sizeof(*value));
207 value[value_end - value_start] = '\0';
208
209 /*
210 * done
211 */
212
213 return value;
214}
215
216
217/**
218 * Populate a pre-allocated ProcessTable structure.
219 */
221 ProcessTable *ptable,
222 const char *program_name,
223 const char *cvs_revision,
224 const char *cvs_source,
225 const char *cvs_date,
226 long process_id
227)
228{
229 char *cvs_keyword_value;
230 uid_t uid;
231 struct passwd *pw;
232 struct tm utc;
233
234 /*
235 * program name entry
236 */
237
238 snprintf(ptable->program, LIGOMETA_PROGRAM_MAX, "%s", program_name);
239
240 /*
241 * cvs version
242 */
243
244 cvs_keyword_value = cvs_get_keyword_value(cvs_revision);
245 if(!cvs_keyword_value) {
246 XLALPrintError("%s(): cannot parse \"%s\"\n", __func__, cvs_revision);
248 }
249 snprintf(ptable->version, LIGOMETA_VERSION_MAX, "%s", cvs_keyword_value);
250 free(cvs_keyword_value);
251
252 /*
253 * cvs repository
254 */
255
256 cvs_keyword_value = cvs_get_keyword_value(cvs_source);
257 if(!cvs_keyword_value) {
258 XLALPrintError("%s(): cannot parse \"%s\"\n", __func__, cvs_source);
260 }
261 snprintf(ptable->cvs_repository, LIGOMETA_CVS_REPOSITORY_MAX, "%s", cvs_keyword_value);
262 free(cvs_keyword_value);
263
264 /*
265 * cvs check-in time
266 */
267
268 cvs_keyword_value = cvs_get_keyword_value(cvs_date);
269 if(!cvs_keyword_value) {
270 XLALPrintError("%s(): cannot parse \"%s\"\n", __func__, cvs_date);
272 }
273 if(!strptime(cvs_keyword_value, "%Y/%m/%d %T", &utc)) {
274 if(!strptime(cvs_keyword_value, "%Y-%m-%d %T", &utc)) {
275 XLALPrintError("%s(): cannot parse \"%s\"\n", __func__, cvs_keyword_value);
276 free(cvs_keyword_value);
278 }
279 }
280 free(cvs_keyword_value);
282 XLALGPSSet(&ptable->cvs_entry_time, XLALUTCToGPS(&utc), 0);
283 if(XLALGetBaseErrno())
285
286 /*
287 * comment
288 */
289
290 snprintf(ptable->comment, LIGOMETA_COMMENT_MAX, " ");
291
292 /*
293 * online flag and domain
294 */
295
296 ptable->is_online = 0;
297 snprintf(ptable->domain, LIGOMETA_DOMAIN_MAX, "lalapps");
298
299 /*
300 * unix process id, username, host, and process_id
301 */
302
303 ptable->unix_procid = getpid();
304 if(!ptable->unix_procid)
305 ptable->unix_procid = getppid();
306 if(gethostname(ptable->node, LIGOMETA_NODE_MAX) < 0) {
307 perror("could not determine host name");
309 }
310 uid = geteuid();
311 if(!(pw = getpwuid(uid)))
312 snprintf(ptable->username, LIGOMETA_USERNAME_MAX, "%d", uid);
313 else
314 snprintf(ptable->username, LIGOMETA_USERNAME_MAX, "%s", pw->pw_name);
315 ptable->process_id = process_id;
316
317 /*
318 * done
319 */
320
321 return 0;
322}
323
324#else /* _WIN32 */
325
327 ProcessTable * ptable,
328 const char *program_name,
329 const char *cvs_revision,
330 const char *cvs_source,
331 const char *cvs_date,
332 long process_id
333)
334{
335 fprintf(stderr, "XLALPopulateProcessTable() not implemented for WIN32\n");
336 return 1;
337}
338#endif /* __WIN32 */
339
340
341/**
342 * Read the process table from a LIGO Light Weight XML file into a linked
343 * list of ProcessTable structures.
344 */
346 const char *filename
347)
348{
349 static const char table_name[] = "process";
350 int miostatus;
351 ProcessTable *head = NULL;
352 ProcessTable **next = &head;
353 struct MetaioParseEnvironment env;
354 struct {
355 int program;
356 int version;
357 int cvs_repository;
358 int cvs_entry_time;
359 int comment;
360 int is_online;
361 int node;
362 int username;
363 int unix_procid;
364 int start_time;
365 int end_time;
366 int jobid;
367 int domain;
368 int ifos;
369 int process_id;
370 } column_pos;
371
372 /* open the file and find table */
373
374 if(MetaioOpenFile(&env, filename)) {
375 XLALPrintError("%s(): error opening \"%s\": %s\n", __func__, filename, env.mierrmsg.data ? env.mierrmsg.data : "unknown reason");
377 }
378 if(MetaioOpenTableOnly(&env, table_name)) {
379 MetaioAbort(&env);
380 XLALPrintError("%s(): cannot find %s table: %s\n", __func__, table_name, env.mierrmsg.data ? env.mierrmsg.data : "unknown reason");
382 }
383
384 /* find columns */
385
387 column_pos.program = XLALLIGOLwFindColumn(&env, "program", METAIO_TYPE_LSTRING, 1);
388 column_pos.version = XLALLIGOLwFindColumn(&env, "version", METAIO_TYPE_LSTRING, 1);
389 column_pos.cvs_repository = XLALLIGOLwFindColumn(&env, "cvs_repository", METAIO_TYPE_LSTRING, 1);
390 column_pos.cvs_entry_time = XLALLIGOLwFindColumn(&env, "cvs_entry_time", METAIO_TYPE_INT_4S, 1);
391 column_pos.comment = XLALLIGOLwFindColumn(&env, "comment", METAIO_TYPE_LSTRING, 1);
392 column_pos.is_online = XLALLIGOLwFindColumn(&env, "is_online", METAIO_TYPE_INT_4S, 1);
393 column_pos.node = XLALLIGOLwFindColumn(&env, "node", METAIO_TYPE_LSTRING, 1);
394 column_pos.username = XLALLIGOLwFindColumn(&env, "username", METAIO_TYPE_LSTRING, 1);
395 column_pos.unix_procid = XLALLIGOLwFindColumn(&env, "unix_procid", METAIO_TYPE_INT_4S, 1);
396 column_pos.start_time = XLALLIGOLwFindColumn(&env, "start_time", METAIO_TYPE_INT_4S, 1);
397 column_pos.end_time = XLALLIGOLwFindColumn(&env, "end_time", METAIO_TYPE_INT_4S, 1);
398 column_pos.jobid = XLALLIGOLwFindColumn(&env, "jobid", METAIO_TYPE_INT_4S, 1);
399 column_pos.domain = XLALLIGOLwFindColumn(&env, "domain", METAIO_TYPE_LSTRING, 1);
400 column_pos.ifos = XLALLIGOLwFindColumn(&env, "ifos", METAIO_TYPE_LSTRING, 1);
401 column_pos.process_id = XLALLIGOLwFindColumn(&env, "process_id", METAIO_TYPE_INT_8S, 1);
402
403 /* check for failure (== a required column is missing) */
404
405 if(XLALGetBaseErrno()) {
406 MetaioAbort(&env);
407 XLALPrintError("%s(): failure reading %s table\n", __func__, table_name);
409 }
410
411 /* loop over the rows in the file */
412
413 while((miostatus = MetaioGetRow(&env)) > 0) {
414 /* create a new row */
415
417
418 if(!row) {
420 MetaioAbort(&env);
422 }
423
424 /* append to linked list */
425
426 *next = row;
427 next = &(*next)->next;
428
429 /* populate the columns */
430
431 strncpy(row->program, env.ligo_lw.table.elt[column_pos.program].data.lstring.data, sizeof(row->program) - 1);
432 strncpy(row->version, env.ligo_lw.table.elt[column_pos.version].data.lstring.data, sizeof(row->version) - 1);
433 strncpy(row->cvs_repository, env.ligo_lw.table.elt[column_pos.cvs_repository].data.lstring.data, sizeof(row->cvs_repository) - 1);
434 XLALGPSSet(&row->cvs_entry_time, env.ligo_lw.table.elt[column_pos.cvs_entry_time].data.int_4s, 0);
435 strncpy(row->comment, env.ligo_lw.table.elt[column_pos.comment].data.lstring.data, sizeof(row->comment) - 1);
436 row->is_online = env.ligo_lw.table.elt[column_pos.is_online].data.int_4s;
437 strncpy(row->node, env.ligo_lw.table.elt[column_pos.node].data.lstring.data, sizeof(row->node) - 1);
438 strncpy(row->username, env.ligo_lw.table.elt[column_pos.username].data.lstring.data, sizeof(row->username) - 1);
439 row->unix_procid = env.ligo_lw.table.elt[column_pos.unix_procid].data.int_4s;
440 XLALGPSSet(&row->start_time, env.ligo_lw.table.elt[column_pos.start_time].data.int_4s, 0);
441 XLALGPSSet(&row->end_time, env.ligo_lw.table.elt[column_pos.end_time].data.int_4s, 0);
442 row->jobid = env.ligo_lw.table.elt[column_pos.jobid].data.int_4s;
443 strncpy(row->domain, env.ligo_lw.table.elt[column_pos.domain].data.lstring.data, sizeof(row->domain) - 1);
444 strncpy(row->ifos, env.ligo_lw.table.elt[column_pos.ifos].data.lstring.data, sizeof(row->ifos) - 1);
445 row->process_id = env.ligo_lw.table.elt[column_pos.process_id].data.int_8s;
446 }
447 if(miostatus < 0) {
449 MetaioAbort(&env);
450 XLALPrintError("%s(): I/O error parsing %s table: %s\n", __func__, table_name, env.mierrmsg.data ? env.mierrmsg.data : "unknown reason");
452 }
453
454 /* close file */
455
456 if(MetaioClose(&env)) {
458 XLALPrintError("%s(): error parsing document after %s table: %s\n", __func__, table_name, env.mierrmsg.data ? env.mierrmsg.data : "unknown reason");
460 }
461
462 /* done */
463
464 return head;
465}
466
467
468/**
469 * Write a process table to an XML file.
470 */
472 LIGOLwXMLStream *xml,
473 const ProcessTable *process
474)
475{
476 const char *row_head = "\n\t\t\t";
477
478 /* table header */
479
481 XLALFilePuts("\t<Table Name=\"process:table\">\n", xml->fp);
482 XLALFilePuts("\t\t<Column Name=\"program\" Type=\"lstring\"/>\n", xml->fp);
483 XLALFilePuts("\t\t<Column Name=\"version\" Type=\"lstring\"/>\n", xml->fp);
484 XLALFilePuts("\t\t<Column Name=\"cvs_repository\" Type=\"lstring\"/>\n", xml->fp);
485 XLALFilePuts("\t\t<Column Name=\"cvs_entry_time\" Type=\"int_4s\"/>\n", xml->fp);
486 XLALFilePuts("\t\t<Column Name=\"comment\" Type=\"lstring\"/>\n", xml->fp);
487 XLALFilePuts("\t\t<Column Name=\"is_online\" Type=\"int_4s\"/>\n", xml->fp);
488 XLALFilePuts("\t\t<Column Name=\"node\" Type=\"lstring\"/>\n", xml->fp);
489 XLALFilePuts("\t\t<Column Name=\"username\" Type=\"lstring\"/>\n", xml->fp);
490 XLALFilePuts("\t\t<Column Name=\"unix_procid\" Type=\"int_4s\"/>\n", xml->fp);
491 XLALFilePuts("\t\t<Column Name=\"start_time\" Type=\"int_4s\"/>\n", xml->fp);
492 XLALFilePuts("\t\t<Column Name=\"end_time\" Type=\"int_4s\"/>\n", xml->fp);
493 XLALFilePuts("\t\t<Column Name=\"jobid\" Type=\"int_4s\"/>\n", xml->fp);
494 XLALFilePuts("\t\t<Column Name=\"domain\" Type=\"lstring\"/>\n", xml->fp);
495 XLALFilePuts("\t\t<Column Name=\"ifos\" Type=\"lstring\"/>\n", xml->fp);
496 XLALFilePuts("\t\t<Column Name=\"process_id\" Type=\"int_8s\"/>\n", xml->fp);
497 XLALFilePuts("\t\t<Stream Name=\"process:table\" Type=\"Local\" Delimiter=\",\">", xml->fp);
498 if(XLALGetBaseErrno())
500
501 /* rows */
502
503 for(; process; process = process->next) {
504 if(XLALFilePrintf(xml->fp, "%s\"%s\",\"%s\",\"%s\",%d,\"%s\",%d,\"%s\",\"%s\",%d,%d,%d,%d,\"%s\",\"%s\",%ld",
505 row_head,
506 process->program,
507 process->version,
508 process->cvs_repository,
509 process->cvs_entry_time.gpsSeconds,
510 process->comment,
511 process->is_online,
512 process->node,
513 process->username,
514 process->unix_procid,
515 process->start_time.gpsSeconds,
516 process->end_time.gpsSeconds,
517 process->jobid,
518 process->domain,
519 process->ifos,
520 process->process_id
521 ) < 0)
523 row_head = ",\n\t\t\t";
524 }
525
526 /* table footer */
527
528 if(XLALFilePuts("\n\t\t</Stream>\n\t</Table>\n", xml->fp) < 0)
530
531 /* done */
532
533 return 0;
534}
const char * program
int XLALLIGOLwFindColumn(struct MetaioParseEnvironment *env, const char *name, unsigned int type, int required)
Convenience wrapper for MetaioFindColumn(), translating to XLAL-style error reporting and printing us...
#define LIGOMETA_COMMENT_MAX
#define LIGOMETA_USERNAME_MAX
#define LIGOMETA_CVS_REPOSITORY_MAX
#define LIGOMETA_NODE_MAX
#define LIGOMETA_VERSION_MAX
#define LIGOMETA_PROGRAM_MAX
#define LIGOMETA_DOMAIN_MAX
#define fprintf
int XLALFilePuts(const char *s, LALFILE *file)
int XLALFilePrintf(LALFILE *file, const char *fmt,...)
void * XLALMalloc(size_t n)
void XLALFree(void *p)
INT4 XLALUTCToGPS(const struct tm *utc)
#define XLAL_ERROR_NULL(...)
int XLALGetBaseErrno(void)
#define XLAL_ERROR(...)
int XLALPrintError(const char *fmt,...) _LAL_GCC_PRINTF_FORMAT_(1
int XLALClearErrno(void)
XLAL_EFUNC
XLAL_EIO
XLAL_ESYS
XLAL_EINVAL
LIGOTimeGPS * XLALGPSSet(LIGOTimeGPS *epoch, INT4 gpssec, INT8 gpsnan)
string version
filename
ProcessTable * XLALProcessTableFromLIGOLw(const char *filename)
Read the process table from a LIGO Light Weight XML file into a linked list of ProcessTable structure...
Definition: processtable.c:345
ProcessTable * XLALDestroyProcessTableRow(ProcessTable *row)
Destroy a ProcessTable structure.
Definition: processtable.c:83
ProcessTable * XLALCreateProcessTableRow(void)
Create a ProcessTable structure.
Definition: processtable.c:52
void XLALDestroyProcessTable(ProcessTable *head)
Destroy a ProcessTable linked list.
Definition: processtable.c:94
int XLALPopulateProcessTable(ProcessTable *ptable, const char *program_name, const char *cvs_revision, const char *cvs_source, const char *cvs_date, long process_id)
Populate a pre-allocated ProcessTable structure.
Definition: processtable.c:220
long XLALProcessTableGetNextID(ProcessTable *head)
Return the next available process ID.
Definition: processtable.c:104
int XLALCountProcessTable(ProcessTable *head)
Count and return the number of rows in the linked list.
Definition: processtable.c:117
int XLALWriteLIGOLwXMLProcessTable(LIGOLwXMLStream *xml, const ProcessTable *process)
Write a process table to an XML file.
Definition: processtable.c:471
static char * cvs_get_keyword_value(const char *cvs_string)
Parses a cvs keyword string in the form.
Definition: processtable.c:135
This structure contains the file stream and current table type for writing to LIGO lightweight XML fi...
Definition: LIGOLwXML.h:71
LALFILE * fp
Definition: LIGOLwXML.h:72
CHAR domain[LIGOMETA_DOMAIN_MAX]
CHAR version[LIGOMETA_VERSION_MAX]
LIGOTimeGPS start_time
CHAR ifos[LIGOMETA_IFOS_MAX]
CHAR program[LIGOMETA_PROGRAM_MAX]
struct tagProcessTable * next
LIGOTimeGPS cvs_entry_time
CHAR node[LIGOMETA_NODE_MAX]
CHAR cvs_repository[LIGOMETA_CVS_REPOSITORY_MAX]
LIGOTimeGPS end_time
CHAR username[LIGOMETA_USERNAME_MAX]
CHAR comment[LIGOMETA_COMMENT_MAX]