/*
 * $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 *
 */

/*	Copyright (c) 1984 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

#ident	"$Header: files.c 1.2 89/10/10 $@(#)nlp:lib/lp/files.c	1.7"
/* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */

#include "stdio.h"
#include "fcntl.h"
#include "string.h"
#include "errno.h"
#include "pwd.h"
#include "sys/types.h"
#include "sys/stat.h"

#include "lp.h"

extern char		*malloc();

extern struct passwd	*getpwnam();

extern void		endpwent();

/**
 ** open_lpfile() - OPEN AND LOCK A FILE; REUSE STATIC BUFFER
 ** close_lpfile() - CLOSE FILE; RELEASE STATIC BUFFER
 **/

#define	MAX_NOFILES	100	/* current max. setting of NOFILES */

static struct buffers {
	FILE			*fp;
	char			*buffer;
}			buffers[MAX_NOFILES];

/*VARARGS2*/
FILE			*open_lpfile (path, type, mode)
	char			*path,
				*type;
	unsigned int		mode;
{
	struct flock		l;

	FILE			*fp;

	int			fd,
				oflag,
				create;

	register struct buffers	*bp;


	if (!path || !type) {
		errno = EINVAL;
		return (0);
	}

#define plus (type[1] == '+')
	switch (type[0]) {
	case 'w':
		oflag = (plus? O_RDWR : O_WRONLY) | O_TRUNC;
		create = 1;
		break;
	case 'a':
		oflag = (plus? O_RDWR : O_WRONLY) | O_APPEND;
		create = 1;
		break;
	case 'r':
		oflag = plus? O_RDWR : O_RDONLY;
		create = 0;
		break;
	default:
		return (0);
	}
	if ((fd = Open(path, oflag)) == -1)
		if (errno == ENOENT && create) {
			register int		old_umask = umask(0);

			if ((fd = Open(path, oflag|O_CREAT, mode)) != -1)
				chown_lppath (path);
			if (old_umask)
				umask (old_umask);
		}

	if (fd == -1) switch (errno) {
	case ENOTDIR:
		errno = EACCES;
		/*FALLTHROUGH*/
	default:
		return (0);
	}

	l.l_type = (oflag & (O_WRONLY|O_RDWR)? F_WRLCK : F_RDLCK);
	l.l_whence = 1;
	l.l_start = 0;
	l.l_len = 0;
	if (Fcntl(fd, F_SETLK, &l) == -1) {
		/*
		 * Early UNIX op. sys. have wrong errno.
		 */
		if (errno == EACCES)
			errno = EAGAIN;
		Close (fd);
		return (0);
	}

	if (!(fp = fdopen(fd, type)))
		Close (fd);
	else {
		/*
		 * If MAX_NOFILES happens to be too low, no problem:
		 * the file will be buffered normally.
		 */
		for (bp = &buffers[0]; bp < &buffers[MAX_NOFILES]; bp++)
			if (!bp->fp) {
				if (!bp->buffer)
					bp->buffer = malloc(BUFSIZ + 8);
				bp->fp = fp;
				setvbuf (fp, bp->buffer, _IOFBF, BUFSIZ + 8);
				break;
			}
	}

	return (fp);
}

int			close_lpfile (fp)
	FILE			*fp;
{
	register struct buffers	*bp;


	for (bp = &buffers[0]; bp < &buffers[MAX_NOFILES]; bp++)
		if (bp->fp == fp) {
			bp->fp = 0;
			break;
		}

	/*
	 * Closing the file removes all locks.
	 */
	return (fclose(fp));
}

/**
 ** chown_lppath()
 **/

int			chown_lppath (path)
	char			*path;
{
	static int		lp_uid		= -1,
				lp_gid		= -1;

	struct passwd		*ppw;


	if (lp_uid == -1) {
		if (!(ppw = getpwnam(LPUSER)))
			ppw = getpwnam(ROOTUSER);
		endpwent ();
		if (!ppw)
			return (-1);
		lp_uid = ppw->pw_uid;
		lp_gid = ppw->pw_gid;
	}
	return (Chown(path, lp_uid, lp_gid));
}

/**
 ** rmfile() - UNLINK FILE BUT NO COMPLAINT IF NOT THERE
 **/

int			rmfile (path)
	char			*path;
{
	return (Unlink(path) == 0 || errno == ENOENT);
}

/**
 ** loadline() - LOAD A ONE-LINE CHARACTER STRING FROM FILE
 **/

char			*loadline (path)
	char			*path;
{
	register FILE		*fp;

	register char		*ret;

	register int		len;

	char			buf[BUFSIZ];

	if (!(fp = open_lpfile(path, "r")))
		return (0);

	if (fgets(buf, BUFSIZ, fp)) {
		if ((len = strlen(buf)) && buf[len - 1] == '\n')
			buf[--len] = 0;
		if ((ret = malloc(len + 1)))
			strcpy (ret, buf);
	} else {
		if (feof(fp))
			errno = 0;
		ret = 0;
	}

	close_lpfile (fp);
	return (ret);
}

/**
 ** loadstring() - LOAD A CHARACTER STRING FROM FILE
 **/

char			*loadstring (path)
	char			*path;
{
	register FILE		*fp;

	register char		*ret;

	register int		len;


	if (!(fp = open_lpfile(path, "r")))
		return (0);

	if ((ret = sop_up_rest(fp, (char *)0))) {
		if ((len = strlen(ret)) && ret[len - 1] == '\n')
			ret[len - 1] = 0;
	} else
		if (feof(fp))
			errno = 0;

	close_lpfile (fp);
	return (ret);
}

/**
 ** dumpstring() - DUMP CHARACTER STRING TO FILE
 **/

int			dumpstring (path, str)
	char			*path,
				*str;
{
	register FILE		*fp;

	if (!str)
		return (rmfile(path));

	if (!(fp = open_lpfile(path, "w", MODE_READ)))
		return (-1);
	fprintf (fp, "%s\n", str);
	close_lpfile (fp);
	return (0);
}
