OSDN Git Service

Add MS7619SE
[uclinux-h8/uClinux-dist.git] / tools / ucfront / util.c
1 /*
2    Copyright (C) Andrew Tridgell 2002
3    
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8    
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13    
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include "ucfront.h"
20
21 static FILE *logfile;
22
23 /* log a message to the UCFRONT_LOGFILE location */
24 void cc_log(const char *format, ...)
25 {
26         va_list ap;
27         extern char *cache_logfile;
28
29         if (!cache_logfile) return;
30
31         if (!logfile) {
32                 if (strcmp(cache_logfile, "stderr") == 0)
33                         logfile = stderr;
34                 else if (strcmp(cache_logfile, "stdout") == 0)
35                         logfile = stdout;
36                 else
37                         logfile = fopen(cache_logfile, "a");
38         }
39
40         if (!logfile)
41                 return;
42         
43         va_start(ap, format);
44         vfprintf(logfile, format, ap);
45         va_end(ap);
46         fflush(logfile);
47 }
48
49 /* something went badly wrong! */
50 void fatal(const char *format, ...)
51 {
52         va_list args;
53
54         fprintf(stderr, "FATAL: ");
55         va_start(args, format);
56         vfprintf(stderr, format, args);
57         va_end(args);
58         fprintf(stderr, "\n");
59         exit(1);
60 }
61
62 /* copy all data from one file descriptor to another */
63 void copy_fd(int fd_in, int fd_out)
64 {
65         char buf[10240];
66         int n;
67
68         while ((n = read(fd_in, buf, sizeof(buf))) > 0) {
69                 if (write(fd_out, buf, n) != n) {
70                         fatal("Failed to copy fd");
71                 }
72         }
73 }
74
75 /* copy a file - used when hard links don't work 
76    the copy is done via a temporary file and atomic rename
77 */
78 int copy_file(const char *src, const char *dest)
79 {
80         int fd1, fd2;
81         char buf[10240];
82         int n;
83         char *tmp_name;
84         mode_t mask;
85
86         x_asprintf(&tmp_name, "%s.XXXXXX", dest);
87
88         fd1 = open(src, O_RDONLY);
89         if (fd1 == -1) {
90                 free(tmp_name);
91                 return -1;
92         }
93
94         fd2 = mkstemp(tmp_name);
95         if (fd2 == -1) {
96                 close(fd1);
97                 free(tmp_name);
98                 return -1;
99         }
100
101         while ((n = read(fd1, buf, sizeof(buf))) > 0) {
102                 if (write(fd2, buf, n) != n) {
103                         close(fd2);
104                         close(fd1);
105                         unlink(tmp_name);
106                         free(tmp_name);
107                         return -1;
108                 }
109         }
110
111         close(fd1);
112
113         /* get perms right on the tmp file */
114         mask = umask(0);
115         fchmod(fd2, 0666 & ~mask);
116         umask(mask);
117
118         /* the close can fail on NFS if out of space */
119         if (close(fd2) == -1) {
120                 unlink(tmp_name);
121                 free(tmp_name);
122                 return -1;
123         }
124
125         unlink(dest);
126
127         if (rename(tmp_name, dest) == -1) {
128                 unlink(tmp_name);
129                 free(tmp_name);
130                 return -1;
131         }
132
133         free(tmp_name);
134
135         return 0;
136 }
137
138
139 /* make sure a directory exists */
140 int create_dir(const char *dir)
141 {
142         struct stat st;
143         if (stat(dir, &st) == 0) {
144                 if (S_ISDIR(st.st_mode)) {
145                         return 0;
146                 }
147                 errno = ENOTDIR;
148                 return 1;
149         }
150         if (mkdir(dir, 0777) != 0 && errno != EEXIST) {
151                 return 1;
152         }
153         return 0;
154 }
155
156 /*
157   this is like asprintf() but dies if the malloc fails
158   here we just use vasprintf() to do the work for us.
159 */
160 void x_asprintf(char **ptr, const char *format, ...)
161 {
162         va_list ap;
163
164         *ptr = NULL;
165         va_start(ap, format);
166         if (vasprintf(ptr, format, ap) == -1) {
167                 fatal("out of memory in x_asprintf");
168         }
169         va_end(ap);
170         
171 }
172
173 /*
174   this is like strdup() but dies if the malloc fails
175 */
176 char *x_strdup(const char *s)
177 {
178         char *ret;
179         ret = strdup(s);
180         if (!ret) {
181                 fatal("out of memory in strdup\n");
182         }
183         return ret;
184 }
185
186 /*
187   this is like malloc() but dies if the malloc fails
188 */
189 void *x_malloc(size_t size)
190 {
191         void *ret;
192         ret = malloc(size);
193         if (!ret) {
194                 fatal("out of memory in malloc\n");
195         }
196         return ret;
197 }
198
199 /*
200   this is like realloc() but dies if the malloc fails
201 */
202 void *x_realloc(void *ptr, size_t size)
203 {
204         void *p2;
205         if (!ptr) return x_malloc(size);
206         p2 = malloc(size);
207         if (!p2) {
208                 fatal("out of memory in x_realloc");
209         }
210         if (ptr) {
211                 memcpy(p2, ptr, size);
212                 free(ptr);
213         }
214         return p2;
215 }
216
217
218 /* 
219    revsusive directory traversal - used for cleanup
220    fn() is called on all files/dirs in the tree
221  */
222 void traverse(const char *dir, void (*fn)(const char *, struct stat *))
223 {
224         DIR *d;
225         struct dirent *de;
226
227         d = opendir(dir);
228         if (!d) return;
229
230         while ((de = readdir(d))) {
231                 char *fname;
232                 struct stat st;
233
234                 if (strcmp(de->d_name,".") == 0) continue;
235                 if (strcmp(de->d_name,"..") == 0) continue;
236
237                 if (strlen(de->d_name) == 0) continue;
238
239                 x_asprintf(&fname, "%s/%s", dir, de->d_name);
240                 if (lstat(fname, &st)) {
241                         if (errno != ENOENT) {
242                                 perror(fname);
243                         }
244                         free(fname);
245                         continue;
246                 }
247
248                 if (S_ISDIR(st.st_mode)) {
249                         traverse(fname, fn);
250                 }
251
252                 fn(fname, &st);
253                 free(fname);
254         }
255
256         closedir(d);
257 }
258
259
260 /* return the base name of a file - caller frees */
261 char *str_basename(const char *s)
262 {
263         char *p = strrchr(s, '/');
264         if (p) {
265                 return x_strdup(p+1);
266         } 
267
268         return x_strdup(s);
269 }
270
271 /* return the dir name of a file - caller frees */
272 char *dirname(char *s)
273 {
274         char *p;
275         s = x_strdup(s);
276         p = strrchr(s, '/');
277         if (p) {
278                 *p = 0;
279         } 
280         return s;
281 }
282
283 int lock_fd(int fd)
284 {
285         struct flock fl;
286         int ret;
287
288         fl.l_type = F_WRLCK;
289         fl.l_whence = SEEK_SET;
290         fl.l_start = 0;
291         fl.l_len = 1;
292         fl.l_pid = 0;
293
294         /* not sure why we would be getting a signal here,
295            but one user claimed it is possible */
296         do {
297                 ret = fcntl(fd, F_SETLKW, &fl);
298         } while (ret == -1 && errno == EINTR);
299         return ret;
300 }
301
302 /* return size on disk of a file */
303 size_t file_size(struct stat *st)
304 {
305         size_t size = st->st_blocks * 512;
306         if ((size_t)st->st_size > size) {
307                 /* probably a broken stat() call ... */
308                 size = (st->st_size + 1023) & ~1023;
309         }
310         return size;
311 }
312
313
314 /* a safe open/create for read-write */
315 int safe_open(const char *fname)
316 {
317         int fd = open(fname, O_RDWR);
318         if (fd == -1 && errno == ENOENT) {
319                 fd = open(fname, O_RDWR|O_CREAT|O_EXCL, 0666);
320                 if (fd == -1 && errno == EEXIST) {
321                         fd = open(fname, O_RDWR);
322                 }
323         }
324         return fd;
325 }
326
327 /* display a kilobyte unsigned value in M, k or G */
328 void display_size(unsigned v)
329 {
330         if (v > 1024*1024) {
331                 printf("%8.1f Gbytes", v/((double)(1024*1024)));
332         } else if (v > 1024) {
333                 printf("%8.1f Mbytes", v/((double)(1024)));
334         } else {
335                 printf("%8u Kbytes", v);
336         }
337 }
338
339 /* return a value in multiples of 1024 give a string that can end
340    in K, M or G
341 */
342 size_t value_units(const char *s)
343 {
344         char m;
345         double v = atof(s);
346         m = s[strlen(s)-1];
347         switch (m) {
348         case 'G':
349         case 'g':
350         default:
351                 v *= 1024*1024;
352                 break;
353         case 'M':
354         case 'm':
355                 v *= 1024;
356                 break;
357         case 'K':
358         case 'k':
359                 v *= 1;
360                 break;
361         }
362         return (size_t)v;
363 }
364
365
366 /*
367   a sane realpath() function, trying to cope with stupid path limits and 
368   a broken API
369 */
370 char *x_realpath(const char *path)
371 {
372         int maxlen;
373         char *ret, *p;
374 #ifdef PATH_MAX
375         maxlen = PATH_MAX;
376 #elif defined(MAXPATHLEN)
377         maxlen = MAXPATHLEN;
378 #elif defined(_PC_PATH_MAX)
379         maxlen = pathconf(path, _PC_PATH_MAX);
380 #endif
381         if (maxlen < 4096) maxlen = 4096;
382         
383         ret = x_malloc(maxlen);
384
385 #if HAVE_REALPATH
386         p = realpath(path, ret);
387 #else
388         /* yes, there are such systems. This replacement relies on
389            the fact that when we call x_realpath we only care about symlinks */
390         {
391                 int len = readlink(path, ret, maxlen-1);
392                 if (len == -1) {
393                         free(ret);
394                         return NULL;
395                 }
396                 ret[len] = 0;
397                 p = ret;
398         }
399 #endif
400         if (p) {
401                 p = x_strdup(p);
402                 free(ret);
403                 return p;
404         }
405         free(ret);
406         return NULL;
407 }
408
409 /* a getcwd that will returns an allocated buffer */
410 char *gnu_getcwd(void)
411 {
412         unsigned size = 128;
413
414         while (1) {
415                 char *buffer = (char *)x_malloc(size);
416                 if (getcwd(buffer, size) == buffer) {
417                         return buffer;
418                 }
419                 free(buffer);
420                 if (errno != ERANGE) {
421                         return 0;
422                 }
423                 size *= 2;
424         }
425 }
426
427 #ifndef HAVE_MKSTEMP
428 /* cheap and nasty mkstemp replacement */
429 int mkstemp(char *template)
430 {
431         mktemp(template);
432         return open(template, O_RDWR | O_CREAT | O_EXCL, 0600);
433 }
434 #endif
435
436
437 /* create an empty file */
438 int create_empty_file(const char *fname)
439 {
440         int fd;
441
442         fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0666);
443         if (fd == -1) {
444                 return -1;
445         }
446         close(fd);
447         return 0;
448 }