static int query(pid_t pid,
                 opal_pstats_t *stats,
                 opal_node_stats_t *nstats)
{
    char data[4096];
    int fd;
    size_t numchars;
    char *ptr, *eptr;
    int i;
    int len, itime;
    double dtime;
    FILE *fp;
    char *dptr, *value;
    char **fields;
    opal_diskstats_t *ds;
    opal_netstats_t *ns;

    if (NULL != stats) {
        /* record the time of this sample */
        gettimeofday(&stats->sample_time, NULL);
        /* check the nstats - don't do gettimeofday twice
         * as it is expensive
         */
        if (NULL != nstats) {
            nstats->sample_time.tv_sec = stats->sample_time.tv_sec;
            nstats->sample_time.tv_usec = stats->sample_time.tv_usec;
        }
    } else if (NULL != nstats) {
        /* record the time of this sample */
        gettimeofday(&nstats->sample_time, NULL);
    }

    if (NULL != stats) {
        /* create the stat filename for this proc */
        numchars = snprintf(data, sizeof(data), "/proc/%d/stat", pid);
        if (numchars >= sizeof(data)) {
            return OPAL_ERR_VALUE_OUT_OF_BOUNDS;
        }

        if (0 > (fd = open(data, O_RDONLY))) {
            /* can't access this file - most likely, this means we
             * aren't really on a supported system, or the proc no
             * longer exists. Just return an error
             */
            return OPAL_ERR_FILE_OPEN_FAILURE;
        }

        /* absorb all of the file's contents in one gulp - we'll process
         * it once it is in memory for speed
         */
        memset(data, 0, sizeof(data));
        len = read(fd, data, sizeof(data)-1);
        if (len < 0) {
            /* This shouldn't happen! */
            close(fd);
            return OPAL_ERR_FILE_OPEN_FAILURE;
        }
        close(fd);

        /* remove newline at end */
        data[len] = '\0';

        /* the stat file consists of a single line in a carefully formatted
         * form. Parse it field by field as per proc(3) to get the ones we want
         */

        /* we don't need to read the pid from the file - we already know it! */
        stats->pid = pid;

        /* the cmd is surrounded by parentheses - find the start */
        if (NULL == (ptr = strchr(data, '('))) {
            /* no cmd => something wrong with data, return error */
            return OPAL_ERR_BAD_PARAM;
        }
        /* step over the paren */
        ptr++;

        /* find the ending paren */
        if (NULL == (eptr = strchr(ptr, ')'))) {
            /* no end to cmd => something wrong with data, return error */
            return OPAL_ERR_BAD_PARAM;
        }

        /* save the cmd name, up to the limit of the array */
        i = 0;
        while (ptr < eptr && i < OPAL_PSTAT_MAX_STRING_LEN) {
            stats->cmd[i++] = *ptr++;
        }

        /* move to the next field in the data */
        ptr = next_field(eptr, len);

        /* next is the process state - a single character */
        stats->state[0] = *ptr;
        /* move to next field */
        ptr = next_field(ptr, len);

        /* skip fields until we get to the times */
        ptr = next_field(ptr, len); /* ppid */
        ptr = next_field(ptr, len); /* pgrp */
        ptr = next_field(ptr, len); /* session */
        ptr = next_field(ptr, len); /* tty_nr */
        ptr = next_field(ptr, len); /* tpgid */
        ptr = next_field(ptr, len); /* flags */
        ptr = next_field(ptr, len); /* minflt */
        ptr = next_field(ptr, len); /* cminflt */
        ptr = next_field(ptr, len); /* majflt */
        ptr = next_field(ptr, len); /* cmajflt */

        /* grab the process time usage fields */
        itime = strtoul(ptr, &ptr, 10);    /* utime */
        itime += strtoul(ptr, &ptr, 10);   /* add the stime */
        /* convert to time in seconds */
        dtime = (double)itime / (double)HZ;
        stats->time.tv_sec = (int)dtime;
        stats->time.tv_usec = (int)(1000000.0 * (dtime - stats->time.tv_sec));
        /* move to next field */
        ptr = next_field(ptr, len);

        /* skip fields until we get to priority */
        ptr = next_field(ptr, len); /* cutime */
        ptr = next_field(ptr, len); /* cstime */

        /* save the priority */
        stats->priority = strtol(ptr, &ptr, 10);
        /* move to next field */
        ptr = next_field(ptr, len);

        /* skip nice */
        ptr = next_field(ptr, len);

        /* get number of threads */
        stats->num_threads = strtoul(ptr, &ptr, 10);
        /* move to next field */
        ptr = next_field(ptr, len);

        /* skip fields until we get to processor id */
        ptr = next_field(ptr, len);  /* itrealvalue */
        ptr = next_field(ptr, len);  /* starttime */
        ptr = next_field(ptr, len);  /* vsize */
        ptr = next_field(ptr, len);  /* rss */
        ptr = next_field(ptr, len);  /* rss limit */
        ptr = next_field(ptr, len);  /* startcode */
        ptr = next_field(ptr, len);  /* endcode */
        ptr = next_field(ptr, len);  /* startstack */
        ptr = next_field(ptr, len);  /* kstkesp */
        ptr = next_field(ptr, len);  /* kstkeip */
        ptr = next_field(ptr, len);  /* signal */
        ptr = next_field(ptr, len);  /* blocked */
        ptr = next_field(ptr, len);  /* sigignore */
        ptr = next_field(ptr, len);  /* sigcatch */
        ptr = next_field(ptr, len);  /* wchan */
        ptr = next_field(ptr, len);  /* nswap */
        ptr = next_field(ptr, len);  /* cnswap */
        ptr = next_field(ptr, len);  /* exit_signal */

        /* finally - get the processor */
        stats->processor = strtol(ptr, NULL, 10);

        /* that's all we care about from this data - ignore the rest */

        /* now create the status filename for this proc */
        memset(data, 0, sizeof(data));
        numchars = snprintf(data, sizeof(data), "/proc/%d/status", pid);
        if (numchars >= sizeof(data)) {
            return OPAL_ERR_VALUE_OUT_OF_BOUNDS;
        }

        if (NULL == (fp = fopen(data, "r"))) {
            /* ignore this */
            return OPAL_SUCCESS;
        }

        /* parse it according to proc(3) */
        while (NULL != (dptr = local_getline(fp))) {
            if (NULL == (value = local_stripper(dptr))) {
                /* cannot process */
                continue;
            }
            /* look for VmPeak */
            if (0 == strncmp(dptr, "VmPeak", strlen("VmPeak"))) {
                stats->peak_vsize = convert_value(value);
            } else if (0 == strncmp(dptr, "VmSize", strlen("VmSize"))) {
                stats->vsize = convert_value(value);
            } else if (0 == strncmp(dptr, "VmRSS", strlen("VmRSS"))) {
                stats->rss = convert_value(value);
            }
        }
        fclose(fp);
    }

    if (NULL != nstats) {
        /* get the loadavg data */
        if (0 > (fd = open("/proc/loadavg", O_RDONLY))) {
            /* not an error if we don't find this one as it
             * isn't critical
             */
            goto diskstats;
        }

        /* absorb all of the file's contents in one gulp - we'll process
         * it once it is in memory for speed
         */
        memset(data, 0, sizeof(data));
        len = read(fd, data, sizeof(data)-1);
        close(fd);
        if (len < 0) {
            goto diskstats;
        }

        /* remove newline at end */
        data[len] = '\0';

        /* we only care about the first three numbers */
        nstats->la = strtof(data, &ptr);
        nstats->la5 = strtof(ptr, &eptr);
        nstats->la15 = strtof(eptr, NULL);

        /* see if we can open the meminfo file */
        if (NULL == (fp = fopen("/proc/meminfo", "r"))) {
            /* ignore this */
            goto diskstats;
        }

        /* read the file one line at a time */
        while (NULL != (dptr = local_getline(fp))) {
            if (NULL == (value = local_stripper(dptr))) {
                /* cannot process */
                continue;
            }
            if (0 == strcmp(dptr, "MemTotal")) {
                nstats->total_mem = convert_value(value);
            } else if (0 == strcmp(dptr, "MemFree")) {
                nstats->free_mem = convert_value(value);
            } else if (0 == strcmp(dptr, "Buffers")) {
                nstats->buffers = convert_value(value);
            } else if (0 == strcmp(dptr, "Cached")) {
                nstats->cached = convert_value(value);
            } else if (0 == strcmp(dptr, "SwapCached")) {
                nstats->swap_cached = convert_value(value);
            } else if (0 == strcmp(dptr, "SwapTotal")) {
                nstats->swap_total = convert_value(value);
            } else if (0 == strcmp(dptr, "SwapFree")) {
                nstats->swap_free = convert_value(value);
            } else if (0 == strcmp(dptr, "Mapped")) {
                nstats->mapped = convert_value(value);
            }
        }
        fclose(fp);

    diskstats:
        /* look for the diskstats file */
        if (NULL == (fp = fopen("/proc/diskstats", "r"))) {
            /* not an error if we don't find this one as it
             * isn't critical
             */
            goto netstats;
        }
        /* read the file one line at a time */
        while (NULL != (dptr = local_getline(fp))) {
            /* look for the local disks */
            if (NULL == strstr(dptr, "sd")) {
                continue;
            }
            /* parse to extract the fields */
            fields = NULL;
            local_getfields(dptr, &fields);
            if (NULL == fields) {
                continue;
            }
            if (14 < opal_argv_count(fields)) {
                opal_argv_free(fields);
                continue;
            }
            /* pack the ones of interest into the struct */
            ds = OBJ_NEW(opal_diskstats_t);
            ds->disk = strdup(fields[2]);
            ds->num_reads_completed = strtoul(fields[3], NULL, 10);
            ds->num_reads_merged = strtoul(fields[4], NULL, 10);
            ds->num_sectors_read = strtoul(fields[5], NULL, 10);
            ds->milliseconds_reading = strtoul(fields[6], NULL, 10);
            ds->num_writes_completed = strtoul(fields[7], NULL, 10);
            ds->num_writes_merged = strtoul(fields[8], NULL, 10);
            ds->num_sectors_written = strtoul(fields[9], NULL, 10);
            ds->milliseconds_writing = strtoul(fields[10], NULL, 10);
            ds->num_ios_in_progress = strtoul(fields[11], NULL, 10);
            ds->milliseconds_io = strtoul(fields[12], NULL, 10);
            ds->weighted_milliseconds_io = strtoul(fields[13], NULL, 10);
            opal_list_append(&nstats->diskstats, &ds->super);
            opal_argv_free(fields);
        }
        fclose(fp);

    netstats:
        /* look for the netstats file */
        if (NULL == (fp = fopen("/proc/net/dev", "r"))) {
            /* not an error if we don't find this one as it
             * isn't critical
             */
            goto complete;
        }
        /* skip the first two lines as they are headers */
        local_getline(fp);
        local_getline(fp);
        /* read the file one line at a time */
        while (NULL != (dptr = local_getline(fp))) {
            /* the interface is at the start of the line */
            if (NULL == (ptr = strchr(dptr, ':'))) {
                continue;
            }
            *ptr = '\0';
            ptr++;
            /* parse to extract the fields */
            fields = NULL;
            local_getfields(ptr, &fields);
            if (NULL == fields) {
                continue;
            }
            /* pack the ones of interest into the struct */
            ns = OBJ_NEW(opal_netstats_t);
            ns->net_interface = strdup(dptr);
            ns->num_bytes_recvd = strtoul(fields[0], NULL, 10);
            ns->num_packets_recvd = strtoul(fields[1], NULL, 10);
            ns->num_recv_errs = strtoul(fields[2], NULL, 10);
            ns->num_bytes_sent = strtoul(fields[8], NULL, 10);
            ns->num_packets_sent = strtoul(fields[9], NULL, 10);
            ns->num_send_errs = strtoul(fields[10], NULL, 10);
            opal_list_append(&nstats->netstats, &ns->super);
            opal_argv_free(fields);
        }
        fclose(fp);
    }

 complete:
    return OPAL_SUCCESS;
}
static int linux_module_init(void)
{
    FILE *fp;
    char *data, *value, *ptr;

    /* see if we can open the cpuinfo file */
    if (NULL == (fp = fopen("/proc/cpuinfo", "r"))) {
        /* can't access this file - most likely, this means we
         * aren't really on a supported system, or the proc no
         * longer exists. Just return an error
         */
        return OPAL_ERR_NOT_SUPPORTED;
    }
    
    /* read the file one line at a time */
    while (NULL != (data = local_getline(fp))) {
        if (NULL == (value = local_stripper(data))) {
            /* cannot process */
            continue;
        }
        if (NULL == cpu_type && 0 == strcmp(data, "vendor_id")) {
            cpu_type = strdup(value);
            continue;
        }
        if (NULL == cpu_model && 0 == strcmp(data, "model name")) {
            cpu_model = strdup(value);
        }
        if (0 == strcmp(data, "processor")) {
            /* increment the num_cpus */
            ++num_cpus;
        }
    }
    fclose(fp);

    /* see if we can open the meminfo file */
    if (NULL == (fp = fopen("/proc/meminfo", "r"))) {
        /* ignore this */
        return OPAL_SUCCESS;
    }
    
    /* read the file one line at a time */
    while (NULL != (data = local_getline(fp))) {
        if (NULL == (value = local_stripper(data))) {
            /* cannot process */
            continue;
        }
        if (0 == strcmp(data, "MemTotal")) {
            /* find units */
            ptr = &value[strlen(value)-2];
            value[strlen(value)-3] = '\0';
            /* compute base value */
            mem_size = strtol(value, NULL, 10);
            /* get the unit multiplier */
            if (0 == strcmp(ptr, "kB")) {
                mem_size = mem_size / 1024;
            }
            continue;
        }
    }
    fclose(fp);
    
    return OPAL_SUCCESS;
}