fileupd.c revision 30259
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[] =
2930259Scharnier	"$Id$";
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{
7420253Sjoerg	int             rc = 0;
7520253Sjoerg
7620253Sjoerg	if (pfxlen <= 1)
7720253Sjoerg		errno = EINVAL;
7820253Sjoerg	else {
7920253Sjoerg		int             infd = open(filename, O_RDWR | O_CREAT | O_EXLOCK, fmode);
8020253Sjoerg
8120253Sjoerg		if (infd != -1) {
8220253Sjoerg			FILE           *infp = fdopen(infd, "r+");
8320253Sjoerg
8420253Sjoerg			if (infp == NULL)
8520253Sjoerg				close(infd);
8620253Sjoerg			else {
8720253Sjoerg				int             outfd;
8820253Sjoerg				char            file[MAXPATHLEN];
8920253Sjoerg
9020253Sjoerg				strcpy(file, filename);
9120253Sjoerg				strcat(file, ".new");
9220253Sjoerg				outfd = open(file, O_RDWR | O_CREAT | O_TRUNC | O_EXLOCK, fmode);
9320253Sjoerg				if (outfd != -1) {
9420253Sjoerg					FILE           *outfp = fdopen(outfd, "w+");
9520253Sjoerg
9620253Sjoerg					if (outfp == NULL)
9720253Sjoerg						close(outfd);
9820253Sjoerg					else {
9920253Sjoerg						int             updated = UPD_CREATE;
10020747Sdavidn						int		linesize = PWBUFSZ;
10120747Sdavidn						char           *line = malloc(linesize);
10220253Sjoerg
10320747Sdavidn					nextline:
10420747Sdavidn						while (fgets(line, linesize, infp) != NULL) {
10520253Sjoerg							char           *p = strchr(line, '\n');
10620253Sjoerg
10720747Sdavidn							while ((p = strchr(line, '\n')) == NULL) {
10820747Sdavidn								int	l;
10920747Sdavidn								if (extendline(&line, &linesize, linesize + PWBUFSZ) == -1) {
11020747Sdavidn									int	ch;
11120747Sdavidn									fputs(line, outfp);
11220747Sdavidn									while ((ch = fgetc(infp)) != EOF) {
11320747Sdavidn										fputc(ch, outfp);
11420747Sdavidn										if (ch == '\n')
11520747Sdavidn											break;
11620747Sdavidn									}
11720747Sdavidn									goto nextline;
11820253Sjoerg								}
11920747Sdavidn								l = strlen(line);
12020747Sdavidn								if (fgets(line + l, linesize - l, infp) == NULL)
12120747Sdavidn									break;
12220253Sjoerg							}
12320253Sjoerg							if (*line != '#' && *line != '\n') {
12420253Sjoerg								if (!updated && strncmp(line, prefix, pfxlen) == 0) {
12520253Sjoerg									updated = updmode == UPD_REPLACE ? UPD_REPLACE : UPD_DELETE;
12620253Sjoerg
12720253Sjoerg									/*
12820253Sjoerg									 * Only actually write changes if updating
12920253Sjoerg									 */
13020253Sjoerg									if (updmode == UPD_REPLACE)
13120253Sjoerg										strcpy(line, newline);
13220253Sjoerg									else if (updmode == UPD_DELETE)
13320253Sjoerg										continue;
13420253Sjoerg								}
13520253Sjoerg							}
13620253Sjoerg							fputs(line, outfp);
13720253Sjoerg						}
13820253Sjoerg
13920253Sjoerg						/*
14020253Sjoerg						 * Now, we need to decide what to do: If we are in
14120253Sjoerg						 * update mode, and no record was updated, then error If
14220253Sjoerg						 * we are in insert mode, and record already exists,
14320253Sjoerg						 * then error
14420253Sjoerg						 */
14520253Sjoerg						if (updmode != updated)
14620253Sjoerg							errno = (updmode == UPD_CREATE) ? EEXIST : ENOENT;
14720253Sjoerg						else {
14820253Sjoerg
14920253Sjoerg							/*
15020253Sjoerg							 * If adding a new record, append it to the end
15120253Sjoerg							 */
15220253Sjoerg							if (updmode == UPD_CREATE)
15320253Sjoerg								fputs(newline, outfp);
15420253Sjoerg
15520253Sjoerg							/*
15620253Sjoerg							 * Flush the file and check for the result
15720253Sjoerg							 */
15820253Sjoerg							rc = fflush(outfp) != EOF;
15920253Sjoerg							if (rc) {
16020253Sjoerg
16120253Sjoerg								/*
16220253Sjoerg								 * Copy data back into the
16320253Sjoerg								 * original file and truncate
16420253Sjoerg								 */
16520253Sjoerg								rewind(infp);
16620253Sjoerg								rewind(outfp);
16720747Sdavidn								while (fgets(line, linesize, outfp) != NULL)
16820253Sjoerg									fputs(line, infp);
16920253Sjoerg
17020253Sjoerg								/*
17120253Sjoerg								 * This is a gross hack, but we may have
17220253Sjoerg								 * corrupted the original file
17320253Sjoerg								 * Unfortunately, it will lose the inode.
17420253Sjoerg								 */
17520253Sjoerg								if (fflush(infp) == EOF || ferror(infp))
17620253Sjoerg									rc = rename(file, filename) == 0;
17720253Sjoerg								else
17820253Sjoerg									ftruncate(infd, ftell(infp));
17920253Sjoerg							}
18020253Sjoerg						}
18120747Sdavidn						free(line);
18220253Sjoerg						fclose(outfp);
18320253Sjoerg					}
18420253Sjoerg					remove(file);
18520253Sjoerg				}
18620253Sjoerg				fclose(infp);
18720253Sjoerg			}
18820253Sjoerg		}
18920253Sjoerg	}
19020253Sjoerg	return rc;
19120253Sjoerg}
192