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