darshan-logutils.c 47.9 KB
Newer Older
1
/*
Shane Snyder's avatar
Shane Snyder committed
2 3 4
 * Copyright (C) 2015 University of Chicago.
 * See COPYRIGHT notice in top-level directory.
 *
5 6
 */

7
#define _GNU_SOURCE
8
#include "darshan-util-config.h"
9 10
#include <stdio.h>
#include <string.h>
11
#include <assert.h>
12
#include <stdlib.h>
13
#include <unistd.h>
14
#include <inttypes.h>
15 16 17
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
18
#include <errno.h>
19

20 21
#include "darshan-logutils.h"

22 23 24
/* default input buffer size for decompression algorithm */
#define DARSHAN_DEF_COMP_BUF_SZ (1024*1024) /* 1 MiB */

25
/* special identifers for referring to header, job, and
26 27 28 29
 * record map regions of the darshan log file
 */
#define DARSHAN_HEADER_REGION_ID    (-3)
#define DARSHAN_JOB_REGION_ID       (-2)
30
#define DARSHAN_NAME_MAP_REGION_ID  (-1)
31

32 33
struct darshan_dz_state
{
34 35 36 37 38
    /* pointer to arbitrary data structure used for managing
     * compression/decompression state (e.g., z_stream
     * structure needed for libz)
     */
    void *comp_dat;
39 40 41
    /* buffer for staging compressed data to/from log file */
    unsigned char *buf;
    /* size of staging buffer */
42
    unsigned int size;
43 44
    /* for reading logs, flag indicating end of log file region */
    int eor;
45
    /* the region id we last tried reading/writing */
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
    int prev_reg_id;
};

/* internal fd data structure */
struct darshan_fd_int_state
{
    /* posix file descriptor for the log file */
    int fildes;
    /* file pointer position */
    int64_t pos;
    /* flag indicating whether log file was created (and written) */
    int creat_flag;
    /* log file path name */
    char logfile_path[PATH_MAX];
    /* pointer to exe & mount data in darshan job data structure */
    char *exe_mnt_data;
    /* whether previous file operations have failed */
    int err;

65
    /* compression/decompression stream read/write state */
66 67 68
    struct darshan_dz_state dz;
};

69 70
static int darshan_log_get_header(darshan_fd fd);
static int darshan_log_put_header(darshan_fd fd);
71 72
static int darshan_log_seek(darshan_fd fd, off_t offset);
static int darshan_log_read(darshan_fd fd, void *buf, int len);
73
static int darshan_log_write(darshan_fd fd, void *buf, int len);
74 75
static int darshan_log_dzinit(darshan_fd fd);
static void darshan_log_dzdestroy(darshan_fd fd);
76 77
static int darshan_log_dzread(darshan_fd fd, int region_id, void *buf, int len);
static int darshan_log_dzwrite(darshan_fd fd, int region_id, void *buf, int len);
78 79 80 81
static int darshan_log_libz_read(darshan_fd fd, struct darshan_log_map map, 
    void *buf, int len, int reset_strm_flag);
static int darshan_log_libz_write(darshan_fd fd, struct darshan_log_map *map_p,
    void *buf, int len, int flush_strm_flag);
82
static int darshan_log_libz_flush(darshan_fd fd, int region_id);
83
#ifdef HAVE_LIBBZ2
84 85 86 87
static int darshan_log_bzip2_read(darshan_fd fd, struct darshan_log_map map, 
    void *buf, int len, int reset_strm_flag);
static int darshan_log_bzip2_write(darshan_fd fd, struct darshan_log_map *map_p,
    void *buf, int len, int flush_strm_flag);
88 89
static int darshan_log_bzip2_flush(darshan_fd fd, int region_id);
#endif
90 91
static int darshan_log_dzload(darshan_fd fd, struct darshan_log_map map);
static int darshan_log_dzunload(darshan_fd fd, struct darshan_log_map *map_p);
92 93
static int darshan_log_noz_read(darshan_fd fd, struct darshan_log_map map,
    void *buf, int len, int reset_strm_flag);
94

