File: utils.c

package info (click to toggle)
dhcp-probe 1.3.0-10.1
  • links: PTS
  • area: main
  • in suites: bookworm, bullseye, buster, jessie, jessie-kfreebsd, stretch, trixie
  • size: 1,312 kB
  • ctags: 250
  • sloc: sh: 4,294; ansic: 2,305; perl: 279; makefile: 98
file content (166 lines) | stat: -rw-r--r-- 4,616 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/* Miscellaneous utilities:
    open_for_writing()
    smalloc()
    open_append()
*/

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include "defs.h"

#include <stdio.h> /* for fdopen */
#include <sys/stat.h>  /* for stat, open*/
#include <errno.h>

#include <strings.h> 
#include <stdlib.h>

#ifdef HAVE_UNISTD_H
#include <unistd.h> /* for setuid/seteuid/setgid/setegid, unlink */
#endif

#ifdef HAVE_FCNTL_H
#include <fcntl.h> /* for open */
#else /* not HAVE_FCNTL_H */
#ifdef HAVE_SYS_FILE_H
#include <sys/file.h> /* for open, O_ constants defined here on BSD systems */
#endif /* HAVE_SYS_FILE_H */
#endif /* not HAVE_FCNTL_H */

#include <sys/stat.h> /* for stat, open */

#include "dhcp_probe.h"
#include "utils.h"
#include "report.h"


FILE *
open_for_writing(char * filename) 
{
/*	Open a regular file for writing.
	If the file already exists, it will be removed first.
	On error we return NULL and log an error message.
	Based closely on write_open() from BIND 8.1.2.
*/
	int fd;
	FILE *stream;
	struct stat stat_buffer;

	if (stat(filename, &stat_buffer) < 0) {
		if (errno != ENOENT) {
			report(LOG_ERR, "open_for_writing(): stat of %s failed: %s", filename, get_errmsg());
			return NULL;
		} 
	} else { /* filename already exists */
		if (!(stat_buffer.st_mode & S_IFREG)) {
			/* since we just want to open a regular file for writing, its existance as a special
			   file probably means something is wrong, so let's TRY to avoid removing it. */
			report(LOG_ERR, "open_for_writing(): %s exists but isn't a regular file", filename);
			return(NULL);
		}
	}

	/* At this point, filename either does not exist, or already exists as a regular file.
	   Either way, it's toast.  Note that it is possible for it's status to have changed since
	   we checked earlier; e.g. it may have changed from non-existance to existance as a special file.
	   So it's still possible we'll wipe out a special file, but we've made an effort to avoid it. */
	if (unlink(filename) < 0) {
		if (errno != ENOENT) {
			report(LOG_ERR, "open_for_writing(): unlink of %s failed: %s", filename, get_errmsg());
			return NULL;
		}
	}

	/* Use open() to get the atomic behavior provided by O_CREAT|O_EXCL.  If it succeeds,
	   convert the file descriptor into a file stream, which is what we're supposed to return. */
	fd = open(filename, O_WRONLY|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
	if (fd < 0) {
		report(LOG_ERR, "open_for_writing(): open of %s failed: %s", filename, get_errmsg());
		return NULL;
	}
	stream = fdopen(fd, "w");
	if (stream == NULL) {
		report(LOG_ERR, "open_for_writing(): fdopen failed: %s", get_errmsg());
		(void) close(fd);
		return NULL;
	}
	return(stream);
}


void *
smalloc(size_t size, int init)
{
/*	safe malloc()
	Always returns a valid pointer (if it returns at all).  The allocated
	memory is initialized to all zeros if 'init' is non-zero.  
	If malloc() returns an error, a
	message is printed using the report() function and the program aborts
	with a status of 1.
*/


	void *rc;

	rc = malloc(size);
	if (!rc) {
		report(LOG_ERR, "malloc() failed");
		my_exit(1, 1, 1);
	}

	if (init)
		bzero((char *) rc, size);

	return rc;
}


FILE *
open_append(char *filename)
{
/*	Open a regular file for appending.
	If the file does not exist, it will be created.
	On error we return NULL and log an error message.
	(Note that if logging is going to the same file we are trying to open, the error message may be lost.)
	Based closely on write_open() from BIND 8.1.2.
*/
	int fd;
	FILE *stream;
	struct stat stat_buffer;


	fd = open(filename, O_WRONLY|O_APPEND|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
	if (fd < 0) {
		report(LOG_ERR, "open_append(): open of %s failed: %s", filename, get_errmsg());
		return NULL;
	}

	/* Verify that the file (if it already exists) is a regular file.
	   We do this after the open to avoid a race condition.
	*/
	if (stat(filename, &stat_buffer) < 0) {
		if (errno != ENOENT) {
			close(fd);
			report(LOG_ERR, "open_append(): stat of %s failed; %s", filename, get_errmsg());
			return NULL;
		}
	} else { /* filename already exists */
		if (!(stat_buffer.st_mode & S_IFREG)) {
			/* since we just want to open a regular file for appending, its existance as a special
			   file probably means something is wrong, so let's TRY to avoid stepping on it. */
			close(fd);
			report(LOG_ERR, "open_append(): %s exists but isn't a regular file", filename);
			return NULL;
		}
	}

	stream = fdopen(fd, "a");
	if (stream == NULL) {
		report(LOG_ERR, "open_append(): fdopen failed: %s", get_errmsg());
		close(fd);
		return NULL;
	}
	return stream;
}