1/*
2
3	Tomato Firmware
4	Copyright (C) 2006-2009 Jonathan Zarate
5
6*/
7
8#include <string.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <unistd.h>
12#include <fcntl.h>
13#include <sys/stat.h>
14#include <stdarg.h>
15#include <dirent.h>
16#include <bcmnvram.h>
17#include <syslog.h>
18#include <sys/file.h>
19#include "shutils.h"
20#include "shared.h"
21
22
23int f_exists(const char *path)	// note: anything but a directory
24{
25	struct stat st;
26	return (stat(path, &st) == 0) && (!S_ISDIR(st.st_mode));
27}
28
29int d_exists(const char *path)	//  directory only
30{
31	struct stat st;
32	return (stat(path, &st) == 0) && (S_ISDIR(st.st_mode));
33}
34
35unsigned long f_size(const char *path)	// 4GB-1	-1 = error
36{
37	struct stat st;
38	if (stat(path, &st) == 0) return st.st_size;
39	return (unsigned long)-1;
40}
41
42int f_read_excl(const char *path, void *buffer, int max)
43{
44	int f;
45	int n;
46
47	if ((f = open(path, O_RDONLY)) < 0) return -1;
48	flock(f, LOCK_EX);
49	n = read(f, buffer, max);
50	flock(f, LOCK_UN);
51	close(f);
52	return n;
53}
54
55int f_read(const char *path, void *buffer, int max)
56{
57	int f;
58	int n;
59
60	if ((f = open(path, O_RDONLY)) < 0) return -1;
61	n = read(f, buffer, max);
62	close(f);
63	return n;
64}
65
66int f_write_excl(const char *path, const void *buffer, int len, unsigned flags, unsigned cmode)
67{
68	static const char nl = '\n';
69	int f, fl;
70	int r = -1;
71	mode_t m;
72
73	m = umask(0);
74	if (cmode == 0) cmode = 0666;
75	if ((fl = open(ACTION_LOCK_FILE, O_WRONLY|O_CREAT|O_EXCL|O_TRUNC, 0600)) >= 0) { // own the lock
76		if (( f = open(path, (flags & FW_APPEND) ? (O_WRONLY|O_CREAT|O_APPEND) : (O_WRONLY|O_CREAT|O_TRUNC), cmode)) >= 0) {
77			flock(f, LOCK_EX);
78			if ((buffer == NULL) || ((r = write(f, buffer, len)) == len)) {
79				if (flags & FW_NEWLINE) {
80					if (write(f, &nl, 1) == 1) ++r;
81				}
82			}
83			flock(f, LOCK_UN);
84			close(f);
85		}
86		close(fl);
87		unlink(ACTION_LOCK_FILE);
88	}
89	umask(m);
90	return r;
91}
92
93int f_write(const char *path, const void *buffer, int len, unsigned flags, unsigned cmode)
94{
95	static const char nl = '\n';
96	int f;
97	int r = -1;
98	mode_t m;
99
100	m = umask(0);
101	if (cmode == 0) cmode = 0666;
102	if ((f = open(path, (flags & FW_APPEND) ? (O_WRONLY|O_CREAT|O_APPEND) : (O_WRONLY|O_CREAT|O_TRUNC), cmode)) >= 0) {
103		if ((buffer == NULL) || ((r = write(f, buffer, len)) == len)) {
104			if (flags & FW_NEWLINE) {
105				if (write(f, &nl, 1) == 1) ++r;
106			}
107		}
108		close(f);
109	}
110	umask(m);
111	return r;
112}
113
114int f_read_string(const char *path, char *buffer, int max)
115{
116	if (max <= 0) return -1;
117	int n = f_read(path, buffer, max - 1);
118	buffer[(n > 0) ? n : 0] = 0;
119	return n;
120}
121
122int f_write_string(const char *path, const char *buffer, unsigned flags, unsigned cmode)
123{
124	return f_write(path, buffer, strlen(buffer), flags, cmode);
125}
126
127static int _f_read_alloc(const char *path, char **buffer, int max, int z)
128{
129	unsigned long n;
130
131	*buffer = NULL;
132	if (max >= 0) {
133		if ((n = f_size(path)) != (unsigned long)-1) {
134			if (n < max) max = n;
135			if ((!z) && (max == 0)) return 0;
136			if ((*buffer = malloc(max + z)) != NULL) {
137				if ((max = f_read(path, *buffer, max)) >= 0) {
138					if (z) *(*buffer + max) = 0;
139					return max;
140				}
141				free(buffer);
142			}
143		}
144	}
145	return -1;
146}
147
148int f_read_alloc(const char *path, char **buffer, int max)
149{
150	return _f_read_alloc(path, buffer, max, 0);
151}
152
153int f_read_alloc_string(const char *path, char **buffer, int max)
154{
155	return _f_read_alloc(path, buffer, max, 1);
156}
157
158static int _f_wait_exists(const char *name, int max, int invert)
159{
160	while (max-- > 0) {
161		if (f_exists(name) ^ invert) return 1;
162		sleep(1);
163	}
164	return 0;
165}
166
167int f_wait_exists(const char *name, int max)
168{
169	return _f_wait_exists(name, max, 0);
170}
171
172int f_wait_notexists(const char *name, int max)
173{
174	return _f_wait_exists(name, max, 1);
175}
176
177int
178check_if_dir_exist(const char *dirpath)
179{
180	return d_exists(dirpath);
181}
182
183int
184check_if_dir_empty(const char *dirpath)
185{
186	DIR *dir;
187	struct dirent *dirent;
188	int found=0;
189
190	if((dir=opendir(dirpath))!=NULL) {
191		while ((dirent=readdir(dir))!=NULL) {
192			if(strcmp(dirent->d_name, ".") && strcmp(dirent->d_name, "..")) {
193				found=1;
194				break;
195			}
196
197		}
198		closedir(dir);
199	}
200	return found;
201}
202
203int
204check_if_file_exist(const char *filepath)
205{
206/* Note: f_exists() checks not S_ISREG, but !S_ISDIR
207	struct stat st;
208	return (stat(path, &st) == 0) && (S_ISREG(st.st_mode));
209*/
210	return f_exists(filepath);
211}
212
213/* Test whether we can write to a directory.
214 * @return:
215 * 0		not writable
216 * -1		invalid parameter
217 * otherwise	writable
218 */
219int check_if_dir_writable(const char *dir)
220{
221	char tmp[PATH_MAX];
222	FILE *fp;
223	int ret = 0;
224
225	if (!dir || *dir == '\0')
226		return -1;
227
228	sprintf(tmp, "%s/.test_dir_writable", dir);
229	if ((fp = fopen(tmp, "w")) != NULL) {
230		fclose(fp);
231		unlink(tmp);
232		ret = 1;
233	}
234
235	return ret;
236}
237
238
239/* Serialize using fcntl() calls
240 */
241
242int file_lock(char *tag)
243{
244        char fn[64];
245        struct flock lock;
246        int lockfd = -1;
247        pid_t lockpid;
248
249        sprintf(fn, "/var/lock/%s.lock", tag);
250        if ((lockfd = open(fn, O_CREAT | O_RDWR, 0666)) < 0)
251                goto lock_error;
252
253        pid_t pid = getpid();
254        if (read(lockfd, &lockpid, sizeof(pid_t))) {
255                // check if we already hold a lock
256                if (pid == lockpid) {
257                        // don't close the file here as that will release all locks
258                        return -1;
259                }
260        }
261
262        memset(&lock, 0, sizeof(lock));
263        lock.l_type = F_WRLCK;
264        lock.l_pid = pid;
265
266        if (fcntl(lockfd, F_SETLKW, &lock) < 0) {
267                close(lockfd);
268                goto lock_error;
269        }
270
271        lseek(lockfd, 0, SEEK_SET);
272        write(lockfd, &pid, sizeof(pid_t));
273        return lockfd;
274lock_error:
275        // No proper error processing
276        syslog(LOG_DEBUG, "Error %d locking %s, proceeding anyway", errno, fn);
277        return -1;
278}
279
280void file_unlock(int lockfd)
281{
282        if (lockfd >= 0) {
283                ftruncate(lockfd, 0);
284                close(lockfd);
285        } else
286        	syslog(LOG_DEBUG, "Error %d un-locking, proceeding anyway", errno);
287}
288