Shane Snyder's avatar
Shane Snyder committed
95
/* each module's implementation of the darshan logutil functions */
96
#define X(a, b, c, d) d,
97 98
struct darshan_mod_logutil_funcs *mod_logutils[DARSHAN_MAX_MODS] =
{
Shane Snyder's avatar
Shane Snyder committed
99
    DARSHAN_MODULE_IDS
100
};
Shane Snyder's avatar
Shane Snyder committed
101
#undef X
102 103 104

/* darshan_log_open()
 *
105
 * open an existing darshan log file for reading only
106
 *
107
 * returns file descriptor on success, NULL on failure
108
 */
109
darshan_fd darshan_log_open(const char *name)
110
{
111
    darshan_fd tmp_fd;
112
    int ret;
113

114
    /* allocate a darshan file descriptor */
115 116 117 118
    tmp_fd = malloc(sizeof(*tmp_fd));
    if(!tmp_fd)
        return(NULL);
    memset(tmp_fd, 0, sizeof(*tmp_fd));
119 120 121 122 123 124 125
    tmp_fd->state = malloc(sizeof(struct darshan_fd_int_state));
    if(!tmp_fd->state)
    {
        free(tmp_fd->state);
        return(NULL);
    }
    memset(tmp_fd->state, 0, sizeof(struct darshan_fd_int_state));
126

127
    /* open the log file in read mode */
128 129
    tmp_fd->state->fildes = open(name, O_RDONLY);
    if(tmp_fd->state->fildes < 0)
130
    {
131
        fprintf(stderr, "Error: failed to open darshan log file %s.\n", name);
132
        free(tmp_fd->state);
133 134 135
        free(tmp_fd);
        return(NULL);
    }
136
    strncpy(tmp_fd->state->logfile_path, name, PATH_MAX);
137 138

    /* read the header from the log file to init fd data structures */
139
    ret = darshan_log_get_header(tmp_fd);
140 141
    if(ret < 0)
    {
142
        fprintf(stderr, "Error: failed to read darshan log file header.\n");
143 144
        close(tmp_fd->state->fildes);
        free(tmp_fd->state);
145
        free(tmp_fd);
146 147 148 149
        return(NULL);
    }

    /* initialize compression data structures */
150
    ret = darshan_log_dzinit(tmp_fd);
151 152 153
    if(ret < 0)
    {
        fprintf(stderr, "Error: failed to initialize decompression data structures.\n");
154 155
        close(tmp_fd->state->fildes);
        free(tmp_fd->state);
156 157
        free(tmp_fd);
        return(NULL);
158 159
    }

160 161 162 163 164 165 166
    return(tmp_fd);
}

/* darshan_log_create()
 *
 * create a darshan log file for writing with the given compression method
 *
167
 * returns file descriptor on success, NULL on failure
168
 */
169 170
darshan_fd darshan_log_create(const char *name, enum darshan_comp_type comp_type,
    int partial_flag)
171 172
{
    darshan_fd tmp_fd;
173
    int ret;
174

175
    /* allocate a darshan file descriptor */
176 177 178 179
    tmp_fd = malloc(sizeof(*tmp_fd));
    if(!tmp_fd)
        return(NULL);
    memset(tmp_fd, 0, sizeof(*tmp_fd));
180 181 182 183 184 185 186
    tmp_fd->state = malloc(sizeof(struct darshan_fd_int_state));
    if(!tmp_fd->state)
    {
        free(tmp_fd);
        return(NULL);
    }
    memset(tmp_fd->state, 0, sizeof(struct darshan_fd_int_state));
187
    tmp_fd->comp_type = comp_type;
188

189 190 191
    /* create the log for writing, making sure to not overwrite existing log */
    tmp_fd->state->fildes = creat(name, 0400);
    if(tmp_fd->state->fildes < 0)
192
    {
193
        fprintf(stderr, "Error: failed to open darshan log file %s.\n", name);
194
        free(tmp_fd->state);
195
        free(tmp_fd);
196
        return(NULL);
197
    }
198
    tmp_fd->state->creat_flag = 1;
199
    tmp_fd->partial_flag = partial_flag;
200
    strncpy(tmp_fd->state->logfile_path, name, PATH_MAX);
201

202 203 204 205 206
    /* position file pointer to prealloc space for the log file header
     * NOTE: the header is written at close time, after all internal data
     * structures have been properly set
     */
    ret = darshan_log_seek(tmp_fd, sizeof(struct darshan_header));
207
    if(ret < 0)
208 209
    {
        fprintf(stderr, "Error: unable to seek in darshan log file.\n");
210 211
        close(tmp_fd->state->fildes);
        free(tmp_fd->state);
212 213 214
        free(tmp_fd);
        unlink(name);
        return(NULL);
215 216
    }

217
    /* initialize compression data structures */
218
    ret = darshan_log_dzinit(tmp_fd);
219 220
    if(ret < 0)
    {
221
        fprintf(stderr, "Error: failed to initialize compression data structures.\n");
222 223
        close(tmp_fd->state->fildes);
        free(tmp_fd->state);
224 225 226
        free(tmp_fd);
        unlink(name);
        return(NULL);
227 228
    }

229
    return(tmp_fd);
230 231
}

