120253Sjoerg/*-
220302Sjoerg * Copyright (C) 1996
320302Sjoerg *	David L. Nugent.  All rights reserved.
420253Sjoerg *
520253Sjoerg * Redistribution and use in source and binary forms, with or without
620253Sjoerg * modification, are permitted provided that the following conditions
720253Sjoerg * are met:
820253Sjoerg * 1. Redistributions of source code must retain the above copyright
920302Sjoerg *    notice, this list of conditions and the following disclaimer.
1020253Sjoerg * 2. Redistributions in binary form must reproduce the above copyright
1120253Sjoerg *    notice, this list of conditions and the following disclaimer in the
1220253Sjoerg *    documentation and/or other materials provided with the distribution.
1320253Sjoerg *
1420302Sjoerg * THIS SOFTWARE IS PROVIDED BY DAVID L. NUGENT AND CONTRIBUTORS ``AS IS'' AND
1520253Sjoerg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1620253Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1720302Sjoerg * ARE DISCLAIMED.  IN NO EVENT SHALL DAVID L. NUGENT OR CONTRIBUTORS BE LIABLE
1820253Sjoerg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1920253Sjoerg * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2020253Sjoerg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2120253Sjoerg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2220253Sjoerg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2320253Sjoerg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2420253Sjoerg * SUCH DAMAGE.
2520253Sjoerg */
2620253Sjoerg
2730259Scharnier#ifndef lint
2830259Scharnierstatic const char rcsid[] =
2950479Speter  "$FreeBSD$";
3030259Scharnier#endif /* not lint */
3130259Scharnier
3220253Sjoerg#include <stdio.h>
3320253Sjoerg#include <fcntl.h>
3420253Sjoerg#include <stdlib.h>
3520253Sjoerg#include <string.h>
3620253Sjoerg#include <sys/types.h>
3720253Sjoerg#include <sys/stat.h>
3820253Sjoerg#include <sys/param.h>
3920253Sjoerg#include <errno.h>
4020253Sjoerg#include <unistd.h>
4120253Sjoerg
4220253Sjoerg#include "pwupd.h"
4320253Sjoerg
4420253Sjoergint
4520747Sdavidnextendline(char **buf, int * buflen, int needed)
4620747Sdavidn{
4720747Sdavidn	if (needed > *buflen) {
4820747Sdavidn		char	*tmp = realloc(*buf, needed);
4920747Sdavidn		if (tmp == NULL)
5020747Sdavidn			return -1;
5120747Sdavidn		*buf = tmp;
5220747Sdavidn		*buflen = needed;
5320747Sdavidn	}
5420747Sdavidn	return *buflen;
5520747Sdavidn}
5620747Sdavidn
5720747Sdavidnint
5820747Sdavidnextendarray(char ***buf, int * buflen, int needed)
5920747Sdavidn{
6020747Sdavidn	if (needed > *buflen) {
6120747Sdavidn		char	**tmp = realloc(*buf, needed * sizeof(char *));
6220747Sdavidn		if (tmp == NULL)
6320747Sdavidn			return -1;
6420747Sdavidn		*buf = tmp;
6520747Sdavidn		*buflen = needed;
6620747Sdavidn	}
6720747Sdavidn	return *buflen;
6820747Sdavidn}
6920747Sdavidn
7020747Sdavidn
7120747Sdavidnint
7220253Sjoergfileupdate(char const * filename, mode_t fmode, char const * newline, char const * prefix, int pfxlen, int updmode)
7320253Sjoerg{
7452502Sdavidn	int     rc = 0;
7520253Sjoerg
7620253Sjoerg	if (pfxlen <= 1)
7752502Sdavidn		rc = EINVAL;
7820253Sjoerg	else {
79126753Skensmith		int    infd = open(filename, O_RDWR | O_CREAT | O_EXLOCK, fmode);
8020253Sjoerg
8152502Sdavidn		if (infd == -1)
8252502Sdavidn			rc = errno;
8352502Sdavidn		else {
8452502Sdavidn			FILE   *infp = fdopen(infd, "r+");
8520253Sjoerg
8652502Sdavidn			if (infp == NULL) {
8752502Sdavidn				rc = errno;		/* Assumes fopen(3) sets errno from open(2) */
8820253Sjoerg				close(infd);
8952502Sdavidn			} else {
9052502Sdavidn				int       outfd;
9152502Sdavidn				char      file[MAXPATHLEN];
9220253Sjoerg
9320253Sjoerg				strcpy(file, filename);
9420253Sjoerg				strcat(file, ".new");
95126753Skensmith				outfd = open(file, O_RDWR | O_CREAT | O_TRUNC, fmode);
9652502Sdavidn				if (outfd == -1)
9752502Sdavidn					rc = errno;
9852502Sdavidn				else {
9952502Sdavidn					FILE    *outfp = fdopen(outfd, "w+");
10020253Sjoerg
10152502Sdavidn					if (outfp == NULL) {
10252502Sdavidn						rc = errno;
10320253Sjoerg						close(outfd);
10452502Sdavidn					} else {
10552502Sdavidn						int   updated = UPD_CREATE;
10620747Sdavidn						int		linesize = PWBUFSZ;
10752502Sdavidn						char  *line = malloc(linesize);
10820253Sjoerg
10920747Sdavidn					nextline:
11020747Sdavidn						while (fgets(line, linesize, infp) != NULL) {
11152502Sdavidn							char  *p = strchr(line, '\n');
11220253Sjoerg
11320747Sdavidn							while ((p = strchr(line, '\n')) == NULL) {
11420747Sdavidn								int	l;
11520747Sdavidn								if (extendline(&line, &linesize, linesize + PWBUFSZ) == -1) {
11620747Sdavidn									int	ch;
11720747Sdavidn									fputs(line, outfp);
11820747Sdavidn									while ((ch = fgetc(infp)) != EOF) {
11920747Sdavidn										fputc(ch, outfp);
12020747Sdavidn										if (ch == '\n')
12120747Sdavidn											break;
12220747Sdavidn									}
12320747Sdavidn									goto nextline;
12420253Sjoerg								}
12520747Sdavidn								l = strlen(line);
12620747Sdavidn								if (fgets(line + l, linesize - l, infp) == NULL)
12720747Sdavidn									break;
12820253Sjoerg							}
12920253Sjoerg							if (*line != '#' && *line != '\n') {
13020253Sjoerg								if (!updated && strncmp(line, prefix, pfxlen) == 0) {
13120253Sjoerg									updated = updmode == UPD_REPLACE ? UPD_REPLACE : UPD_DELETE;
13220253Sjoerg
13320253Sjoerg									/*
13420253Sjoerg									 * Only actually write changes if updating
13520253Sjoerg									 */
13620253Sjoerg									if (updmode == UPD_REPLACE)
13720253Sjoerg										strcpy(line, newline);
13820253Sjoerg									else if (updmode == UPD_DELETE)
13920253Sjoerg										continue;
14020253Sjoerg								}
14120253Sjoerg							}
14220253Sjoerg							fputs(line, outfp);
14320253Sjoerg						}
14420253Sjoerg
14520253Sjoerg						/*
14620253Sjoerg						 * Now, we need to decide what to do: If we are in
14720253Sjoerg						 * update mode, and no record was updated, then error If
14820253Sjoerg						 * we are in insert mode, and record already exists,
14920253Sjoerg						 * then error
15020253Sjoerg						 */
15120253Sjoerg						if (updmode != updated)
15252502Sdavidn							/* -1 return means:
15352502Sdavidn							 * update,delete=no user entry
15452502Sdavidn							 * create=entry exists
15552502Sdavidn							 */
15652502Sdavidn							rc = -1;
15720253Sjoerg						else {
15820253Sjoerg
15920253Sjoerg							/*
16020253Sjoerg							 * If adding a new record, append it to the end
16120253Sjoerg							 */
16220253Sjoerg							if (updmode == UPD_CREATE)
16320253Sjoerg								fputs(newline, outfp);
16420253Sjoerg
16520253Sjoerg							/*
16620253Sjoerg							 * Flush the file and check for the result
16720253Sjoerg							 */
16852502Sdavidn							if (fflush(outfp) == EOF)
16952502Sdavidn								rc = errno;	/* Failed to update */
17052502Sdavidn							else {
17120253Sjoerg								/*
17220253Sjoerg								 * Copy data back into the
17320253Sjoerg								 * original file and truncate
17420253Sjoerg								 */
17520253Sjoerg								rewind(infp);
17620253Sjoerg								rewind(outfp);
17720747Sdavidn								while (fgets(line, linesize, outfp) != NULL)
17820253Sjoerg									fputs(line, infp);
17920253Sjoerg
18020253Sjoerg								/*
18152502Sdavidn								 * If there was a problem with copying
18252502Sdavidn								 * we will just rename 'file.new'
18352502Sdavidn								 * to 'file'.
18420253Sjoerg								 * This is a gross hack, but we may have
18520253Sjoerg								 * corrupted the original file
18620253Sjoerg								 */
18752502Sdavidn								if (fflush(infp) == EOF || ferror(infp))
18844229Sdavidn									rename(file, filename);
18920253Sjoerg								else
19020253Sjoerg									ftruncate(infd, ftell(infp));
19120253Sjoerg							}
19220253Sjoerg						}
19320747Sdavidn						free(line);
19420253Sjoerg						fclose(outfp);
19520253Sjoerg					}
19620253Sjoerg					remove(file);
19720253Sjoerg				}
19820253Sjoerg				fclose(infp);
19920253Sjoerg			}
20020253Sjoerg		}
20120253Sjoerg	}
20220253Sjoerg	return rc;
20320253Sjoerg}
204