1 /*
2 * Copyright (C) 1998-9 Pancrazio `Ezio' de Mauro <p@demauro.net>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (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 * $Id: installwatch.c,v 0.6.3.2 2001/12/22 23:01:20 izto Exp $
19 *
20 * april-15-2001 - Modifications by Felipe Eduardo Sanchez Diaz Duran
21 * <izto@asic-linux.com.mx>
22 * Added backup() and make_path() functions.
23 */
24
25 #include <sys/param.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <stdarg.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <dlfcn.h>
33 #include <syslog.h>
34 #include <errno.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <time.h>
38 #include <dlfcn.h>
39
40 #include "localdecls.h"
41
42 /* #define DEBUG 1 */
43
44 #define LOGLEVEL (LOG_USER | LOG_INFO | LOG_PID)
45 #define BUFSIZE 1024
46
47 #define error(X) (X < 0 ? strerror(errno) : "success")
48
49 int __installwatch_refcount = 0;
50 int __installwatch_timecount = 0;
51
52 #define REFCOUNT __installwatch_refcount++
53 #define TIMECOUNT __installwatch_timecount++
54
55 static time_t (*true_time) (time_t *);
56 static int(*true_chmod)(const char *, mode_t);
57 static int(*true_chown)(const char *, uid_t, gid_t);
58 static int(*true_chroot)(const char *);
59 static int(*true_creat)(const char *, mode_t);
60 static int(*true_fchmod)(int, mode_t);
61 static int(*true_fchown)(int, uid_t, gid_t);
62 static FILE *(*true_fopen)(const char *,const char*);
63 static int(*true_ftruncate)(int, TRUNCATE_T);
64 static int(*true_lchown)(const char *, uid_t, gid_t);
65 static int(*true_link)(const char *, const char *);
66 static int(*true_mkdir)(const char *, mode_t);
67 static int(*true_open)(const char *, int, ...);
68 static int(*true_rename)(const char *, const char *);
69 static int(*true_rmdir)(const char *);
70 static int(*true_symlink)(const char *, const char *);
71 static int(*true_truncate)(const char *, TRUNCATE_T);
72 static int(*true_unlink)(const char *);
73
74 #if(GLIBC_MINOR >= 1)
75
76 static int(*true_creat64)(const char *, __mode_t);
77 static FILE *(*true_fopen64)(const char *,const char *);
78 static int(*true_ftruncate64)(int, __off64_t);
79 static int(*true_open64)(const char *, int, ...);
80 static int(*true_truncate64)(const char *, __off64_t);
81
82 #endif
83
84 static void log(const char *format, ...)
85 #ifdef __GNUC__
86 /* Tell gcc that this function behaves like printf()
87 * for parameters 1 and 2 */
88 __attribute__((format(printf, 1, 2)))
89 #endif /* defined __GNUC__ */
90 ;
91
_init(void)92 void _init(void) {
93
94 void *libc_handle;
95
96 #ifdef BROKEN_RTLD_NEXT
97 // printf ("RTLD_LAZY");
98 libc_handle = dlopen(LIBC_VERSION, RTLD_LAZY);
99 #else
100 // printf ("RTLD_NEXT");
101 libc_handle = RTLD_NEXT;
102 #endif
103
104
105 true_time = dlsym(libc_handle, "time");
106 true_chmod = dlsym(libc_handle, "chmod");
107 true_chown = dlsym(libc_handle, "chown");
108 true_chroot = dlsym(libc_handle, "chroot");
109 true_creat = dlsym(libc_handle, "creat");
110 true_fchmod = dlsym(libc_handle, "fchmod");
111 true_fchown = dlsym(libc_handle, "fchown");
112 true_fopen = dlsym(libc_handle, "fopen");
113 true_ftruncate = dlsym(libc_handle, "ftruncate");
114 true_lchown = dlsym(libc_handle, "lchown");
115 true_link = dlsym(libc_handle, "link");
116 true_mkdir = dlsym(libc_handle, "mkdir");
117 true_open = dlsym(libc_handle, "open");
118 true_rename = dlsym(libc_handle, "rename");
119 true_rmdir = dlsym(libc_handle, "rmdir");
120 true_symlink = dlsym(libc_handle, "symlink");
121 true_truncate = dlsym(libc_handle, "truncate");
122 true_unlink = dlsym(libc_handle, "unlink");
123
124 #if(GLIBC_MINOR >= 1)
125 true_creat64 = dlsym(libc_handle, "creat64");
126 true_fopen64 = dlsym(libc_handle, "fopen64");
127 true_ftruncate64 = dlsym(libc_handle, "ftruncate64");
128 true_open64 = dlsym(libc_handle, "open64");
129 true_truncate64 = dlsym(libc_handle, "truncate64");
130 #endif
131
132 }
133
log(const char * format,...)134 static void log(const char *format, ...) {
135 char buffer[BUFSIZE], *logname;
136 va_list ap;
137 int count, logfd;
138
139 va_start(ap, format);
140 count = vsnprintf(buffer, BUFSIZE, format, ap);
141 va_end(ap);
142 if(count == -1) {
143 /* The buffer was not big enough */
144 strcpy(&(buffer[BUFSIZE - 5]), "...\n");
145 count = BUFSIZE - 1;
146 }
147 if((logname = getenv("INSTALLWATCHFILE"))) {
148 logfd = true_open(logname, O_WRONLY | O_CREAT | O_APPEND, 0666);
149 if(logfd >= 0) {
150 if(write(logfd, buffer, count) != count)
151 syslog(LOGLEVEL, "Count not write `%s' in `%s': %s\n", buffer, logname, strerror(errno));
152 if(close(logfd) < 0)
153 syslog(LOGLEVEL, "Could not close `%s': %s\n", logname, strerror(errno));
154 } else
155 syslog(LOGLEVEL, "Could not open `%s' to write `%s': %s\n", logname, buffer, strerror(errno));
156
157 } else
158 syslog(LOGLEVEL, buffer);
159 }
160
canonicalize(const char * path,char * resolved_path)161 static void canonicalize(const char *path, char *resolved_path) {
162 if(!realpath(path, resolved_path) && (path[0] != '/')) {
163 /* The path could not be canonicalized, append it
164 * to the current working directory if it was not
165 * an absolute path */
166 getcwd(resolved_path, MAXPATHLEN - 2);
167 strcat(resolved_path, "/");
168 strncat(resolved_path, path, MAXPATHLEN - 1);
169 }
170 }
171
make_path(char * path)172 static void make_path (char *path) {
173 char checkdir[BUFSIZ];
174 struct stat inode;
175 int i = 0;
176
177 #if DEBUG
178 printf ("===== make_path: %s\n", path);
179 #endif
180
181 while ( path[i] != '\0' ) {
182 checkdir[i] = path[i];
183 if (checkdir[i] == '/') { /* Each time a '/' is found, check if the */
184 checkdir[i+1] = '\0'; /* path exists. If it doesn't, we create it. */
185 if (stat (checkdir, &inode) < 0)
186 true_mkdir (checkdir, S_IRWXU);
187 }
188 i++;
189 }
190
191 }
192
193
194
backup(char * path)195 static void backup(char *path) {
196
197 char buffer[BUFSIZ];
198 char checkdir[BUFSIZ];
199 char backup_path[BUFSIZ];
200 int orig,
201 dest,
202 placeholder,
203 bytes,
204 i,
205 blen;
206
207
208 struct stat inode, newinode, backup_inode;
209
210 #if DEBUG
211 printf ("========= backup () =========\npath: %s\n", path);
212 #endif
213
214 /* If INSTALLWATCH_BACKUP_PATH is not defined then we won't do the backup */
215 if (!getenv("INSTALLWATCH_BACKUP_PATH")) {
216 #ifdef DEBUG
217 printf ("Backup not enabled, path: %s\n", path);
218 #endif
219 return;
220 }
221
222
223 /* Check if this is inside /dev */
224 if (strstr (path, "/dev") == path) {
225 #if DEBUG
226 printf ("%s is inside /dev. Ignoring.\n", path);
227 #endif
228 return;
229 }
230
231 /* Now check for /tmp */
232 if (strstr (path, "/tmp") == path) {
233 #if DEBUG
234 printf ("%s is inside /tmp. Ignoring.\n", path);
235 #endif
236 return;
237 }
238
239 /* Finally, the backup path itself */
240 if (strstr (path, getenv("INSTALLWATCH_BACKUP_PATH")) == path) {
241 #if DEBUG
242 printf ("%s is inside the backup path. Ignoring.\n", path);
243 #endif
244 return;
245 }
246
247
248 /* Does it exist already? */
249 #if DEBUG
250 printf ("Existe %s?\n", path);
251 #endif
252 if (stat(path, &inode) < 0) {
253
254 /* It doesn't exist, we'll tag it so we won't back it up */
255 /* if we run into it later */
256
257 strcpy (backup_path, getenv ("INSTALLWATCH_BACKUP_PATH"));
258 strncat (backup_path, "/no-backup/", 11);
259 strcat (backup_path, path);
260 make_path(backup_path);
261
262 /* This one's just a placeholder */
263 placeholder = true_creat(backup_path, S_IREAD);
264 if (!(placeholder < 0)) close (placeholder);
265
266 #if DEBUG
267 printf ("NO EXISTE\n");
268 #endif
269 return;
270 }
271
272
273 /* Is this one tagged for no backup (i.e. it didn't previously exist)? */
274
275
276 strcpy (backup_path, getenv ("INSTALLWATCH_BACKUP_PATH"));
277 strncat (backup_path, "/no-backup/", 11);
278 strcat (backup_path, path);
279
280 if (stat (backup_path, &backup_inode) >= 0) {
281 #if DEBUG
282 printf ("%s no debe ser respaldado", backup_path);
283 #endif
284 return;
285 }
286
287
288 #if DEBUG
289 printf ("Si existe, veamos de que tipo es.\n");
290 #endif
291
292 /* Append the path to the backup_path */
293
294 strcpy (backup_path, getenv ("INSTALLWATCH_BACKUP_PATH"));
295 strcat (backup_path, path);
296
297
298 /* Create the directory tree for this file in the backup dir */
299 make_path (backup_path);
300
301 /* What kind of file is this? */
302
303 /* Regular file */
304 if (S_ISREG(inode.st_mode)) {
305 #if DEBUG
306 printf ("%s es un archivo regular\n", path);
307 #endif
308 if ( (orig = true_open (path, O_RDONLY)) < 0) return;
309
310 /* Write the backup */
311 if ( (dest = true_open (backup_path, O_WRONLY|O_CREAT|O_TRUNC, inode.st_mode)) < 0) {
312 close (orig);
313 return ;
314 }
315
316 while ( (bytes = read (orig, buffer, BUFSIZ)) > 0)
317 write (dest, buffer, bytes);
318 close( dest );
319 close( orig );
320 }
321
322
323 /* Directory */
324 if (S_ISDIR(inode.st_mode)) {
325 #if DEBUG
326 printf ("%s es un directorio\n", path);
327 #endif
328 true_mkdir (backup_path, inode.st_mode);
329 }
330
331
332 /* Block special */
333
334 /* Since we're ignoring everything under /dev,
335 * this one will be hard to find. */
336
337 if (S_ISBLK(inode.st_mode)) {
338 #if DEBUG
339 printf ("%s es un blkspecial\n", path);
340 #endif
341 mknod (backup_path, inode.st_mode | S_IFBLK, inode.st_rdev);
342 }
343
344
345 /* Character special */
346 if (S_ISCHR(inode.st_mode)) {
347 #if DEBUG
348 printf ("%s es un charspecial\n", path);
349 #endif
350 mknod (backup_path, inode.st_mode | S_IFCHR, inode.st_rdev);
351 }
352
353
354 /* FIFO */
355 if (S_ISFIFO(inode.st_mode)) {
356 #if DEBUG
357 printf ("%s es un fifo\n", path);
358 #endif
359 mknod (backup_path, inode.st_mode | S_IFIFO, 0);
360 }
361
362 /* If we have a new file, set it to the right owner and group */
363 if (!stat (path, &newinode)) true_chown (backup_path, inode.st_uid, inode.st_gid);
364
365
366 /* Check the owner and permission of the created directories */
367 i=0;
368 blen = strlen (getenv ("INSTALLWATCH_BACKUP_PATH"));
369 while ( path[i] != '\0' ) {
370 checkdir[i] = backup_path[blen+i] = path[i];
371 if (checkdir[i] == '/') { /* Each time a '/' is found, check if the */
372 checkdir[i+1] = '\0'; /* path exists. If it does, set it's perms. */
373 if (!stat (checkdir, &inode)) {
374 backup_path[blen+i+1]='\0';
375 true_chmod (backup_path, inode.st_mode);
376 true_chown (backup_path, inode.st_uid, inode.st_gid);
377 }
378 }
379 i++;
380 }
381
382 }
383
time(time_t * timer)384 time_t time (time_t *timer) {
385 TIMECOUNT;
386
387 #if DEBUG
388 puts("time\n");
389 #endif
390
391 return true_time(timer);
392 }
393
chmod(const char * path,mode_t mode)394 int chmod(const char *path, mode_t mode) {
395 int result;
396 char canonic[MAXPATHLEN];
397
398 REFCOUNT;
399 canonicalize(path, canonic);
400
401 #if DEBUG
402 puts ("in installwatch chmod\n");
403 #endif
404 backup (canonic);
405
406 result = true_chmod(path, mode);
407 log("%d\tchmod\t%s\t0%04o\t#%s\n", result, canonic, mode, error(result));
408 return result;
409 }
410
chown(const char * path,uid_t owner,gid_t group)411 int chown(const char *path, uid_t owner, gid_t group) {
412 int result;
413 char canonic[MAXPATHLEN];
414
415 REFCOUNT;
416 canonicalize(path, canonic);
417
418 #if DEBUG
419 puts("chown\n");
420 #endif
421 backup (canonic);
422
423 result = true_chown(path, owner, group);
424 log("%d\tchown\t%s\t%d\t%d\t#%s\n", result, canonic, owner, group, error(result));
425 return result;
426 }
427
chroot(const char * path)428 int chroot(const char *path) {
429 int result;
430 char canonic[MAXPATHLEN];
431
432 REFCOUNT;
433 canonicalize(path, canonic);
434 result = true_chroot(path);
435 /* From now on, another log file will be written if *
436 * INSTALLWATCHFILE is set */
437 log("%d\tchroot\t%s\t#%s\n", result, canonic, error(result));
438 return result;
439 }
440
creat(const char * pathname,mode_t mode)441 int creat(const char *pathname, mode_t mode) {
442 /* Is it a system call? */
443 int result;
444 char canonic[MAXPATHLEN];
445
446 REFCOUNT;
447 canonicalize(pathname, canonic);
448
449 #if DEBUG
450 printf("creat\n");
451 #endif
452 backup(canonic);
453
454
455 result = true_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
456 log("%d\tcreat\t%s\t#%s\n", result, canonic, error(result));
457 return result;
458 }
459
fchmod(int filedes,mode_t mode)460 int fchmod(int filedes, mode_t mode) {
461 int result;
462
463 REFCOUNT;
464
465 #if DEBUG
466 puts("fchmod\n");
467 #endif
468
469 result = true_fchmod(filedes, mode);
470 log("%d\tfchmod\t%d\t0%04o\t#%s\n", result, filedes, mode, error(result));
471 return result;
472 }
473
fchown(int fd,uid_t owner,gid_t group)474 int fchown(int fd, uid_t owner, gid_t group) {
475 int result;
476
477 REFCOUNT;
478
479 #if DEBUG
480 puts("fchown\n");
481 #endif
482
483 result = true_fchown(fd, owner, group);
484 log("%d\tfchown\t%d\t%d\t%d\t#%s\n", result, fd, owner, group, error(result));
485 return result;
486 }
487
fopen(const char * pathname,const char * mode)488 FILE *fopen(const char *pathname, const char *mode) {
489 FILE *result;
490 char canonic[MAXPATHLEN];
491
492 REFCOUNT;
493 canonicalize(pathname, canonic);
494
495 #if DEBUG
496 puts("fopen\n");
497 #endif
498 if(mode[0]=='w'||mode[0]=='a'||mode[1]=='+')
499 backup (canonic);
500
501 result = true_fopen(pathname,mode);
502 if(mode[0]=='w'||mode[0]=='a'||mode[1]=='+')
503 log("%d\tfopen\t%s\t#%s\n", (int)result, canonic, error(result));
504 return result;
505 }
506
ftruncate(int fd,TRUNCATE_T length)507 int ftruncate(int fd, TRUNCATE_T length) {
508 int result;
509
510 REFCOUNT;
511
512 #if DEBUG
513 puts ("ftruncate\n");
514 #endif
515
516 result = true_ftruncate(fd, length);
517 log("%d\tftruncate\t%d\t%d\t#%s\n", result, fd, (int)length, error(result));
518 return result;
519 }
520
lchown(const char * path,uid_t owner,gid_t group)521 int lchown(const char *path, uid_t owner, gid_t group) {
522 /* Linux specific? */
523 int result;
524 char canonic[MAXPATHLEN];
525
526 REFCOUNT;
527
528 #if DEBUG
529 puts ("lchown\n");
530 #endif
531 canonicalize(path, canonic);
532
533 backup (canonic);
534
535 result = true_chown(path, owner, group);
536 log("%d\tlchown\t%s\t%d\t%d\t#%s\n", result, canonic, owner, group, error(result));
537 return result;
538 }
539
link(const char * oldpath,const char * newpath)540 int link(const char *oldpath, const char *newpath) {
541 int result;
542 char old_canonic[MAXPATHLEN], new_canonic[MAXPATHLEN];
543
544 REFCOUNT;
545
546 #if DEBUG
547 puts ("link\n");
548 #endif
549
550 canonicalize(oldpath, old_canonic);
551 canonicalize(newpath, new_canonic);
552 result = true_link(oldpath, newpath);
553 log("%d\tlink\t%s\t%s\t#%s\n", result, old_canonic, new_canonic, error(result));
554 return result;
555 }
556
mkdir(const char * pathname,mode_t mode)557 int mkdir(const char *pathname, mode_t mode) {
558 int result;
559 char canonic[MAXPATHLEN];
560
561 REFCOUNT;
562 canonicalize(pathname, canonic);
563 result = true_mkdir(pathname, mode);
564 log("%d\tmkdir\t%s\t#%s\n", result, canonic, error(result));
565 return result;
566 }
567
open(const char * pathname,int flags,...)568 int open(const char *pathname, int flags, ...) {
569 /* Eventually, there is a third parameter: it's mode_t mode */
570 va_list ap;
571 mode_t mode;
572 int result;
573 char canonic[MAXPATHLEN];
574
575 REFCOUNT;
576 va_start(ap, flags);
577 mode = va_arg(ap, int);
578 va_end(ap);
579 canonicalize(pathname, canonic);
580
581 #if DEBUG
582 printf ("open\n");
583 #endif
584 if(flags & (O_WRONLY | O_RDWR))
585 backup (canonic);
586
587 result = true_open(pathname, flags, mode);
588 if(flags & (O_WRONLY | O_RDWR))
589 log("%d\topen\t%s\t#%s\n", result, canonic, error(result));
590 return result;
591 }
592
rename(const char * oldpath,const char * newpath)593 int rename(const char *oldpath, const char *newpath) {
594 int result;
595 char old_canonic[MAXPATHLEN], new_canonic[MAXPATHLEN];
596
597 REFCOUNT;
598 canonicalize(oldpath, old_canonic);
599
600 #if DEBUG
601 puts ("rename\n");
602 #endif
603 backup (old_canonic);
604
605 canonicalize(newpath, new_canonic);
606 result = true_rename(oldpath, newpath);
607 log("%d\trename\t%s\t%s\t#%s\n", result, old_canonic, new_canonic, error(result));
608 return result;
609 }
610
rmdir(const char * pathname)611 int rmdir(const char *pathname) {
612 int result;
613 char canonic[MAXPATHLEN];
614
615 REFCOUNT;
616 canonicalize(pathname, canonic);
617
618 #if DEBUG
619 printf ("rmdir\n");
620 #endif
621 backup(canonic);
622
623 result = true_rmdir(pathname);
624 log("%d\trmdir\t%s\t#%s\n", result, canonic, error(result));
625 return result;
626 }
627
symlink(const char * oldpath,const char * newpath)628 int symlink(const char *oldpath, const char *newpath) {
629 int result;
630 char old_canonic[MAXPATHLEN], new_canonic[MAXPATHLEN];
631
632 REFCOUNT;
633
634 #if DEBUG
635 puts ("symlink\n");
636 #endif
637
638 canonicalize(oldpath, old_canonic);
639 canonicalize(newpath, new_canonic);
640 result = true_symlink(oldpath, newpath);
641 log("%d\tsymlink\t%s\t%s\t#%s\n", result, old_canonic, new_canonic, error(result));
642 return result;
643 }
644
truncate(const char * path,TRUNCATE_T length)645 int truncate(const char *path, TRUNCATE_T length) {
646 int result;
647 char canonic[MAXPATHLEN];
648
649 REFCOUNT;
650
651 #if DEBUG
652 puts ("truncate\n");
653 #endif
654
655 canonicalize(path, canonic);
656
657 backup (canonic);
658
659 result = true_truncate(path, length);
660 log("%d\ttruncate\t%s\t%d\t#%s\n", result, path, (int)length, error(result));
661 return result;
662 }
663
unlink(const char * pathname)664 int unlink(const char *pathname) {
665 int result;
666 char canonic[MAXPATHLEN];
667
668 REFCOUNT;
669 canonicalize(pathname, canonic);
670
671 #if DEBUG
672 printf ("unlink\n");
673 #endif
674 backup(canonic);
675
676 result = true_unlink(pathname);
677 log("%d\tunlink\t%s\t#%s\n", result, canonic, error(result));
678 return result;
679 }
680
681 #if(GLIBC_MINOR >= 1)
682
creat64(const char * pathname,__mode_t mode)683 int creat64(const char *pathname, __mode_t mode) {
684 /* Is it a system call? */
685 int result;
686 char canonic[MAXPATHLEN];
687
688 REFCOUNT;
689 canonicalize(pathname, canonic);
690
691 #if DEBUG
692 puts ("creat64\n");
693 #endif
694 backup (canonic);
695
696 result = true_open64(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
697 log("%d\tcreat\t%s\t#%s\n", result, canonic, error(result));
698 return result;
699 }
700
ftruncate64(int fd,__off64_t length)701 int ftruncate64(int fd, __off64_t length) {
702 int result;
703
704 REFCOUNT;
705
706 #if DEBUG
707 puts ("ftruncate64\n");
708 #endif
709
710 result = true_ftruncate64(fd, length);
711 log("%d\tftruncate\t%d\t%d\t#%s\n", result, fd, (int)length, error(result));
712 return result;
713 }
714
fopen64(const char * pathname,const char * mode)715 FILE *fopen64(const char *pathname, const char *mode) {
716 FILE *result;
717 char canonic[MAXPATHLEN];
718
719 REFCOUNT;
720 canonicalize(pathname, canonic);
721
722 #if DEBUG
723 puts("fopen64\n");
724 #endif
725 if(mode[0]=='w'||mode[0]=='a'||mode[1]=='+')
726 backup (canonic);
727
728 result = true_fopen(pathname,mode);
729 if(mode[0]=='w'||mode[0]=='a'||mode[1]=='+')
730 log("%d\tfopen64\t%s\t#%s\n", (int)result, canonic, error(result));
731 return result;
732 }
733
open64(const char * pathname,int flags,...)734 int open64(const char *pathname, int flags, ...) {
735 /* Eventually, there is a third parameter: it's mode_t mode */
736 va_list ap;
737 mode_t mode;
738 int result;
739 char canonic[MAXPATHLEN];
740
741 REFCOUNT;
742
743 #if DEBUG
744 puts ("open64\n");
745 #endif
746
747 va_start(ap, flags);
748 mode = va_arg(ap, mode_t);
749 va_end(ap);
750 canonicalize(pathname, canonic);
751 if(flags & (O_WRONLY | O_RDWR))
752 backup(canonic);
753 result = true_open64(pathname, flags, mode);
754 if(flags & (O_WRONLY | O_RDWR))
755 log("%d\topen\t%s\t#%s\n", result, canonic, error(result));
756 return result;
757 }
758
truncate64(const char * path,__off64_t length)759 int truncate64(const char *path, __off64_t length) {
760 int result;
761 char canonic[MAXPATHLEN];
762
763 REFCOUNT;
764
765 #if DEBUG
766 puts ("truncate64\n");
767 #endif
768
769 canonicalize(path, canonic);
770
771 backup(canonic);
772
773 result = true_truncate64(path, length);
774 log("%d\ttruncate\t%s\t%d\t#%s\n", result, path, (int)length, error(result));
775 return result;
776 }
777
778 #endif /* GLIBC_MINOR >= 1 */
779
780