232
/* darshan_log_get_job()
233 234
 *
 * read job level metadata from the darshan log file
235
 *
236
 * returns 0 on success, -1 on failure
237
 */
238
int darshan_log_get_job(darshan_fd fd, struct darshan_job *job)
239
{
240
    struct darshan_fd_int_state *state = fd->state;
241 242
    char job_buf[DARSHAN_JOB_RECORD_SIZE] = {0};
    int job_buf_sz = DARSHAN_JOB_RECORD_SIZE;
243
    int ret;
244

245
    assert(state);
246 247
    assert(fd->job_map.len > 0 && fd->job_map.off > 0);

248
    /* read the compressed job data from the log file */
249
    ret = darshan_log_dzread(fd, DARSHAN_JOB_REGION_ID, job_buf, job_buf_sz);
250
    if(ret <= (int)sizeof(*job))
251
    {
252
        fprintf(stderr, "Error: failed to read darshan log file job data.\n");
253 254
        return(-1);
    }
255 256

    memcpy(job, job_buf, sizeof(*job));
257

258
    if(fd->swap_flag)
259
    {
260 261 262 263 264 265
        /* swap bytes if necessary */
        DARSHAN_BSWAP64(&job->uid);
        DARSHAN_BSWAP64(&job->start_time);
        DARSHAN_BSWAP64(&job->end_time);
        DARSHAN_BSWAP64(&job->nprocs);
        DARSHAN_BSWAP64(&job->jobid);
266 267
    }

268
    /* save trailing exe & mount information, so it can be retrieved later */
269 270 271
    if(!(state->exe_mnt_data))
        state->exe_mnt_data = malloc(DARSHAN_EXE_LEN+1);
    if(!(state->exe_mnt_data))
272
        return(-1);
273
    memcpy(state->exe_mnt_data, &job_buf[sizeof(*job)], DARSHAN_EXE_LEN+1);
274

275 276 277
    return(0);
}

278
/* darshan_log_put_job()
279
 *
280
 * write job level metadata to darshan log file
281 282 283
 *
 * returns 0 on success, -1 on failure
 */
284
int darshan_log_put_job(darshan_fd fd, struct darshan_job *job)
285
{
286
    struct darshan_fd_int_state *state = fd->state;
287 288 289 290
    struct darshan_job job_copy;
    int len;
    int ret;

291 292
    assert(state);

293 294 295 296 297 298 299 300 301 302 303 304 305 306
    memset(&job_copy, 0, sizeof(*job));
    memcpy(&job_copy, job, sizeof(*job));

    /* check for newline in existing metadata, add if needed */
    len = strlen(job_copy.metadata);
    if(len > 0 && len < DARSHAN_JOB_METADATA_LEN)
    {
        if(job_copy.metadata[len-1] != '\n')
        {
            job_copy.metadata[len] = '\n';
            job_copy.metadata[len+1] = '\0';
        }
    }

307 308
    /* write the compressed job data to log file */
    ret = darshan_log_dzwrite(fd, DARSHAN_JOB_REGION_ID, &job_copy, sizeof(*job));
309
    if(ret != sizeof(*job))
310
    {
311
        state->err = -1;
312 313 314 315 316 317 318
        fprintf(stderr, "Error: failed to write darshan log file job data.\n");
        return(-1);
    }

    return(0);
}

