]> granicus.if.org Git - strace/blob - file.c
Use the same source code for struct stat/stat64 decoding
[strace] / file.c
1 /*
2  * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3  * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4  * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
5  * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "defs.h"
32
33 #if defined(SPARC) || defined(SPARC64)
34 struct stat {
35         unsigned short  st_dev;
36         unsigned int    st_ino;
37         unsigned short  st_mode;
38         short           st_nlink;
39         unsigned short  st_uid;
40         unsigned short  st_gid;
41         unsigned short  st_rdev;
42         unsigned int    st_size;
43         int             st_atime;
44         unsigned int    __unused1;
45         int             st_mtime;
46         unsigned int    __unused2;
47         int             st_ctime;
48         unsigned int    __unused3;
49         int             st_blksize;
50         int             st_blocks;
51         unsigned int    __unused4[2];
52 };
53 # if defined(SPARC64)
54 struct stat_sparc64 {
55         unsigned int    st_dev;
56         unsigned long   st_ino;
57         unsigned int    st_mode;
58         unsigned int    st_nlink;
59         unsigned int    st_uid;
60         unsigned int    st_gid;
61         unsigned int    st_rdev;
62         long            st_size;
63         long            st_atime;
64         long            st_mtime;
65         long            st_ctime;
66         long            st_blksize;
67         long            st_blocks;
68         unsigned long   __unused4[2];
69 };
70 # endif /* SPARC64 */
71 # define stat kernel_stat
72 # include <asm/stat.h>
73 # undef stat
74 #else /* !SPARC && !SPARC64 */
75 # undef dev_t
76 # undef ino_t
77 # undef mode_t
78 # undef nlink_t
79 # undef uid_t
80 # undef gid_t
81 # undef off_t
82 # undef loff_t
83 # define dev_t __kernel_dev_t
84 # define ino_t __kernel_ino_t
85 # define mode_t __kernel_mode_t
86 # define nlink_t __kernel_nlink_t
87 # define uid_t __kernel_uid_t
88 # define gid_t __kernel_gid_t
89 # define off_t __kernel_off_t
90 # define loff_t __kernel_loff_t
91
92 # include <asm/stat.h>
93
94 # undef dev_t
95 # undef ino_t
96 # undef mode_t
97 # undef nlink_t
98 # undef uid_t
99 # undef gid_t
100 # undef off_t
101 # undef loff_t
102 # define dev_t dev_t
103 # define ino_t ino_t
104 # define mode_t mode_t
105 # define nlink_t nlink_t
106 # define uid_t uid_t
107 # define gid_t gid_t
108 # define off_t off_t
109 # define loff_t loff_t
110 #endif
111
112 #define stat libc_stat
113 #define stat64 libc_stat64
114 #include <sys/stat.h>
115 #undef stat
116 #undef stat64
117 /* These might be macros. */
118 #undef st_atime
119 #undef st_mtime
120 #undef st_ctime
121
122 #ifdef MAJOR_IN_SYSMACROS
123 # include <sys/sysmacros.h>
124 #endif
125
126 #ifdef MAJOR_IN_MKDEV
127 # include <sys/mkdev.h>
128 #endif
129
130 /* several stats */
131
132 #if defined(SPARC) || defined(SPARC64)
133 typedef struct {
134         int     tv_sec;
135         int     tv_nsec;
136 } timestruct_t;
137
138 struct solstat {
139         unsigned        st_dev;
140         int             st_pad1[3];     /* network id */
141         unsigned        st_ino;
142         unsigned        st_mode;
143         unsigned        st_nlink;
144         unsigned        st_uid;
145         unsigned        st_gid;
146         unsigned        st_rdev;
147         int             st_pad2[2];
148         int             st_size;
149         int             st_pad3;        /* st_size, off_t expansion */
150         timestruct_t    st_atime;
151         timestruct_t    st_mtime;
152         timestruct_t    st_ctime;
153         int             st_blksize;
154         int             st_blocks;
155         char            st_fstype[16];
156         int             st_pad4[8];     /* expansion area */
157 };
158
159 static void
160 printstatsol(struct tcb *tcp, long addr)
161 {
162         struct solstat statbuf;
163
164         if (umove(tcp, addr, &statbuf) < 0) {
165                 tprints("{...}");
166                 return;
167         }
168         if (!abbrev(tcp)) {
169                 tprintf("{st_dev=makedev(%lu, %lu), st_ino=%lu, st_mode=%s, ",
170                         (unsigned long) ((statbuf.st_dev >> 18) & 0x3fff),
171                         (unsigned long) (statbuf.st_dev & 0x3ffff),
172                         (unsigned long) statbuf.st_ino,
173                         sprintmode(statbuf.st_mode));
174                 tprintf("st_nlink=%lu, st_uid=%lu, st_gid=%lu, ",
175                         (unsigned long) statbuf.st_nlink,
176                         (unsigned long) statbuf.st_uid,
177                         (unsigned long) statbuf.st_gid);
178                 tprintf("st_blksize=%lu, ", (unsigned long) statbuf.st_blksize);
179                 tprintf("st_blocks=%lu, ", (unsigned long) statbuf.st_blocks);
180         }
181         else
182                 tprintf("{st_mode=%s, ", sprintmode(statbuf.st_mode));
183         switch (statbuf.st_mode & S_IFMT) {
184         case S_IFCHR: case S_IFBLK:
185                 tprintf("st_rdev=makedev(%lu, %lu), ",
186                         (unsigned long) ((statbuf.st_rdev >> 18) & 0x3fff),
187                         (unsigned long) (statbuf.st_rdev & 0x3ffff));
188                 break;
189         default:
190                 tprintf("st_size=%u, ", statbuf.st_size);
191                 break;
192         }
193         if (!abbrev(tcp)) {
194                 tprintf("st_atime=%s, ", sprinttime(statbuf.st_atime.tv_sec));
195                 tprintf("st_mtime=%s, ", sprinttime(statbuf.st_mtime.tv_sec));
196                 tprintf("st_ctime=%s}", sprinttime(statbuf.st_ctime.tv_sec));
197         }
198         else
199                 tprints("...}");
200 }
201
202 # if defined(SPARC64)
203 static void
204 printstat_sparc64(struct tcb *tcp, long addr)
205 {
206         struct stat_sparc64 statbuf;
207
208         if (umove(tcp, addr, &statbuf) < 0) {
209                 tprints("{...}");
210                 return;
211         }
212
213         if (!abbrev(tcp)) {
214                 tprintf("{st_dev=makedev(%lu, %lu), st_ino=%lu, st_mode=%s, ",
215                         (unsigned long) major(statbuf.st_dev),
216                         (unsigned long) minor(statbuf.st_dev),
217                         (unsigned long) statbuf.st_ino,
218                         sprintmode(statbuf.st_mode));
219                 tprintf("st_nlink=%lu, st_uid=%lu, st_gid=%lu, ",
220                         (unsigned long) statbuf.st_nlink,
221                         (unsigned long) statbuf.st_uid,
222                         (unsigned long) statbuf.st_gid);
223                 tprintf("st_blksize=%lu, ",
224                         (unsigned long) statbuf.st_blksize);
225                 tprintf("st_blocks=%lu, ",
226                         (unsigned long) statbuf.st_blocks);
227         }
228         else
229                 tprintf("{st_mode=%s, ", sprintmode(statbuf.st_mode));
230         switch (statbuf.st_mode & S_IFMT) {
231         case S_IFCHR: case S_IFBLK:
232                 tprintf("st_rdev=makedev(%lu, %lu), ",
233                         (unsigned long) major(statbuf.st_rdev),
234                         (unsigned long) minor(statbuf.st_rdev));
235                 break;
236         default:
237                 tprintf("st_size=%lu, ", statbuf.st_size);
238                 break;
239         }
240         if (!abbrev(tcp)) {
241                 tprintf("st_atime=%s, ", sprinttime(statbuf.st_atime));
242                 tprintf("st_mtime=%s, ", sprinttime(statbuf.st_mtime));
243                 tprintf("st_ctime=%s}", sprinttime(statbuf.st_ctime));
244         }
245         else
246                 tprints("...}");
247 }
248 # endif /* SPARC64 */
249 #endif /* SPARC[64] */
250
251 #if defined POWERPC64
252 struct stat_powerpc32 {
253         unsigned int    st_dev;
254         unsigned int    st_ino;
255         unsigned int    st_mode;
256         unsigned short  st_nlink;
257         unsigned int    st_uid;
258         unsigned int    st_gid;
259         unsigned int    st_rdev;
260         unsigned int    st_size;
261         unsigned int    st_blksize;
262         unsigned int    st_blocks;
263         unsigned int    st_atime;
264         unsigned int    st_atime_nsec;
265         unsigned int    st_mtime;
266         unsigned int    st_mtime_nsec;
267         unsigned int    st_ctime;
268         unsigned int    st_ctime_nsec;
269         unsigned int    __unused4;
270         unsigned int    __unused5;
271 };
272
273 static void
274 printstat_powerpc32(struct tcb *tcp, long addr)
275 {
276         struct stat_powerpc32 statbuf;
277
278         if (umove(tcp, addr, &statbuf) < 0) {
279                 tprints("{...}");
280                 return;
281         }
282
283         if (!abbrev(tcp)) {
284                 tprintf("{st_dev=makedev(%u, %u), st_ino=%u, st_mode=%s, ",
285                         major(statbuf.st_dev), minor(statbuf.st_dev),
286                         statbuf.st_ino,
287                         sprintmode(statbuf.st_mode));
288                 tprintf("st_nlink=%u, st_uid=%u, st_gid=%u, ",
289                         statbuf.st_nlink, statbuf.st_uid, statbuf.st_gid);
290                 tprintf("st_blksize=%u, ", statbuf.st_blksize);
291                 tprintf("st_blocks=%u, ", statbuf.st_blocks);
292         }
293         else
294                 tprintf("{st_mode=%s, ", sprintmode(statbuf.st_mode));
295         switch (statbuf.st_mode & S_IFMT) {
296         case S_IFCHR: case S_IFBLK:
297                 tprintf("st_rdev=makedev(%lu, %lu), ",
298                         (unsigned long) major(statbuf.st_rdev),
299                         (unsigned long) minor(statbuf.st_rdev));
300                 break;
301         default:
302                 tprintf("st_size=%u, ", statbuf.st_size);
303                 break;
304         }
305         if (!abbrev(tcp)) {
306                 tprintf("st_atime=%s, ", sprinttime(statbuf.st_atime));
307                 tprintf("st_mtime=%s, ", sprinttime(statbuf.st_mtime));
308                 tprintf("st_ctime=%s}", sprinttime(statbuf.st_ctime));
309         }
310         else
311                 tprints("...}");
312 }
313 #endif /* POWERPC64 */
314
315 #include "printstat.h"
316
317 static void
318 printstat(struct tcb *tcp, long addr)
319 {
320         struct stat statbuf;
321
322         if (!addr) {
323                 tprints("NULL");
324                 return;
325         }
326         if (syserror(tcp) || !verbose(tcp)) {
327                 tprintf("%#lx", addr);
328                 return;
329         }
330
331 #if defined(SPARC) || defined(SPARC64)
332         if (current_personality == 1) {
333                 printstatsol(tcp, addr);
334                 return;
335         }
336 # ifdef SPARC64
337         else if (current_personality == 2) {
338                 printstat_sparc64(tcp, addr);
339                 return;
340         }
341 # endif
342 #endif /* SPARC[64] */
343
344 #if defined POWERPC64
345         if (current_personality == 1) {
346                 printstat_powerpc32(tcp, addr);
347                 return;
348         }
349 #endif
350
351         if (umove(tcp, addr, &statbuf) < 0) {
352                 tprints("{...}");
353                 return;
354         }
355
356         do_printstat(tcp, &statbuf);
357 }
358
359 #if !defined HAVE_STAT64 && (defined AARCH64 || defined X86_64 || defined X32)
360 /*
361  * Linux x86_64 and x32 have unified `struct stat' but their i386 personality
362  * needs `struct stat64'.
363  * linux/arch/x86/include/uapi/asm/stat.h defines `struct stat64' only for i386.
364  * __GNUC__ is needed for the required __attribute__ below.
365  *
366  * Similarly, aarch64 has a unified `struct stat' but its arm personality
367  * needs `struct stat64' (unlike x86, it shouldn't be packed).
368  */
369 struct stat64 {
370         unsigned long long      st_dev;
371         unsigned char   __pad0[4];
372         unsigned int    __st_ino;
373         unsigned int    st_mode;
374         unsigned int    st_nlink;
375         unsigned int    st_uid;
376         unsigned int    st_gid;
377         unsigned long long      st_rdev;
378         unsigned char   __pad3[4];
379         long long       st_size;
380         unsigned int    st_blksize;
381         unsigned long long      st_blocks;
382         unsigned int    st_atime;
383         unsigned int    st_atime_nsec;
384         unsigned int    st_mtime;
385         unsigned int    st_mtime_nsec;
386         unsigned int    st_ctime;
387         unsigned int    st_ctime_nsec;
388         unsigned long long      st_ino;
389 }
390 # if defined X86_64 || defined X32
391    __attribute__((packed))
392 #  define STAT64_SIZE   96
393 #else
394 #  define STAT64_SIZE   104
395 # endif
396 ;
397 # define HAVE_STAT64    1
398 #endif /* AARCH64 || X86_64 || X32 */
399
400 #ifdef HAVE_STAT64
401
402 # define DO_PRINTSTAT do_printstat64
403 # define STRUCT_STAT struct stat64
404 # undef HAVE_STRUCT_STAT_ST_FLAGS
405 # undef HAVE_STRUCT_STAT_ST_FSTYPE
406 # undef HAVE_STRUCT_STAT_ST_GEN
407 # include "printstat.h"
408
409 static void
410 printstat64(struct tcb *tcp, long addr)
411 {
412         struct stat64 statbuf;
413
414 #ifdef STAT64_SIZE
415         (void) sizeof(char[sizeof statbuf == STAT64_SIZE ? 1 : -1]);
416 #endif
417
418         if (!addr) {
419                 tprints("NULL");
420                 return;
421         }
422         if (syserror(tcp) || !verbose(tcp)) {
423                 tprintf("%#lx", addr);
424                 return;
425         }
426
427 #if defined(SPARC) || defined(SPARC64)
428         if (current_personality == 1) {
429                 printstatsol(tcp, addr);
430                 return;
431         }
432 # ifdef SPARC64
433         else if (current_personality == 2) {
434                 printstat_sparc64(tcp, addr);
435                 return;
436         }
437 # endif
438 #endif /* SPARC[64] */
439
440 #if defined AARCH64
441         if (current_personality != 0) {
442                 printstat(tcp, addr);
443                 return;
444         }
445 #endif
446 #if defined X86_64 || defined X32
447         if (current_personality != 1) {
448                 printstat(tcp, addr);
449                 return;
450         }
451 #endif
452
453         if (umove(tcp, addr, &statbuf) < 0) {
454                 tprints("{...}");
455                 return;
456         }
457
458         do_printstat64(tcp, &statbuf);
459 }
460 #endif /* HAVE_STAT64 */
461
462 #if defined(HAVE_STRUCT___OLD_KERNEL_STAT)
463 static void
464 convertoldstat(const struct __old_kernel_stat *oldbuf, struct stat *newbuf)
465 {
466         newbuf->st_dev = oldbuf->st_dev;
467         newbuf->st_ino = oldbuf->st_ino;
468         newbuf->st_mode = oldbuf->st_mode;
469         newbuf->st_nlink = oldbuf->st_nlink;
470         newbuf->st_uid = oldbuf->st_uid;
471         newbuf->st_gid = oldbuf->st_gid;
472         newbuf->st_rdev = oldbuf->st_rdev;
473         newbuf->st_size = oldbuf->st_size;
474         newbuf->st_atime = oldbuf->st_atime;
475         newbuf->st_mtime = oldbuf->st_mtime;
476         newbuf->st_ctime = oldbuf->st_ctime;
477         newbuf->st_blksize = 0; /* not supported in old_stat */
478         newbuf->st_blocks = 0; /* not supported in old_stat */
479 }
480
481 static void
482 printoldstat(struct tcb *tcp, long addr)
483 {
484         struct __old_kernel_stat statbuf;
485         struct stat newstatbuf;
486
487         if (!addr) {
488                 tprints("NULL");
489                 return;
490         }
491         if (syserror(tcp) || !verbose(tcp)) {
492                 tprintf("%#lx", addr);
493                 return;
494         }
495
496 # if defined(SPARC) || defined(SPARC64)
497         if (current_personality == 1) {
498                 printstatsol(tcp, addr);
499                 return;
500         }
501 # endif
502
503         if (umove(tcp, addr, &statbuf) < 0) {
504                 tprints("{...}");
505                 return;
506         }
507
508         convertoldstat(&statbuf, &newstatbuf);
509         do_printstat(tcp, &newstatbuf);
510 }
511 #endif
512
513 int
514 sys_stat(struct tcb *tcp)
515 {
516         if (entering(tcp)) {
517                 printpath(tcp, tcp->u_arg[0]);
518                 tprints(", ");
519         } else {
520                 printstat(tcp, tcp->u_arg[1]);
521         }
522         return 0;
523 }
524
525 int
526 sys_stat64(struct tcb *tcp)
527 {
528 #ifdef HAVE_STAT64
529         if (entering(tcp)) {
530                 printpath(tcp, tcp->u_arg[0]);
531                 tprints(", ");
532         } else {
533                 printstat64(tcp, tcp->u_arg[1]);
534         }
535         return 0;
536 #else
537         return printargs(tcp);
538 #endif
539 }
540
541 int
542 sys_newfstatat(struct tcb *tcp)
543 {
544         if (entering(tcp)) {
545                 print_dirfd(tcp, tcp->u_arg[0]);
546                 printpath(tcp, tcp->u_arg[1]);
547                 tprints(", ");
548         } else {
549 #ifdef POWERPC64
550                 if (current_personality == 0)
551                         printstat(tcp, tcp->u_arg[2]);
552                 else
553                         printstat64(tcp, tcp->u_arg[2]);
554 #elif defined HAVE_STAT64
555                 printstat64(tcp, tcp->u_arg[2]);
556 #else
557                 printstat(tcp, tcp->u_arg[2]);
558 #endif
559                 tprints(", ");
560                 printflags(at_flags, tcp->u_arg[3], "AT_???");
561         }
562         return 0;
563 }
564
565 #if defined(HAVE_STRUCT___OLD_KERNEL_STAT)
566 int
567 sys_oldstat(struct tcb *tcp)
568 {
569         if (entering(tcp)) {
570                 printpath(tcp, tcp->u_arg[0]);
571                 tprints(", ");
572         } else {
573                 printoldstat(tcp, tcp->u_arg[1]);
574         }
575         return 0;
576 }
577 #endif
578
579 int
580 sys_fstat(struct tcb *tcp)
581 {
582         if (entering(tcp)) {
583                 printfd(tcp, tcp->u_arg[0]);
584                 tprints(", ");
585         } else {
586                 printstat(tcp, tcp->u_arg[1]);
587         }
588         return 0;
589 }
590
591 int
592 sys_fstat64(struct tcb *tcp)
593 {
594 #ifdef HAVE_STAT64
595         if (entering(tcp)) {
596                 printfd(tcp, tcp->u_arg[0]);
597                 tprints(", ");
598         } else {
599                 printstat64(tcp, tcp->u_arg[1]);
600         }
601         return 0;
602 #else
603         return printargs(tcp);
604 #endif
605 }
606
607 #if defined(HAVE_STRUCT___OLD_KERNEL_STAT)
608 int
609 sys_oldfstat(struct tcb *tcp)
610 {
611         if (entering(tcp)) {
612                 printfd(tcp, tcp->u_arg[0]);
613                 tprints(", ");
614         } else {
615                 printoldstat(tcp, tcp->u_arg[1]);
616         }
617         return 0;
618 }
619 #endif
620
621 #if defined(SPARC) || defined(SPARC64)
622
623 int
624 sys_xstat(struct tcb *tcp)
625 {
626         if (entering(tcp)) {
627                 tprintf("%ld, ", tcp->u_arg[0]);
628                 printpath(tcp, tcp->u_arg[1]);
629                 tprints(", ");
630         } else {
631                 printstat(tcp, tcp->u_arg[2]);
632         }
633         return 0;
634 }
635
636 int
637 sys_fxstat(struct tcb *tcp)
638 {
639         if (entering(tcp)) {
640                 tprintf("%ld, ", tcp->u_arg[0]);
641                 printfd(tcp, tcp->u_arg[1]);
642                 tprints(", ");
643         } else {
644                 printstat(tcp, tcp->u_arg[2]);
645         }
646         return 0;
647 }
648
649 #endif /* SPARC || SPARC64 */