]> granicus.if.org Git - strace/blob - desc.c
2004-10-07 Roland McGrath <roland@redhat.com>
[strace] / desc.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  *      $Id$
31  */
32
33 #include "defs.h"
34
35 #include <fcntl.h>
36 #include <sys/file.h>
37 #ifdef LINUX
38 #include <inttypes.h>
39 #include <sys/epoll.h>
40 #endif
41
42 #if HAVE_LONG_LONG_OFF_T
43 /*
44  * Hacks for systems that have a long long off_t
45  */
46 #define flock64 flock           /* Horrid hack */
47 #define printflock printflock64 /* Horrider hack */
48 #endif
49
50
51 static const struct xlat fcntlcmds[] = {
52         { F_DUPFD,      "F_DUPFD"       },
53         { F_GETFD,      "F_GETFD"       },
54         { F_SETFD,      "F_SETFD"       },
55         { F_GETFL,      "F_GETFL"       },
56         { F_SETFL,      "F_SETFL"       },
57         { F_GETLK,      "F_GETLK"       },
58         { F_SETLK,      "F_SETLK"       },
59         { F_SETLKW,     "F_SETLKW"      },
60         { F_GETOWN,     "F_GETOWN"      },
61         { F_SETOWN,     "F_SETOWN"      },
62 #ifdef F_RSETLK
63         { F_RSETLK,     "F_RSETLK"      },
64 #endif
65 #ifdef F_RSETLKW
66         { F_RSETLKW,    "F_RSETLKW"     },
67 #endif
68 #ifdef F_RGETLK
69         { F_RGETLK,     "F_RGETLK"      },
70 #endif
71 #ifdef F_CNVT
72         { F_CNVT,       "F_CNVT"        },
73 #endif
74 #ifdef F_SETSIG
75         { F_SETSIG,     "F_SETSIG"      },
76 #endif
77 #ifdef F_GETSIG
78         { F_GETSIG,     "F_GETSIG"      },
79 #endif
80 #ifdef F_CHKFL
81         { F_CHKFL,      "F_CHKFL"       },
82 #endif
83 #ifdef F_DUP2FD
84         { F_DUP2FD,     "F_DUP2FD"      },
85 #endif
86 #ifdef F_ALLOCSP
87         { F_ALLOCSP,    "F_ALLOCSP"     },
88 #endif
89 #ifdef F_ISSTREAM
90         { F_ISSTREAM,   "F_ISSTREAM"    },
91 #endif
92 #ifdef F_PRIV
93         { F_PRIV,       "F_PRIV"        },
94 #endif
95 #ifdef F_NPRIV
96         { F_NPRIV,      "F_NPRIV"       },
97 #endif
98 #ifdef F_QUOTACL
99         { F_QUOTACL,    "F_QUOTACL"     },
100 #endif
101 #ifdef F_BLOCKS
102         { F_BLOCKS,     "F_BLOCKS"      },
103 #endif
104 #ifdef F_BLKSIZE
105         { F_BLKSIZE,    "F_BLKSIZE"     },
106 #endif
107 #ifdef F_GETOWN
108         { F_GETOWN,     "F_GETOWN"      },
109 #endif
110 #ifdef F_SETOWN
111         { F_SETOWN,     "F_SETOWN"      },
112 #endif
113 #ifdef F_REVOKE
114         { F_REVOKE,     "F_REVOKE"      },
115 #endif
116 #ifdef F_SETLK
117         { F_SETLK,      "F_SETLK"       },
118 #endif
119 #ifdef F_SETLKW
120         { F_SETLKW,     "F_SETLKW"      },
121 #endif
122 #ifdef F_FREESP
123         { F_FREESP,     "F_FREESP"      },
124 #endif
125 #ifdef F_GETLK
126         { F_GETLK,      "F_GETLK"       },
127 #endif
128 #ifdef F_SETLK64
129         { F_SETLK64,    "F_SETLK64"     },
130 #endif
131 #ifdef F_SETLKW64
132         { F_SETLKW64,   "F_SETLKW64"    },
133 #endif
134 #ifdef F_FREESP64
135         { F_FREESP64,   "F_FREESP64"    },
136 #endif
137 #ifdef F_GETLK64
138         { F_GETLK64,    "F_GETLK64"     },
139 #endif
140 #ifdef F_SHARE
141         { F_SHARE,      "F_SHARE"       },
142 #endif
143 #ifdef F_UNSHARE
144         { F_UNSHARE,    "F_UNSHARE"     },
145 #endif
146         { 0,            NULL            },
147 };
148
149 static const struct xlat fdflags[] = {
150 #ifdef FD_CLOEXEC
151         { FD_CLOEXEC,   "FD_CLOEXEC"    },
152 #endif
153         { 0,            NULL            },
154 };
155
156 #ifdef LOCK_SH
157
158 static const struct xlat flockcmds[] = {
159         { LOCK_SH,      "LOCK_SH"       },
160         { LOCK_EX,      "LOCK_EX"       },
161         { LOCK_NB,      "LOCK_NB"       },
162         { LOCK_UN,      "LOCK_UN"       },
163         { 0,            NULL            },
164 };
165
166 #endif /* LOCK_SH */
167
168 static const struct xlat lockfcmds[] = {
169         { F_RDLCK,      "F_RDLCK"       },
170         { F_WRLCK,      "F_WRLCK"       },
171         { F_UNLCK,      "F_UNLCK"       },
172 #ifdef F_EXLCK
173         { F_EXLCK,      "F_EXLCK"       },
174 #endif
175 #ifdef F_SHLCK
176         { F_SHLCK,      "F_SHLCK"       },
177 #endif
178         { 0,            NULL            },
179 };
180
181 static const struct xlat whence[] = {
182         { SEEK_SET,     "SEEK_SET"      },
183         { SEEK_CUR,     "SEEK_CUR"      },
184         { SEEK_END,     "SEEK_END"      },
185         { 0,            NULL            },
186 };
187
188 #ifndef HAVE_LONG_LONG_OFF_T
189 /* fcntl/lockf */
190 static void
191 printflock(tcp, addr, getlk)
192 struct tcb *tcp;
193 long addr;
194 int getlk;
195 {
196         struct flock fl;
197
198         if (umove(tcp, addr, &fl) < 0) {
199                 tprintf("{...}");
200                 return;
201         }
202         tprintf("{type=");
203         printxval(lockfcmds, fl.l_type, "F_???");
204         tprintf(", whence=");
205         printxval(whence, fl.l_whence, "SEEK_???");
206         tprintf(", start=%ld, len=%ld", fl.l_start, fl.l_len);
207         if (getlk)
208                 tprintf(", pid=%lu}", (unsigned long) fl.l_pid);
209         else
210                 tprintf("}");
211 }
212 #endif
213
214 #if _LFS64_LARGEFILE || HAVE_LONG_LONG_OFF_T
215 /* fcntl/lockf */
216 static void
217 printflock64(tcp, addr, getlk)
218 struct tcb *tcp;
219 long addr;
220 int getlk;
221 {
222         struct flock64 fl;
223
224         if (umove(tcp, addr, &fl) < 0) {
225                 tprintf("{...}");
226                 return;
227         }
228         tprintf("{type=");
229         printxval(lockfcmds, fl.l_type, "F_???");
230         tprintf(", whence=");
231         printxval(whence, fl.l_whence, "SEEK_???");
232         tprintf(", start=%lld, len=%lld", (long long) fl.l_start, (long long) fl.l_len);
233         if (getlk)
234                 tprintf(", pid=%lu}", (unsigned long) fl.l_pid);
235         else
236                 tprintf("}");
237 }
238 #endif
239
240 static char *
241 sprintflags(xlat, flags)
242 const struct xlat *xlat;
243 int flags;
244 {
245         static char outstr[1024];
246         char *sep;
247
248         strcpy(outstr, "flags ");
249         sep = "";
250         for (; xlat->str; xlat++) {
251                 if ((flags & xlat->val) == xlat->val) {
252                         sprintf(outstr + strlen(outstr),
253                                 "%s%s", sep, xlat->str);
254                         sep = "|";
255                         flags &= ~xlat->val;
256                 }
257         }
258         if (flags)
259                 sprintf(outstr + strlen(outstr),
260                         "%s%#x", sep, flags);
261         return outstr;
262 }
263
264 int
265 sys_fcntl(tcp)
266 struct tcb *tcp;
267 {
268         extern const struct xlat openmodes[];
269
270         if (entering(tcp)) {
271                 tprintf("%ld, ", tcp->u_arg[0]);
272                 printxval(fcntlcmds, tcp->u_arg[1], "F_???");
273                 switch (tcp->u_arg[1]) {
274                 case F_SETFD:
275                         tprintf(", ");
276                         if (printflags(fdflags, tcp->u_arg[2]) == 0)
277                                 tprintf("0");
278                         break;
279                 case F_SETOWN: case F_DUPFD:
280                         tprintf(", %ld", tcp->u_arg[2]);
281                         break;
282                 case F_SETFL:
283                         tprintf(", ");
284                         if (printflags(openmodes, tcp->u_arg[2] + 1) == 0)
285                                 tprintf("0");
286                         break;
287                 case F_SETLK: case F_SETLKW:
288 #ifdef F_FREESP
289                 case F_FREESP:
290 #endif
291                         tprintf(", ");
292                         printflock(tcp, tcp->u_arg[2], 0);
293                         break;
294 #if _LFS64_LARGEFILE
295 #ifdef F_FREESP64
296                 case F_FREESP64:
297 #endif
298                 /* Linux glibc defines SETLK64 as SETLK,
299                    even though the kernel has different values - as does Solaris. */
300 #if defined(F_SETLK64) && F_SETLK64+0!=F_SETLK
301                 case F_SETLK64:
302 #endif
303 #if defined(F_SETLKW64) && F_SETLKW64+0!=F_SETLKW
304                 case F_SETLKW64:
305 #endif
306                         tprintf(", ");
307                         printflock64(tcp, tcp->u_arg[2], 0);
308                         break;
309 #endif
310                 }
311         }
312         else {
313                 switch (tcp->u_arg[1]) {
314                 case F_DUPFD:
315                 case F_SETFD: case F_SETFL:
316                 case F_SETLK: case F_SETLKW:
317                 case F_SETOWN: case F_GETOWN:
318                         break;
319                 case F_GETFD:
320                         if (tcp->u_rval == 0)
321                                 return 0;
322                         tcp->auxstr = sprintflags(fdflags, tcp->u_rval);
323                         return RVAL_HEX|RVAL_STR;
324                 case F_GETFL:
325                         tcp->auxstr = sprintflags(openmodes, tcp->u_rval + 1);
326                         return RVAL_HEX|RVAL_STR;
327                 case F_GETLK:
328                         tprintf(", ");
329                         printflock(tcp, tcp->u_arg[2], 1);
330                         break;
331 #if _LFS64_LARGEFILE
332 #if defined(F_GETLK64) && F_GETLK64+0!=F_GETLK
333                 case F_GETLK64:
334 #endif
335                         tprintf(", ");
336                         printflock64(tcp, tcp->u_arg[2], 1);
337                         break;
338 #endif
339                 default:
340                         tprintf(", %#lx", tcp->u_arg[2]);
341                         break;
342                 }
343         }
344         return 0;
345 }
346
347 #ifdef LOCK_SH
348
349 int
350 sys_flock(tcp)
351 struct tcb *tcp;
352 {
353         if (entering(tcp)) {
354                 tprintf("%ld, ", tcp->u_arg[0]);
355                 if (!printflags(flockcmds, tcp->u_arg[1]))
356                         tprintf("LOCK_???");
357         }
358         return 0;
359 }
360 #endif /* LOCK_SH */
361
362 int
363 sys_close(tcp)
364 struct tcb *tcp;
365 {
366         if (entering(tcp)) {
367                 tprintf("%ld", tcp->u_arg[0]);
368         }
369         return 0;
370 }
371
372 int
373 sys_dup(tcp)
374 struct tcb *tcp;
375 {
376         if (entering(tcp)) {
377                 tprintf("%ld", tcp->u_arg[0]);
378         }
379         return 0;
380 }
381
382 int
383 sys_dup2(tcp)
384 struct tcb *tcp;
385 {
386         if (entering(tcp)) {
387                 tprintf("%ld, %ld", tcp->u_arg[0], tcp->u_arg[1]);
388         }
389         return 0;
390 }
391
392 int
393 sys_getdtablesize(tcp)
394 struct tcb *tcp;
395 {
396         return 0;
397 }
398
399 static int
400 decode_select(tcp, args, bitness)
401 struct tcb *tcp;
402 long *args;
403 int bitness;
404 {
405         int i, j, nfds;
406         fd_set fds;
407         struct timeval tv;
408 #ifdef ALPHA
409         struct timeval32 {
410                 unsigned tv_sec;
411                 unsigned tv_usec;
412         } *tv32;
413 #endif
414         static char outstr[1024];
415         char *sep;
416         long arg;
417
418         if (entering(tcp)) {
419                 nfds = args[0];
420                 tprintf("%d", nfds);
421                 for (i = 0; i < 3; i++) {
422                         arg = args[i+1];
423                         if (arg == 0) {
424                                 tprintf(", NULL");
425                                 continue;
426                         }
427                         if (!verbose(tcp)) {
428                                 tprintf(", %#lx", arg);
429                                 continue;
430                         }
431                         if (umove(tcp, arg, &fds) < 0) {
432                                 tprintf(", [?]");
433                                 continue;
434                         }
435                         tprintf(", [");
436                         for (j = 0, sep = ""; j < nfds; j++) {
437                                 if (FD_ISSET(j, &fds)) {
438                                         tprintf("%s%u", sep, j);
439                                         sep = " ";
440                                 }
441                         }
442                         tprintf("]");
443                 }
444                 if (!args[4])
445                         tprintf(", NULL");
446                 else if (!verbose(tcp))
447                         tprintf(", %#lx", args[4]);
448                 else if (umove(tcp, args[4], &tv) < 0)
449                         tprintf(", {...}");
450                 else {
451 #ifdef ALPHA
452                         if (bitness) {
453                                 tv32=(struct timeval32*)&tv;
454                                 tprintf(", {%u, %u}", tv32->tv_sec, tv32->tv_usec);
455                         } else
456 #endif
457                                 tprintf(", {%lu, %lu}",
458                                         (long) tv.tv_sec, (long) tv.tv_usec);
459                 }
460         }
461         else
462         {
463                 unsigned int cumlen = 0;
464                 char *sep = "";
465
466                 if (syserror(tcp))
467                         return 0;
468
469                 if ((nfds = tcp->u_rval) == 0) {
470                         tcp->auxstr = "Timeout";
471                         return RVAL_STR;
472                 }
473                 outstr[0] = '\0';
474                 for (i = 0; i < 3; i++) {
475                         int first = 1;
476                         char str[20];
477
478                         tcp->auxstr = outstr;
479                         arg = args[i+1];
480                         if (!arg || umove(tcp, arg, &fds) < 0)
481                                 continue;
482                         for (j = 0; j < args[0]; j++) {
483                                 if (FD_ISSET(j, &fds)) {
484                                         if (first) {
485                                                 sprintf(str, "%s%s [%u", sep,
486                                                         i == 0 ? "in" :
487                                                         i == 1 ? "out" :
488                                                         "except", j);
489                                                 first = 0;
490                                                 sep = ", ";
491                                         }
492                                         else
493                                                 sprintf(str, " %u", j);
494                                         cumlen += strlen(str);
495                                         if (cumlen < sizeof(outstr))
496                                                 strcat(outstr, str);
497                                         nfds--;
498                                 }
499                         }
500                         if (cumlen)
501                                 strcat(outstr, "]");
502                         if (nfds == 0)
503                                 break;
504                 }
505 #ifdef LINUX
506                 /* This contains no useful information on SunOS.  */
507                 if (args[4]) {
508                         char str[20];
509
510                         if (umove(tcp, args[4], &tv) >= 0) {
511 #ifdef ALPHA
512                                 if (bitness) {
513                                         tv32=(struct timeval32*)&tv;
514                                         sprintf(str, "%sleft {%u, %u}", sep,
515                                                 tv32->tv_sec, tv32->tv_usec);
516                                 } else
517 #endif
518                                         sprintf(str, "%sleft {%lu, %lu}", sep,
519                                                 (long) tv.tv_sec, (long) tv.tv_usec);
520
521                                 if ((cumlen += strlen(str)) < sizeof(outstr))
522                                         strcat(outstr, str);
523                         }
524                 }
525 #endif /* LINUX */
526                 return RVAL_STR;
527         }
528         return 0;
529 }
530
531 #ifdef LINUX
532
533 int
534 sys_oldselect(tcp)
535 struct tcb *tcp;
536 {
537         long args[5];
538
539         if (umoven(tcp, tcp->u_arg[0], sizeof args, (char *) args) < 0) {
540                 tprintf("[...]");
541                 return 0;
542         }
543         return decode_select(tcp, args, 0);
544 }
545
546 #ifdef ALPHA
547 int
548 sys_osf_select(tcp)
549 struct tcb *tcp;
550 {
551         long *args = tcp->u_arg;
552         return decode_select(tcp, args, 1);
553 }
554 #endif
555
556 static struct xlat epollctls[] = {
557         { EPOLL_CTL_ADD,        "EPOLL_CTL_ADD" },
558         { EPOLL_CTL_MOD,        "EPOLL_CTL_MOD" },
559         { EPOLL_CTL_DEL,        "EPOLL_CTL_DEL" },
560         { 0,                    NULL            }
561 };
562
563 static struct xlat epollevents[] = {
564         { EPOLLIN,      "EPOLLIN"       },
565         { EPOLLPRI,     "EPOLLPRI"      },
566         { EPOLLOUT,     "EPOLLOUT"      },
567         { EPOLLRDNORM,  "EPOLLRDNORM"   },
568         { EPOLLRDBAND,  "EPOLLRDBAND"   },
569         { EPOLLWRNORM,  "EPOLLWRNORM"   },
570         { EPOLLWRBAND,  "EPOLLWRBAND"   },
571         { EPOLLMSG,     "EPOLLMSG"      },
572         { EPOLLERR,     "EPOLLERR"      },
573         { EPOLLHUP,     "EPOLLHUP"      },
574         { EPOLLONESHOT, "EPOLLONESHOT"  },
575         { EPOLLET,      "EPOLLET"       },
576         { 0,            NULL            }
577 };
578
579 int
580 sys_epoll_create(tcp)
581 struct tcb *tcp;
582 {
583         if (entering(tcp))
584                 tprintf("%ld", tcp->u_arg[0]);
585         return 0;
586 }
587
588 static void
589 print_epoll_event(ev)
590 struct epoll_event *ev;
591 {
592         tprintf("{");
593         if (printflags(epollevents, ev->events) == 0)
594                 tprintf("0");
595         /* We cannot know what format the program uses, so print u32 and u64
596            which will cover every value.  */
597         tprintf(", {u32=%" PRIu32 ", u64=%" PRIu64 "}}",
598                 ev->data.u32, ev->data.u64);
599 }
600
601 int
602 sys_epoll_ctl(tcp)
603 struct tcb *tcp;
604 {
605         if (entering(tcp)) {
606                 struct epoll_event ev;
607                 tprintf("%ld, ", tcp->u_arg[0]);
608                 printxval(epollctls, tcp->u_arg[1], "EPOLL_CTL_???");
609                 tprintf(", %ld, ", tcp->u_arg[2]);
610                 if (tcp->u_arg[3] == 0)
611                         tprintf("NULL");
612                 else if (umove(tcp, tcp->u_arg[3], &ev) < 0)
613                         tprintf("{...}");
614                 else
615                         print_epoll_event(&ev);
616         }
617         return 0;
618 }
619
620 int
621 sys_epoll_wait(tcp)
622 struct tcb *tcp;
623 {
624         if (entering(tcp))
625                 tprintf("%ld, ", tcp->u_arg[0]);
626         else {
627                 if (syserror(tcp))
628                         tprintf("%lx", tcp->u_arg[1]);
629                 else if (tcp->u_rval == 0)
630                         tprintf("{}");
631                 else {
632                         struct epoll_event evs[tcp->u_rval];
633                         if (umove(tcp, tcp->u_arg[1], evs) < 0)
634                                 tprintf("{...}");
635                         else {
636                                 unsigned long i;
637                                 tprintf("{");
638                                 for (i = 0; i < tcp->u_rval; ++i) {
639                                         if (i > 0)
640                                                 tprintf(", ");
641                                         print_epoll_event(&evs[i]);
642                                 }
643                                 tprintf("}");
644                         }
645                 }
646                 tprintf(", %ld, %ld", tcp->u_arg[2], tcp->u_arg[3]);
647         }
648         return 0;
649 }
650 #endif /* LINUX */
651
652 int
653 sys_select(tcp)
654 struct tcb *tcp;
655 {
656         long *args = tcp->u_arg;
657         return decode_select(tcp, args, 0);
658 }