319
/* darshan_log_get_exe()
320 321 322 323 324
 *
 * reads the application exe name from darshan log file
 * 
 * returns 0 on success, -1 on failure 
 */
325
int darshan_log_get_exe(darshan_fd fd, char *buf)
326
{
327
    struct darshan_fd_int_state *state = fd->state;
328
    char *newline;
329
    int ret;
330

331 332
    assert(state);

333
    /* if the exe/mount data has not been saved yet, read in the job info */
334
    if(!(state->exe_mnt_data))
335
    {
336
        struct darshan_job job;
337
        ret = darshan_log_get_job(fd, &job);
338

339
        if(ret < 0 || !(state->exe_mnt_data))
340
            return(-1);
341
    }
342

343
    /* exe string is located before the first line break */
344
    newline = strchr(state->exe_mnt_data, '\n');
345 346

    /* copy over the exe string */
347
    if(newline)
348
        memcpy(buf, state->exe_mnt_data, (newline - state->exe_mnt_data));
349 350 351 352

    return (0);
}

353
/* darshan_log_put_exe()
354 355
 *
 * wrties the application exe name to darshan log file
356
 * NOTE: this needs to be called immediately following put_job as it
357
 * expects the file pointer to be positioned immediately following
358
 * the darshan job information
359 360 361
 *
 * returns 0 on success, -1 on failure 
 */
362
int darshan_log_put_exe(darshan_fd fd, char *buf)
363
{
364 365
    struct darshan_fd_int_state *state = fd->state;
    int len = strlen(buf);
366
    int ret;
367

368
    assert(fd->state);
369

370 371
    ret = darshan_log_dzwrite(fd, DARSHAN_JOB_REGION_ID, buf, len);
    if(ret != len)
372
    {
373
        state->err = -1;
374 375 376 377 378 379 380
        fprintf(stderr, "Error: failed to write exe string to darshan log file.\n");
        return(-1);
    }

    return(0);
}

381
/* darshan_log_get_mounts()
382
 * 
383
 * retrieves mount table information from the log. Note that mnt_pts and
384
 * fs_types are arrays that will be allocated by the function and must be
385 386 387
 * freed by the caller. count will indicate the size of the arrays
 *
 * returns 0 on success, -1 on failure
388
 */
389
int darshan_log_get_mounts(darshan_fd fd, char*** mnt_pts,
390 391
    char*** fs_types, int* count)
{
392
    struct darshan_fd_int_state *state = fd->state;
393 394
    char *pos;
    int array_index = 0;
395
    int ret;
396

397 398
    assert(state);

399
    /* if the exe/mount data has not been saved yet, read in the job info */
400
    if(!(state->exe_mnt_data))
401
    {
402
        struct darshan_job job;
403
        ret = darshan_log_get_job(fd, &job);
404

405
        if(ret < 0 || !(state->exe_mnt_data))
406
            return(-1);
407
    }
408

409
    /* count entries */
410
    *count = 0;
411
    pos = state->exe_mnt_data;
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
    while((pos = strchr(pos, '\n')) != NULL)
    {
        pos++;
        (*count)++;
    }

    if(*count == 0)
    {
        /* no mount entries present */
        return(0);
    }

    /* allocate output arrays */
    *mnt_pts = malloc((*count)*sizeof(char*));
    assert(*mnt_pts);
    *fs_types = malloc((*count)*sizeof(char*));
    assert(*fs_types);

    /* work backwards through the table and parse each line (except for
     * first, which holds command line information)
     */
433
    while((pos = strrchr(state->exe_mnt_data, '\n')) != NULL)
434 435
    {
        /* overestimate string lengths */
436
        (*mnt_pts)[array_index] = malloc(DARSHAN_EXE_LEN);
437
        assert((*mnt_pts)[array_index]);
438
        (*fs_types)[array_index] = malloc(DARSHAN_EXE_LEN);
439 440
        assert((*fs_types)[array_index]);

441 442 443
        ret = sscanf(++pos, "%s\t%s", (*fs_types)[array_index],
            (*mnt_pts)[array_index]);
        if(ret != 2)
444
        {
445
            fprintf(stderr, "Error: poorly formatted mount table in darshan log file.\n");
446 447 448 449 450 451 452
            return(-1);
        }
        pos--;
        *pos = '\0';
        array_index++;
    }

453 454 455
    return(0);
}

