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