fileupd.c revision 20302
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 *
2620302Sjoerg *	$Id: fileupd.c,v 1.1.1.1 1996/12/09 14:05:35 joerg Exp $
2720253Sjoerg */
2820253Sjoerg
2920253Sjoerg#include <stdio.h>
3020253Sjoerg#include <fcntl.h>
3120253Sjoerg#include <stdlib.h>
3220253Sjoerg#include <string.h>
3320253Sjoerg#include <sys/types.h>
3420253Sjoerg#include <sys/stat.h>
3520253Sjoerg#include <sys/param.h>
3620253Sjoerg#include <errno.h>
3720253Sjoerg#include <unistd.h>
3820253Sjoerg
3920253Sjoerg#include "pwupd.h"
4020253Sjoerg
4120253Sjoergint
4220253Sjoergfileupdate(char const * filename, mode_t fmode, char const * newline, char const * prefix, int pfxlen, int updmode)
4320253Sjoerg{
4420253Sjoerg	int             rc = 0;
4520253Sjoerg
4620253Sjoerg	if (pfxlen <= 1)
4720253Sjoerg		errno = EINVAL;
4820253Sjoerg	else {
4920253Sjoerg		int             infd = open(filename, O_RDWR | O_CREAT | O_EXLOCK, fmode);
5020253Sjoerg
5120253Sjoerg		if (infd != -1) {
5220253Sjoerg			FILE           *infp = fdopen(infd, "r+");
5320253Sjoerg
5420253Sjoerg			if (infp == NULL)
5520253Sjoerg				close(infd);
5620253Sjoerg			else {
5720253Sjoerg				int             outfd;
5820253Sjoerg				char            file[MAXPATHLEN];
5920253Sjoerg
6020253Sjoerg				strcpy(file, filename);
6120253Sjoerg				strcat(file, ".new");
6220253Sjoerg				outfd = open(file, O_RDWR | O_CREAT | O_TRUNC | O_EXLOCK, fmode);
6320253Sjoerg				if (outfd != -1) {
6420253Sjoerg					FILE           *outfp = fdopen(outfd, "w+");
6520253Sjoerg
6620253Sjoerg					if (outfp == NULL)
6720253Sjoerg						close(outfd);
6820253Sjoerg					else {
6920253Sjoerg						int             updated = UPD_CREATE;
7020253Sjoerg						char            line[2048];
7120253Sjoerg
7220253Sjoerg						while (fgets(line, sizeof(line), infp) != NULL) {
7320253Sjoerg							char           *p = strchr(line, '\n');
7420253Sjoerg
7520253Sjoerg							if (p == NULL) {	/* Line too long */
7620253Sjoerg								int             ch;
7720253Sjoerg
7820253Sjoerg								fputs(line, outfp);
7920253Sjoerg								while ((ch = fgetc(infp)) != EOF) {
8020253Sjoerg									fputc(ch, outfp);
8120253Sjoerg									if (ch == '\n')
8220253Sjoerg										break;
8320253Sjoerg								}
8420253Sjoerg								continue;
8520253Sjoerg							}
8620253Sjoerg							if (*line != '#' && *line != '\n') {
8720253Sjoerg								if (!updated && strncmp(line, prefix, pfxlen) == 0) {
8820253Sjoerg									updated = updmode == UPD_REPLACE ? UPD_REPLACE : UPD_DELETE;
8920253Sjoerg
9020253Sjoerg									/*
9120253Sjoerg									 * Only actually write changes if updating
9220253Sjoerg									 */
9320253Sjoerg									if (updmode == UPD_REPLACE)
9420253Sjoerg										strcpy(line, newline);
9520253Sjoerg									else if (updmode == UPD_DELETE)
9620253Sjoerg										continue;
9720253Sjoerg								}
9820253Sjoerg							}
9920253Sjoerg							fputs(line, outfp);
10020253Sjoerg						}
10120253Sjoerg
10220253Sjoerg						/*
10320253Sjoerg						 * Now, we need to decide what to do: If we are in
10420253Sjoerg						 * update mode, and no record was updated, then error If
10520253Sjoerg						 * we are in insert mode, and record already exists,
10620253Sjoerg						 * then error
10720253Sjoerg						 */
10820253Sjoerg						if (updmode != updated)
10920253Sjoerg							errno = (updmode == UPD_CREATE) ? EEXIST : ENOENT;
11020253Sjoerg						else {
11120253Sjoerg
11220253Sjoerg							/*
11320253Sjoerg							 * If adding a new record, append it to the end
11420253Sjoerg							 */
11520253Sjoerg							if (updmode == UPD_CREATE)
11620253Sjoerg								fputs(newline, outfp);
11720253Sjoerg
11820253Sjoerg							/*
11920253Sjoerg							 * Flush the file and check for the result
12020253Sjoerg							 */
12120253Sjoerg							rc = fflush(outfp) != EOF;
12220253Sjoerg							if (rc) {
12320253Sjoerg
12420253Sjoerg								/*
12520253Sjoerg								 * Copy data back into the
12620253Sjoerg								 * original file and truncate
12720253Sjoerg								 */
12820253Sjoerg								rewind(infp);
12920253Sjoerg								rewind(outfp);
13020253Sjoerg								while (fgets(line, sizeof(line), outfp) != NULL)
13120253Sjoerg									fputs(line, infp);
13220253Sjoerg
13320253Sjoerg								/*
13420253Sjoerg								 * This is a gross hack, but we may have
13520253Sjoerg								 * corrupted the original file
13620253Sjoerg								 * Unfortunately, it will lose the inode.
13720253Sjoerg								 */
13820253Sjoerg								if (fflush(infp) == EOF || ferror(infp))
13920253Sjoerg									rc = rename(file, filename) == 0;
14020253Sjoerg								else
14120253Sjoerg									ftruncate(infd, ftell(infp));
14220253Sjoerg							}
14320253Sjoerg						}
14420253Sjoerg						fclose(outfp);
14520253Sjoerg					}
14620253Sjoerg					remove(file);
14720253Sjoerg				}
14820253Sjoerg				fclose(infp);
14920253Sjoerg			}
15020253Sjoerg		}
15120253Sjoerg	}
15220253Sjoerg	return rc;
15320253Sjoerg}
154