456
/* darshan_log_put_mounts()
457 458 459 460 461 462 463 464
 *
 * writes mount information to the darshan log file
 * NOTE: this function call should follow immediately after the call
 * to darshan_log_putexe(), as it assumes the darshan log file pointer
 * is pointing to the offset immediately following the exe string
 *
 * returns 0 on success, -1 on failure
 */
465
int darshan_log_put_mounts(darshan_fd fd, char** mnt_pts, char** fs_types, int count)
466
{
467
    struct darshan_fd_int_state *state = fd->state;
468 469
    int i;
    char line[1024];
470 471 472
    char mnt_dat[DARSHAN_EXE_LEN] = {0};
    int mnt_dat_sz = 0;
    char *tmp;
473 474
    int ret;

475 476
    assert(state);

477
    /* write each mount entry to file */
478
    tmp = mnt_dat;
479 480 481
    for(i=count-1; i>=0; i--)
    {
        sprintf(line, "\n%s\t%s", fs_types[i], mnt_pts[i]);
482 483 484 485 486 487

        memcpy(tmp, line, strlen(line));
        tmp += strlen(line);
        mnt_dat_sz += strlen(line);
    }

488 489
    ret = darshan_log_dzwrite(fd, DARSHAN_JOB_REGION_ID, mnt_dat, mnt_dat_sz);
    if (ret != mnt_dat_sz)
490
    {
491
        state->err = -1;
492
        fprintf(stderr, "Error: failed to write darshan log mount data.\n");
493 494 495 496 497 498
        return(-1);
    }

    return(0);
}

499
/* darshan_log_get_namehash()
500
 *
501
 * read the hash of name records from the darshan log file
502 503 504
 *
 * returns 0 on success, -1 on failure
 */
