#include "pamc_private.h"

/*
 * Copyright (c) 1998 Andrew G. Morgan <morgan@linux.kernel.org>
 * All rights reserved.
 *
 * The license for this source code should accompany this file.  Its
 * md5 checksum is: cac41ac118b52c96cf248baec7237381
 */

static const char copyright[] =
"Copyright (c) 1998 Andrew G. Morgan <morgan@linux.kernel.org>";

/*
 * This file contains functions that are independent of the agent
 * handle and packet structures.  These functions are of use to both
 * clients, and agents.
 */

void pamc_scrub(void **data, int length)
{
    D(("called"));
    memset(*data, 0, length);
    free(*data);
    *data = NULL;
    D(("done"));
}

/*
 * shovel data into the pipe and don't return until it has all been
 * sent unless there is a fatal error.
 */

int pamc_push_data(int fd, const void *data, int length)
{
    const unsigned char *d = data;

    D(("called, sennding %d bytes", length));
    while (length > 0) {
	int retval;

	retval = write(fd, d, length);
	if (retval == -1) {
	    if (errno == EINTR) {
		continue;
	    } else {
		D(("errno %s encountered (%d bytes unwritten)",
		   strerror(errno), length));
		return PAMC_CONTROL_ABORT;
	    }
	} else if (retval == 0) {
	    D(("failed to write (%d bytes unwritten)", length));
	    return PAMC_CONTROL_ABORT;
	}

	d += retval;
	length -= retval;
    }

    D(("all bytes written"));
    return PAMC_CONTROL_OK;
}

/*
 * Drain data from the pipe, we want a certain amount so unless we
 * suffer an error, loop until we have it all.
 */

int pamc_pull_data(int fd, void *data, int length)
{
    unsigned char *d = data;

    D(("called, requesting %d bytes", length));
    while (length > 0) {
	int retval;

	retval = read(fd, data, length);
	if (retval == -1) {
	    if (errno == EINTR) {
		continue;
	    } else {
		D(("errno %s encountered (%d bytes unread)",
		   strerror(errno), length));
		return PAMC_CONTROL_ABORT;
	    }
	} else if (retval == 0) {
	    D(("no data left (%d bytes unread)", length));
	    return PAMC_CONTROL_ABORT;
	}

	d += retval;
	length -= retval;
    }

    D(("all bytes read"));
    return PAMC_CONTROL_OK;
}

/*
 * This is a simple check to see if there is anything waiting to be
 * read from the specified file descriptor.
 */

int pamc_silent_fd(int fd)
{
    int retval;
    fd_set readers;
    struct timeval timeout;

    D(("called."));
    FD_ZERO(&readers);
    FD_SET(fd, &readers);
    timeout.tv_sec = 0;
    timeout.tv_usec = 0;
    do {
	retval = select(fd+1, &readers, NULL, NULL, &timeout);
    } while (retval == -1 && errno == EINTR);
    if (retval > 0 && FD_ISSET(fd, &readers)) {
	D(("file has data waiting"));
	return PAMC_CONTROL_FAIL;
    }
    D(("file has no data waiting"));
    return PAMC_CONTROL_OK;
}

