1997-10-15 06:47:20 +04:00
|
|
|
/*
|
|
|
|
* subst.c --- substitution program
|
|
|
|
*
|
|
|
|
* Subst is used as a quicky program to do @ substitutions
|
2008-08-28 07:07:54 +04:00
|
|
|
*
|
1997-10-15 06:47:20 +04:00
|
|
|
*/
|
|
|
|
|
fix cross-compilation support
Commit 2500ebfc89 (util: fix make dependencies for subst) broke cross
compilation because it unconditionally used config.h without setting a
includes path so that the config.h file could be found.
The proposed fix of adding the include path (such as was proposed at
http://patchwork.ozlabs.org/patch/355662/ or in Debian Bug #753375)
isn't really the right way to go, since the information in config.h is
for the target environment, and not the build environment. So using
config.h when building helper programs used as part of the build can
potentially cause more problems than it solves.
In general, build helpers must be written to be as portable as
possible, and to not require any autoconf defined #ifdef's whenever
possible. The subst program broke this rule to (1) address a Coverity
security complaint by using futimes(2) instad of utimes(2) if present,
and (2) to preserve the nanosecond portion of the file timestamp.
Oh, well. We won't be able to do the latter when cross compiling, and
as to the former, if an attacker has write access to your build tree
while you are building programs that will be run as root, you've got
bigger problems. :-)
Fix the problem that commit 2500ebfc89 was trying to address by
explicitly adding @DEFS@ to CFLAGS, so that -DHAVE_CONFIG_H is passed
to make depend. This fixes up the make depend without forcing the use
of config.h when cross-compiling.
Addresses-Debian-Bug: #753375
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Tested-by: Gustavo Zacarias <gustavo@zacarias.com.ar>
Cc: Helmut Grohne <helmut@subdivi.de>
Cc: 753375@bugs.debian.org
2014-07-06 04:23:23 +04:00
|
|
|
#ifdef HAVE_CONFIG_H
|
2014-01-03 09:26:43 +04:00
|
|
|
#include "config.h"
|
2014-10-20 06:02:48 +04:00
|
|
|
#else
|
|
|
|
#define HAVE_SYS_TIME_H
|
fix cross-compilation support
Commit 2500ebfc89 (util: fix make dependencies for subst) broke cross
compilation because it unconditionally used config.h without setting a
includes path so that the config.h file could be found.
The proposed fix of adding the include path (such as was proposed at
http://patchwork.ozlabs.org/patch/355662/ or in Debian Bug #753375)
isn't really the right way to go, since the information in config.h is
for the target environment, and not the build environment. So using
config.h when building helper programs used as part of the build can
potentially cause more problems than it solves.
In general, build helpers must be written to be as portable as
possible, and to not require any autoconf defined #ifdef's whenever
possible. The subst program broke this rule to (1) address a Coverity
security complaint by using futimes(2) instad of utimes(2) if present,
and (2) to preserve the nanosecond portion of the file timestamp.
Oh, well. We won't be able to do the latter when cross compiling, and
as to the former, if an attacker has write access to your build tree
while you are building programs that will be run as root, you've got
bigger problems. :-)
Fix the problem that commit 2500ebfc89 was trying to address by
explicitly adding @DEFS@ to CFLAGS, so that -DHAVE_CONFIG_H is passed
to make depend. This fixes up the make depend without forcing the use
of config.h when cross-compiling.
Addresses-Debian-Bug: #753375
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Tested-by: Gustavo Zacarias <gustavo@zacarias.com.ar>
Cc: Helmut Grohne <helmut@subdivi.de>
Cc: 753375@bugs.debian.org
2014-07-06 04:23:23 +04:00
|
|
|
#endif
|
1997-10-15 06:47:20 +04:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
2014-07-26 05:43:08 +04:00
|
|
|
#ifdef HAVE_SYS_TIME_H
|
|
|
|
#include <sys/time.h>
|
|
|
|
#endif
|
2016-03-06 03:38:33 +03:00
|
|
|
#ifdef HAVE_SYS_TYPES_H
|
2004-04-03 22:53:46 +04:00
|
|
|
#include <sys/types.h>
|
2016-03-06 03:38:33 +03:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_STAT_H
|
2004-04-03 22:53:46 +04:00
|
|
|
#include <sys/stat.h>
|
2016-03-06 03:38:33 +03:00
|
|
|
#endif
|
2014-01-03 09:26:43 +04:00
|
|
|
#include <fcntl.h>
|
2004-04-12 22:16:04 +04:00
|
|
|
#include <time.h>
|
2004-04-03 22:53:46 +04:00
|
|
|
#include <utime.h>
|
2014-03-14 17:43:11 +04:00
|
|
|
#ifdef HAVE_SYS_TIME_H
|
|
|
|
#include <sys/time.h>
|
|
|
|
#endif
|
1997-10-15 06:47:20 +04:00
|
|
|
|
|
|
|
#ifdef HAVE_GETOPT_H
|
|
|
|
#include <getopt.h>
|
2000-04-03 20:16:46 +04:00
|
|
|
#else
|
|
|
|
extern char *optarg;
|
|
|
|
extern int optind;
|
1997-10-15 06:47:20 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
struct subst_entry {
|
|
|
|
char *name;
|
|
|
|
char *value;
|
|
|
|
struct subst_entry *next;
|
|
|
|
};
|
|
|
|
|
2013-12-17 03:56:36 +04:00
|
|
|
static struct subst_entry *subst_table = 0;
|
1997-10-15 06:47:20 +04:00
|
|
|
|
|
|
|
static int add_subst(char *name, char *value)
|
|
|
|
{
|
|
|
|
struct subst_entry *ent = 0;
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1998-01-19 17:40:24 +03:00
|
|
|
ent = (struct subst_entry *) malloc(sizeof(struct subst_entry));
|
1997-10-15 06:47:20 +04:00
|
|
|
if (!ent)
|
|
|
|
goto fail;
|
1998-01-19 17:40:24 +03:00
|
|
|
ent->name = (char *) malloc(strlen(name)+1);
|
1997-10-15 06:47:20 +04:00
|
|
|
if (!ent->name)
|
|
|
|
goto fail;
|
1998-01-19 17:40:24 +03:00
|
|
|
ent->value = (char *) malloc(strlen(value)+1);
|
1997-10-15 06:47:20 +04:00
|
|
|
if (!ent->value)
|
|
|
|
goto fail;
|
|
|
|
strcpy(ent->name, name);
|
|
|
|
strcpy(ent->value, value);
|
|
|
|
ent->next = subst_table;
|
|
|
|
subst_table = ent;
|
|
|
|
return 0;
|
|
|
|
fail:
|
|
|
|
if (ent) {
|
2009-02-23 20:07:50 +03:00
|
|
|
free(ent->name);
|
1997-10-15 06:47:20 +04:00
|
|
|
free(ent);
|
|
|
|
}
|
2011-09-17 00:49:29 +04:00
|
|
|
return ENOMEM;
|
1997-10-15 06:47:20 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct subst_entry *fetch_subst_entry(char *name)
|
|
|
|
{
|
|
|
|
struct subst_entry *ent;
|
|
|
|
|
|
|
|
for (ent = subst_table; ent; ent = ent->next) {
|
|
|
|
if (strcmp(name, ent->name) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return ent;
|
|
|
|
}
|
|
|
|
|
1998-08-01 08:35:39 +04:00
|
|
|
/*
|
|
|
|
* Given the starting and ending position of the replacement name,
|
|
|
|
* check to see if it is valid, and pull it out if it is.
|
|
|
|
*/
|
2003-12-07 09:28:50 +03:00
|
|
|
static char *get_subst_symbol(const char *begin, size_t len, char prefix)
|
1998-08-01 08:35:39 +04:00
|
|
|
{
|
|
|
|
static char replace_name[128];
|
|
|
|
char *cp, *start;
|
|
|
|
|
|
|
|
start = replace_name;
|
|
|
|
if (prefix)
|
|
|
|
*start++ = prefix;
|
|
|
|
|
|
|
|
if (len > sizeof(replace_name)-2)
|
|
|
|
return NULL;
|
|
|
|
memcpy(start, begin, len);
|
|
|
|
start[len] = 0;
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1998-08-01 08:35:39 +04:00
|
|
|
/*
|
1998-12-19 11:08:43 +03:00
|
|
|
* The substitution variable must all be in the of [0-9A-Za-z_].
|
1998-08-01 08:35:39 +04:00
|
|
|
* If it isn't, this must be an invalid symbol name.
|
|
|
|
*/
|
|
|
|
for (cp = start; *cp; cp++) {
|
|
|
|
if (!(*cp >= 'a' && *cp <= 'z') &&
|
|
|
|
!(*cp >= 'A' && *cp <= 'Z') &&
|
1998-12-19 11:08:43 +03:00
|
|
|
!(*cp >= '0' && *cp <= '9') &&
|
1998-08-01 08:35:39 +04:00
|
|
|
!(*cp == '_'))
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return (replace_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void replace_string(char *begin, char *end, char *newstr)
|
|
|
|
{
|
|
|
|
int replace_len, len;
|
|
|
|
|
|
|
|
replace_len = strlen(newstr);
|
|
|
|
len = end - begin;
|
2001-04-17 09:05:37 +04:00
|
|
|
if (replace_len == 0)
|
|
|
|
memmove(begin, end+1, strlen(end)+1);
|
|
|
|
else if (replace_len != len+1)
|
1998-08-01 08:35:39 +04:00
|
|
|
memmove(end+(replace_len-len-1), end,
|
|
|
|
strlen(end)+1);
|
|
|
|
memcpy(begin, newstr, replace_len);
|
|
|
|
}
|
|
|
|
|
1997-10-15 06:47:20 +04:00
|
|
|
static void substitute_line(char *line)
|
|
|
|
{
|
1999-10-26 20:28:59 +04:00
|
|
|
char *ptr, *name_ptr, *end_ptr;
|
1997-10-15 06:47:20 +04:00
|
|
|
struct subst_entry *ent;
|
1998-08-01 08:35:39 +04:00
|
|
|
char *replace_name;
|
2003-12-07 09:28:50 +03:00
|
|
|
size_t len;
|
1997-10-15 06:47:20 +04:00
|
|
|
|
1998-08-01 08:35:39 +04:00
|
|
|
/*
|
|
|
|
* Expand all @FOO@ substitutions
|
|
|
|
*/
|
1997-10-15 06:47:20 +04:00
|
|
|
ptr = line;
|
|
|
|
while (ptr) {
|
|
|
|
name_ptr = strchr(ptr, '@');
|
|
|
|
if (!name_ptr)
|
1998-08-01 08:35:39 +04:00
|
|
|
break; /* No more */
|
|
|
|
if (*(++name_ptr) == '@') {
|
|
|
|
/*
|
|
|
|
* Handle tytso@@mit.edu --> tytso@mit.edu
|
|
|
|
*/
|
|
|
|
memmove(name_ptr-1, name_ptr, strlen(name_ptr)+1);
|
|
|
|
ptr = name_ptr+1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
end_ptr = strchr(name_ptr, '@');
|
1997-10-15 06:47:20 +04:00
|
|
|
if (!end_ptr)
|
|
|
|
break;
|
1998-08-01 08:35:39 +04:00
|
|
|
len = end_ptr - name_ptr;
|
|
|
|
replace_name = get_subst_symbol(name_ptr, len, 0);
|
|
|
|
if (!replace_name) {
|
|
|
|
ptr = name_ptr;
|
|
|
|
continue;
|
|
|
|
}
|
1997-10-15 06:47:20 +04:00
|
|
|
ent = fetch_subst_entry(replace_name);
|
|
|
|
if (!ent) {
|
2008-08-28 07:07:54 +04:00
|
|
|
fprintf(stderr, "Unfound expansion: '%s'\n",
|
1997-10-15 06:47:20 +04:00
|
|
|
replace_name);
|
|
|
|
ptr = end_ptr + 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
fprintf(stderr, "Replace name = '%s' with '%s'\n",
|
|
|
|
replace_name, ent->value);
|
|
|
|
#endif
|
1998-08-01 08:35:39 +04:00
|
|
|
ptr = name_ptr-1;
|
|
|
|
replace_string(ptr, end_ptr, ent->value);
|
2006-11-13 01:43:50 +03:00
|
|
|
if ((ent->value[0] == '@') &&
|
|
|
|
(strlen(replace_name) == strlen(ent->value)-2) &&
|
2008-08-28 07:07:54 +04:00
|
|
|
!strncmp(replace_name, ent->value+1,
|
2006-11-13 01:43:50 +03:00
|
|
|
strlen(ent->value)-2))
|
|
|
|
/* avoid an infinite loop */
|
|
|
|
ptr += strlen(ent->value);
|
1998-08-01 08:35:39 +04:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Now do a second pass to expand ${FOO}
|
|
|
|
*/
|
|
|
|
ptr = line;
|
|
|
|
while (ptr) {
|
|
|
|
name_ptr = strchr(ptr, '$');
|
|
|
|
if (!name_ptr)
|
|
|
|
break; /* No more */
|
|
|
|
if (*(++name_ptr) != '{') {
|
|
|
|
ptr = name_ptr;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
name_ptr++;
|
|
|
|
end_ptr = strchr(name_ptr, '}');
|
|
|
|
if (!end_ptr)
|
|
|
|
break;
|
|
|
|
len = end_ptr - name_ptr;
|
|
|
|
replace_name = get_subst_symbol(name_ptr, len, '$');
|
|
|
|
if (!replace_name) {
|
|
|
|
ptr = name_ptr;
|
|
|
|
continue;
|
2008-08-28 07:07:54 +04:00
|
|
|
}
|
1998-08-01 08:35:39 +04:00
|
|
|
ent = fetch_subst_entry(replace_name);
|
|
|
|
if (!ent) {
|
|
|
|
ptr = end_ptr + 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
fprintf(stderr, "Replace name = '%s' with '%s'\n",
|
|
|
|
replace_name, ent->value);
|
|
|
|
#endif
|
|
|
|
ptr = name_ptr-2;
|
|
|
|
replace_string(ptr, end_ptr, ent->value);
|
1997-10-15 06:47:20 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void parse_config_file(FILE *f)
|
|
|
|
{
|
|
|
|
char line[2048];
|
|
|
|
char *cp, *ptr;
|
|
|
|
|
|
|
|
while (!feof(f)) {
|
|
|
|
memset(line, 0, sizeof(line));
|
|
|
|
if (fgets(line, sizeof(line), f) == NULL)
|
|
|
|
break;
|
|
|
|
/*
|
|
|
|
* Strip newlines and comments.
|
|
|
|
*/
|
|
|
|
cp = strchr(line, '\n');
|
|
|
|
if (cp)
|
|
|
|
*cp = 0;
|
|
|
|
cp = strchr(line, '#');
|
|
|
|
if (cp)
|
|
|
|
*cp = 0;
|
|
|
|
/*
|
|
|
|
* Skip trailing and leading whitespace
|
|
|
|
*/
|
|
|
|
for (cp = line + strlen(line) - 1; cp >= line; cp--) {
|
|
|
|
if (*cp == ' ' || *cp == '\t')
|
|
|
|
*cp = 0;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
cp = line;
|
|
|
|
while (*cp && isspace(*cp))
|
|
|
|
cp++;
|
|
|
|
ptr = cp;
|
|
|
|
/*
|
|
|
|
* Skip empty lines
|
|
|
|
*/
|
|
|
|
if (*ptr == 0)
|
|
|
|
continue;
|
|
|
|
/*
|
|
|
|
* Ignore future extensions
|
|
|
|
*/
|
1998-08-01 08:35:39 +04:00
|
|
|
if (*ptr == '@')
|
1997-10-15 06:47:20 +04:00
|
|
|
continue;
|
|
|
|
/*
|
|
|
|
* Parse substitutions
|
|
|
|
*/
|
|
|
|
for (cp = ptr; *cp; cp++)
|
|
|
|
if (isspace(*cp))
|
|
|
|
break;
|
|
|
|
*cp = 0;
|
|
|
|
for (cp++; *cp; cp++)
|
|
|
|
if (!isspace(*cp))
|
|
|
|
break;
|
|
|
|
#if 0
|
2001-04-17 09:05:37 +04:00
|
|
|
printf("Substitute: '%s' for '%s'\n", ptr, cp ? cp : "<NULL>");
|
1997-10-15 06:47:20 +04:00
|
|
|
#endif
|
|
|
|
add_subst(ptr, cp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return 0 if the files are different, 1 if the files are the same.
|
|
|
|
*/
|
2014-01-03 09:26:43 +04:00
|
|
|
static int compare_file(FILE *old_f, FILE *new_f)
|
1997-10-15 06:47:20 +04:00
|
|
|
{
|
|
|
|
char oldbuf[2048], newbuf[2048], *oldcp, *newcp;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
while (1) {
|
1998-01-19 17:40:24 +03:00
|
|
|
oldcp = fgets(oldbuf, sizeof(oldbuf), old_f);
|
|
|
|
newcp = fgets(newbuf, sizeof(newbuf), new_f);
|
1997-10-15 06:47:20 +04:00
|
|
|
if (!oldcp && !newcp) {
|
|
|
|
retval = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!oldcp || !newcp || strcmp(oldbuf, newbuf)) {
|
|
|
|
retval = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2014-10-20 06:02:48 +04:00
|
|
|
void set_utimes(const char *filename, int fd, const struct timeval times[2])
|
|
|
|
{
|
|
|
|
#ifdef HAVE_FUTIMES
|
|
|
|
if (futimes(fd, times) < 0)
|
|
|
|
perror("futimes");
|
|
|
|
#elif HAVE_UTIMES
|
|
|
|
if (utimes(filename, times) < 0)
|
|
|
|
perror("utimes");
|
|
|
|
#else
|
|
|
|
struct utimbuf ut;
|
|
|
|
|
|
|
|
ut.actime = times[0].tv_sec;
|
|
|
|
ut.modtime = times[1].tv_sec;
|
|
|
|
if (utime(filename, &ut) < 0)
|
|
|
|
perror("utime");
|
|
|
|
#endif
|
|
|
|
}
|
1997-10-15 06:47:20 +04:00
|
|
|
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
char line[2048];
|
|
|
|
int c;
|
2015-09-19 04:37:53 +03:00
|
|
|
int fd, ofd = -1;
|
2014-01-03 09:26:43 +04:00
|
|
|
FILE *in, *out, *old = NULL;
|
1997-10-15 06:47:20 +04:00
|
|
|
char *outfn = NULL, *newfn = NULL;
|
|
|
|
int verbose = 0;
|
2004-04-03 22:53:46 +04:00
|
|
|
int adjust_timestamp = 0;
|
2014-01-03 09:26:43 +04:00
|
|
|
int got_atime = 0;
|
2004-04-03 22:53:46 +04:00
|
|
|
struct stat stbuf;
|
2014-01-03 09:26:43 +04:00
|
|
|
struct timeval tv[2];
|
2008-08-28 07:07:54 +04:00
|
|
|
|
2004-04-03 22:53:46 +04:00
|
|
|
while ((c = getopt (argc, argv, "f:tv")) != EOF) {
|
1997-10-15 06:47:20 +04:00
|
|
|
switch (c) {
|
|
|
|
case 'f':
|
|
|
|
in = fopen(optarg, "r");
|
|
|
|
if (!in) {
|
|
|
|
perror(optarg);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
parse_config_file(in);
|
|
|
|
fclose(in);
|
|
|
|
break;
|
2004-04-03 22:53:46 +04:00
|
|
|
case 't':
|
|
|
|
adjust_timestamp++;
|
|
|
|
break;
|
1997-10-15 06:47:20 +04:00
|
|
|
case 'v':
|
|
|
|
verbose++;
|
|
|
|
break;
|
|
|
|
default:
|
2008-08-28 07:07:54 +04:00
|
|
|
fprintf(stderr, "%s: [-f config-file] [file]\n",
|
1997-10-15 06:47:20 +04:00
|
|
|
argv[0]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (optind < argc) {
|
|
|
|
in = fopen(argv[optind], "r");
|
|
|
|
if (!in) {
|
|
|
|
perror(argv[optind]);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
optind++;
|
|
|
|
} else
|
|
|
|
in = stdin;
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1997-10-15 06:47:20 +04:00
|
|
|
if (optind < argc) {
|
|
|
|
outfn = argv[optind];
|
1998-01-19 17:40:24 +03:00
|
|
|
newfn = (char *) malloc(strlen(outfn)+20);
|
1997-10-15 06:47:20 +04:00
|
|
|
if (!newfn) {
|
|
|
|
fprintf(stderr, "Memory error! Exiting.\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
strcpy(newfn, outfn);
|
|
|
|
strcat(newfn, ".new");
|
2015-09-19 04:37:53 +03:00
|
|
|
ofd = open(newfn, O_CREAT|O_TRUNC|O_RDWR, 0644);
|
|
|
|
if (ofd < 0) {
|
1997-10-15 06:47:20 +04:00
|
|
|
perror(newfn);
|
|
|
|
exit(1);
|
|
|
|
}
|
2015-09-19 04:37:53 +03:00
|
|
|
out = fdopen(ofd, "w+");
|
2014-01-03 09:26:43 +04:00
|
|
|
if (!out) {
|
|
|
|
perror("fdopen");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
fd = open(outfn, O_RDONLY);
|
|
|
|
if (fd > 0) {
|
|
|
|
/* save the original atime, if possible */
|
|
|
|
if (fstat(fd, &stbuf) == 0) {
|
|
|
|
#if HAVE_STRUCT_STAT_ST_ATIM
|
|
|
|
tv[0].tv_sec = stbuf.st_atim.tv_sec;
|
|
|
|
tv[0].tv_usec = stbuf.st_atim.tv_nsec / 1000;
|
|
|
|
#else
|
|
|
|
tv[0].tv_sec = stbuf.st_atime;
|
|
|
|
tv[0].tv_usec = 0;
|
|
|
|
#endif
|
|
|
|
got_atime = 1;
|
|
|
|
}
|
|
|
|
old = fdopen(fd, "r");
|
|
|
|
if (!old)
|
|
|
|
close(fd);
|
|
|
|
}
|
1997-10-15 06:47:20 +04:00
|
|
|
} else {
|
|
|
|
out = stdout;
|
|
|
|
outfn = 0;
|
|
|
|
}
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1997-10-15 06:47:20 +04:00
|
|
|
while (!feof(in)) {
|
|
|
|
if (fgets(line, sizeof(line), in) == NULL)
|
|
|
|
break;
|
|
|
|
substitute_line(line);
|
|
|
|
fputs(line, out);
|
|
|
|
}
|
|
|
|
fclose(in);
|
|
|
|
if (outfn) {
|
2014-01-03 09:26:43 +04:00
|
|
|
fflush(out);
|
|
|
|
rewind(out);
|
|
|
|
if (old && compare_file(old, out)) {
|
1997-10-15 06:47:20 +04:00
|
|
|
if (verbose)
|
|
|
|
printf("No change, keeping %s.\n", outfn);
|
2004-04-03 22:53:46 +04:00
|
|
|
if (adjust_timestamp) {
|
2014-01-03 09:26:43 +04:00
|
|
|
if (verbose)
|
|
|
|
printf("Updating modtime for %s\n", outfn);
|
|
|
|
if (gettimeofday(&tv[1], NULL) < 0) {
|
|
|
|
perror("gettimeofday");
|
|
|
|
exit(1);
|
2004-04-03 22:53:46 +04:00
|
|
|
}
|
2014-01-03 09:26:43 +04:00
|
|
|
if (got_atime == 0)
|
|
|
|
tv[0] = tv[1];
|
|
|
|
else if (verbose)
|
|
|
|
printf("Using original atime\n");
|
2014-10-20 06:02:48 +04:00
|
|
|
set_utimes(outfn, fileno(old), tv);
|
2004-04-03 22:53:46 +04:00
|
|
|
}
|
2015-09-19 04:37:53 +03:00
|
|
|
if (ofd >= 0)
|
|
|
|
(void) fchmod(ofd, 0444);
|
2014-01-03 09:26:43 +04:00
|
|
|
fclose(out);
|
|
|
|
if (unlink(newfn) < 0)
|
|
|
|
perror("unlink");
|
1997-10-15 06:47:20 +04:00
|
|
|
} else {
|
|
|
|
if (verbose)
|
|
|
|
printf("Creating or replacing %s.\n", outfn);
|
2015-09-19 04:37:53 +03:00
|
|
|
if (ofd >= 0)
|
|
|
|
(void) fchmod(ofd, 0444);
|
2014-01-03 09:26:43 +04:00
|
|
|
fclose(out);
|
|
|
|
if (old)
|
|
|
|
fclose(old);
|
|
|
|
old = NULL;
|
|
|
|
if (rename(newfn, outfn) < 0) {
|
|
|
|
perror("rename");
|
|
|
|
exit(1);
|
|
|
|
}
|
1997-10-15 06:47:20 +04:00
|
|
|
}
|
|
|
|
}
|
2014-01-03 09:26:43 +04:00
|
|
|
if (old)
|
|
|
|
fclose(old);
|
2014-03-14 17:34:10 +04:00
|
|
|
if (newfn)
|
|
|
|
free(newfn);
|
1997-10-15 06:47:20 +04:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|