505
int darshan_log_get_namehash(darshan_fd fd, struct darshan_name_record_ref **hash)
506
{
507
    struct darshan_fd_int_state *state = fd->state;
508
    char *name_rec_buf;
509
    char *tmp_p;
510
    int name_rec_buf_sz;
511 512
    int read;
    int read_req_sz;
513 514
    struct darshan_name_record_ref *ref;
    struct darshan_name_record *name_rec;
515
    int buf_rem = 0;
516
    int rec_len;
517

518 519
    assert(state);

520 521
    /* just return if there is no name record mapping data */
    if(fd->name_map.len == 0)
522 523 524 525 526
    {
        *hash = NULL;
        return(0);
    }

527 528 529 530
    /* default to buffer twice as big as default compression buf */
    name_rec_buf_sz = DARSHAN_DEF_COMP_BUF_SZ * 2;
    name_rec_buf = malloc(name_rec_buf_sz);
    if(!name_rec_buf)
531
        return(-1);
532
    memset(name_rec_buf, 0, name_rec_buf_sz);
533

534
    do
535
    {
536
        /* read chunks of the darshan record id -> name mapping from log file,
537
         * constructing a hash table in the process
538
         */
539 540 541
        read_req_sz = name_rec_buf_sz - buf_rem;
        read = darshan_log_dzread(fd, DARSHAN_NAME_MAP_REGION_ID,
            name_rec_buf + buf_rem, read_req_sz);
542
        if(read < 0)
543
        {
544 545
            fprintf(stderr, "Error: failed to read name hash from darshan log file.\n");
            free(name_rec_buf);
546
            return(-1);
547
        }
548
        buf_rem += read;
549

550
        /* work through the name record buffer -- deserialize the mapping data and
551 552 553 554
         * add to the output hash table
         * NOTE: these mapping pairs are variable in length, so we have to be able
         * to handle incomplete mappings temporarily here
         */
555 556
        name_rec = (struct darshan_name_record *)name_rec_buf;
        while(buf_rem > sizeof(darshan_record_id) + 1)
557
        {
558 559
            if(strnlen(name_rec->name, buf_rem - sizeof(darshan_record_id)) ==
                (buf_rem - sizeof(darshan_record_id)))
560
            {
561 562 563
                /* if this record name's terminating null character is not
                 * present, we need to read more of the buffer before continuing
                 */
564
                break;
565
            }
566 567

            if(fd->swap_flag)
568
            {
569
                /* we need to sort out endianness issues before deserializing */
570
                DARSHAN_BSWAP64(&(name_rec->id));
571
            }
572

573
            HASH_FIND(hlink, *hash, &(name_rec->id), sizeof(darshan_record_id), ref);
574
            if(!ref)
575
            {
576
                rec_len = sizeof(darshan_record_id) + strlen(name_rec->name) + 1;
577 578 579
                ref = malloc(sizeof(*ref));
                if(!ref)
                {
580
                    free(name_rec_buf);
581 582
                    return(-1);
                }
583 584
                ref->name_record = malloc(rec_len);
                if(!ref->name_record)
585 586
                {
                    free(ref);
587
                    free(name_rec_buf);
588 589 590
                    return(-1);
                }

591 592
                /* copy the name record over from the hash buffer */
                memcpy(ref->name_record, name_rec, rec_len);
593 594

                /* add this record to the hash */
595
                HASH_ADD(hlink, *hash, name_record->id, sizeof(darshan_record_id), ref);
596 597
            }

598 599 600
            tmp_p = (char *)name_rec + rec_len;
            name_rec = (struct darshan_name_record *)tmp_p;
            buf_rem -= rec_len;
601
        }
602

603
        /* copy any leftover data to beginning of buffer to parse next */
604
        memcpy(name_rec_buf, name_rec, buf_rem);
605 606 607 608 609

        /* we keep reading until we get a short read informing us we have
         * read all of the record hash
         */
    } while(read == read_req_sz);
610
    assert(buf_rem == 0);
611

612
    free(name_rec_buf);
613 614 615
    return(0);
}

616
/* darshan_log_put_namehash()
617
 *
618
 * writes the hash table of name records to the darshan log file
619 620 621
 * NOTE: this function call should follow immediately after the call
 * to darshan_log_putmounts(), as it assumes the darshan log file pointer
 * is pointing to the offset immediately following the mount information
622 623 624
 *
 * returns 0 on success, -1 on failure
 */
625
int darshan_log_put_namehash(darshan_fd fd, struct darshan_name_record_ref *hash)
626
{
627
    struct darshan_fd_int_state *state = fd->state;
628 629 630
    struct darshan_name_record_ref *ref, *tmp;
    struct darshan_name_record_ref *name_rec;
    int name_rec_len;
631
    int wrote;
632

633 634
    assert(state);

635
    /* allocate memory for largest possible hash record */
636 637
    name_rec = malloc(sizeof(struct darshan_name_record) + PATH_MAX);
    if(!name_rec)
638
        return(-1);
639
    memset(name_rec, 0, sizeof(struct darshan_name_record) + PATH_MAX);
640

641
    /* individually serialize each hash record and write to log file */
642 643
    HASH_ITER(hlink, hash, ref, tmp)
    {
644 645
        name_rec_len = sizeof(struct darshan_name_record) + strlen(ref->name_record->name);
        memcpy(name_rec, ref->name_record, name_rec_len);
646

647
        /* write this hash entry to log file */
648 649 650
        wrote = darshan_log_dzwrite(fd, DARSHAN_NAME_MAP_REGION_ID,
            name_rec, name_rec_len);
        if(wrote != name_rec_len)
651
        {
652
            state->err = -1;
653 654
            fprintf(stderr, "Error: failed to write name hash to darshan log file.\n");
            free(name_rec);
655 656
            return(-1);
        }
657 658
    }

659
    free(name_rec);
660 661 662
    return(0);
}

663
/* darshan_log_get_mod()
664
 *
665 666
 * get a chunk of module data from the darshan log file
 *
667
 * returns number of bytes read on success, -1 on failure
668
 */
669
int darshan_log_get_mod(darshan_fd fd, darshan_module_id mod_id,
670
    void *mod_buf, int mod_buf_sz)
671
{
672
    struct darshan_fd_int_state *state = fd->state;
673
    int ret;
674

675 676
    assert(state);

677
    if(mod_id < 0 || mod_id >= DARSHAN_MAX_MODS)
678
    {
679 680
        fprintf(stderr, "Error: invalid Darshan module id.\n");
        return(-1);
681 682
    }

683 684 685 686
    if(fd->mod_map[mod_id].len == 0)
        return(0); /* no data corresponding to this mod_id */

    /* read this module's data from the log file */
687
    ret = darshan_log_dzread(fd, mod_id, mod_buf, mod_buf_sz);
688
    if(ret < 0)
689
    {
690
        fprintf(stderr,
691
            "Error: failed to read module %s data from darshan log file.\n",
692
            darshan_module_names[mod_id]);
693 694 695
        return(-1);
    }

696
    return(ret);
697 698
}

699
/* darshan_log_put_mod()
700 701
 *
 * write a chunk of module data to the darshan log file
Shane Snyder's avatar
Shane Snyder committed
702 703 704 705 706 707
 * NOTE: this function call should be called directly after the
 * put_hash() function, as it expects the file pointer to be
 * positioned directly past the record hash location. Also,
 * for a set of modules with data to write to file, this function
 * should be called in order of increasing module identifiers,
 * as the darshan log file format expects this ordering.
708
 *
709
 * returns number of bytes written on success, -1 on failure
710
 */
711
int darshan_log_put_mod(darshan_fd fd, darshan_module_id mod_id,
712
    void *mod_buf, int mod_buf_sz, int ver)
713
{
714
    struct darshan_fd_int_state *state = fd->state;
715 716
    int ret;

717 718
    assert(state);

Shane Snyder's avatar
Shane Snyder committed
719
    if(mod_id < 0 || mod_id >= DARSHAN_MAX_MODS)
720
    {
721
        state->err = -1;
Shane Snyder's avatar
Shane Snyder committed
722 723
        fprintf(stderr, "Error: invalid Darshan module id.\n");
        return(-1);
724 725 726
    }

    /* write the module chunk to the log file */
727 728
    ret = darshan_log_dzwrite(fd, mod_id, mod_buf, mod_buf_sz);
    if(ret != mod_buf_sz)
729
    {
730
        state->err = -1;
731 732 733 734 735 736
        fprintf(stderr,
            "Error: failed to write module %s data to darshan log file.\n",
            darshan_module_names[mod_id]);
        return(-1);
    }

737 738 739
    /* set the version number for this module's data */
    fd->mod_ver[mod_id] = ver;

740 741 742
    return(0);
}

743 744
/* darshan_log_close()
 *
745
 * close an open darshan file descriptor, freeing any resources
746 747 748
 *
 */
void darshan_log_close(darshan_fd fd)
749
{
750
    struct darshan_fd_int_state *state = fd->state;
751 752
    int ret;

753 754 755 756
    assert(state);

    /* if the file was created for writing */
    if(state->creat_flag)
757 758
    {
        /* flush the last region of the log to file */
759
        switch(fd->comp_type)
760 761
        {
            case DARSHAN_ZLIB_COMP:
762
                ret = darshan_log_libz_flush(fd, state->dz.prev_reg_id);
763 764
                if(ret == 0)
                    break;
765 766
#ifdef HAVE_LIBBZ2
            case DARSHAN_BZIP2_COMP:
767
                ret = darshan_log_bzip2_flush(fd, state->dz.prev_reg_id);
768 769 770
                if(ret == 0)
                    break;
#endif 
771 772
            default:
                /* if flush fails, remove the output log file */
773
                state->err = -1;
774 775 776 777 778
                fprintf(stderr, "Error: final flush to log file failed.\n");