]> granicus.if.org Git - strace/blob - stream.c
Merged in a bunch of patches that I got as reaction to the 3.99 release.
[strace] / stream.c
1 /*
2  * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  *      $Id$
28  */
29
30 #include "defs.h"
31
32 #if defined(HAVE_SYS_STREAM_H) || defined(linux)
33
34 #if defined(linux)
35 #include <sys/poll.h>
36
37 #define RS_HIPRI 1
38 struct strbuf {
39         int     maxlen;                 /* no. of bytes in buffer */
40         int     len;                    /* no. of bytes returned */
41         char    *buf;                   /* pointer to data */
42 };
43 #define MORECTL 1
44 #define MOREDATA 2
45
46 #else /* linux */
47
48 #include <stropts.h>
49 #include <poll.h>
50 #include <sys/conf.h>
51 #include <sys/stream.h>
52 #include <sys/tihdr.h>
53
54 #endif /* linux */
55
56 #ifdef HAVE_SYS_TIUSER_H
57 #include <sys/tiuser.h>
58 #include <sys/sockmod.h>
59 #include <sys/timod.h>
60 #endif /* HAVE_SYS_TIUSER_H */
61
62 static struct xlat msgflags[] = {
63         { RS_HIPRI,     "RS_HIPRI"      },
64         { 0,            NULL            },
65 };
66
67
68 static void
69 printstrbuf(tcp, sbp, getting)
70 struct tcb *tcp;
71 struct strbuf *sbp;
72 int getting;
73 {
74         if (sbp->maxlen == -1 && getting)
75                 tprintf("{maxlen=-1}");
76         else {
77                 tprintf("{");
78                 if (getting)
79                         tprintf("maxlen=%d, ", sbp->maxlen);
80                 tprintf("len=%d, buf=", sbp->len);
81                 printstr(tcp, (unsigned long) sbp->buf, sbp->len);
82                 tprintf("}");
83         }
84 }
85
86 static void
87 printstrbufarg(tcp, arg, getting)
88 struct tcb *tcp;
89 int arg;
90 int getting;
91 {
92         struct strbuf buf;
93
94         if (arg == 0)
95                 tprintf("NULL");
96         else if (umove(tcp, arg, &buf) < 0)
97                 tprintf("{...}");
98         else
99                 printstrbuf(tcp, &buf, getting);
100         tprintf(", ");
101 }
102
103 int
104 sys_putmsg(tcp)
105 struct tcb *tcp;
106 {
107         int i;
108
109         if (entering(tcp)) {
110                 /* fd */
111                 tprintf("%ld, ", tcp->u_arg[0]);
112                 /* control and data */
113                 for (i = 1; i < 3; i++)
114                         printstrbufarg(tcp, tcp->u_arg[i], 0);
115                 /* flags */
116                 if (!printflags(msgflags, tcp->u_arg[3]))
117                         tprintf("0");
118         }
119         return 0;
120 }
121
122 int
123 sys_getmsg(tcp)
124 struct tcb *tcp;
125 {
126         int i, flags;
127
128         if (entering(tcp)) {
129                 /* fd */
130                 tprintf("%lu, ", tcp->u_arg[0]);
131         } else {
132                 if (syserror(tcp)) {
133                         tprintf("%#lx, %#lx, %#lx",
134                                 tcp->u_arg[1], tcp->u_arg[2], tcp->u_arg[3]);
135                         return 0;
136                 }
137                 /* control and data */
138                 for (i = 1; i < 3; i++)
139                         printstrbufarg(tcp, tcp->u_arg[i], 1);
140                 /* pointer to flags */
141                 if (tcp->u_arg[3] == 0)
142                         tprintf("NULL");
143                 else if (umove(tcp, tcp->u_arg[3], &flags) < 0)
144                         tprintf("[?]");
145                 else {
146                         tprintf("[");
147                         if (!printflags(msgflags, flags))
148                                 tprintf("0");
149                         tprintf("]");
150                 }
151                 /* decode return value */
152                 switch (tcp->u_rval) {
153                 case MORECTL:
154                         tcp->auxstr = "MORECTL";
155                         break;
156                 case MORECTL|MOREDATA:
157                         tcp->auxstr = "MORECTL|MOREDATA";
158                         break;
159                 case MOREDATA:
160                         tcp->auxstr = "MORECTL";
161                         break;
162                 default:
163                         tcp->auxstr = NULL;
164                         break;
165                 }
166         }
167         return RVAL_HEX | RVAL_STR;
168 }
169
170 #ifdef HAVE_PUTPMSG
171
172 static struct xlat pmsgflags[] = {
173         { MSG_HIPRI,    "MSG_HIPRI"     },
174         { MSG_ANY,      "MSG_ANY"       },
175         { MSG_BAND,     "MSG_BAND"      },
176         { 0,            NULL            },
177 };
178
179 int
180 sys_putpmsg(tcp)
181 struct tcb *tcp;
182 {
183         int i;
184
185         if (entering(tcp)) {
186                 /* fd */
187                 tprintf("%ld, ", tcp->u_arg[0]);
188                 /* control and data */
189                 for (i = 1; i < 3; i++)
190                         printstrbufarg(tcp, tcp->u_arg[i], 0);
191                 /* band */
192                 tprintf("%ld, ", tcp->u_arg[3]);
193                 /* flags */
194                 if (!printflags(pmsgflags, tcp->u_arg[4]))
195                         tprintf("0");
196         }
197         return 0;
198 }
199
200 int
201 sys_getpmsg(tcp)
202 struct tcb *tcp;
203 {
204         int i, flags;
205
206         if (entering(tcp)) {
207                 /* fd */
208                 tprintf("%lu, ", tcp->u_arg[0]);
209         } else {
210                 if (syserror(tcp)) {
211                         tprintf("%#lx, %#lx, %#lx, %#lx", tcp->u_arg[1],
212                                 tcp->u_arg[2], tcp->u_arg[3], tcp->u_arg[4]);
213                         return 0;
214                 }
215                 /* control and data */
216                 for (i = 1; i < 3; i++)
217                         printstrbufarg(tcp, tcp->u_arg[i], 1);
218                 /* pointer to band */
219                 printnum(tcp, tcp->u_arg[3], "%d");
220                 /* pointer to flags */
221                 if (tcp->u_arg[4] == 0)
222                         tprintf("NULL");
223                 else if (umove(tcp, tcp->u_arg[4], &flags) < 0)
224                         tprintf("[?]");
225                 else {
226                         tprintf("[");
227                         if (!printflags(pmsgflags, flags))
228                                 tprintf("0");
229                         tprintf("]");
230                 }
231                 /* decode return value */
232                 switch (tcp->u_rval) {
233                 case MORECTL:
234                         tcp->auxstr = "MORECTL";
235                         break;
236                 case MORECTL|MOREDATA:
237                         tcp->auxstr = "MORECTL|MOREDATA";
238                         break;
239                 case MOREDATA:
240                         tcp->auxstr = "MORECTL";
241                         break;
242                 default:
243                         tcp->auxstr = NULL;
244                         break;
245                 }
246         }
247         return RVAL_HEX | RVAL_STR;
248 }
249
250 #endif /* HAVE_PUTPMSG */
251
252
253 static struct xlat pollflags[] = {
254         { POLLIN,       "POLLIN"        },
255         { POLLPRI,      "POLLPRI"       },
256         { POLLOUT,      "POLLOUT"       },
257 #ifdef POLLRDNORM
258         { POLLRDNORM,   "POLLRDNORM"    },
259 #endif
260 #ifdef POLLWRNORM
261         { POLLWRNORM,   "POLLWRNORM"    },
262 #endif
263 #ifdef POLLRDBAND
264         { POLLRDBAND,   "POLLRDBAND"    },
265 #endif
266 #ifdef POLLWRBAND
267         { POLLWRBAND,   "POLLWRBAND"    },
268 #endif
269         { POLLERR,      "POLLERR"       },
270         { POLLHUP,      "POLLHUP"       },
271         { POLLNVAL,     "POLLNVAL"      },
272         { 0,            NULL            },
273 };
274
275 int
276 sys_poll(tcp)
277 struct tcb *tcp;
278 {
279         struct pollfd *pollp;
280
281         if (exiting(tcp)) {
282                 int i;
283                 int nfds = tcp->u_arg[1];
284
285                 if (nfds <= 0) {
286                         tprintf("%#lx, %d, %ld\n",
287                                 tcp->u_arg[0], nfds, tcp->u_arg[2]);
288                         return 0;
289                 }
290                 pollp = (struct pollfd *) malloc(nfds * sizeof(*pollp));
291                 if (pollp == NULL) {
292                         fprintf(stderr, "sys_poll: no memory\n");
293                         tprintf("%#lx, %d, %ld",
294                                 tcp->u_arg[0], nfds, tcp->u_arg[2]);
295                         return 0;
296                 }
297                 if (umoven(tcp, tcp->u_arg[0],
298                            (nfds * sizeof(*pollp)), (char *) pollp) < 0) {
299                         tprintf("%#lx", tcp->u_arg[0]);
300                 }
301                 else {
302                         tprintf("[");
303                         for (i = 0; i < nfds; i++) {
304                                 if (i)
305                                         tprintf(", ");
306                                 if (pollp[i].fd < 0) {
307                                         tprintf("{fd=%d}", pollp[i].fd);
308                                         continue;
309                                 }
310                                 tprintf("{fd=%d, events=", pollp[i].fd);
311                                 if (!printflags(pollflags, pollp[i].events))
312                                         tprintf("0");
313                                 if (!syserror(tcp) && pollp[i].revents) {
314                                         tprintf(", revents=");
315                                         if (!printflags(pollflags,
316                                                         pollp[i].revents))
317                                                 tprintf("0");
318                                 }
319                                 tprintf("}");
320                         }
321                         tprintf("]");
322                 }
323                 tprintf(", %d, ", nfds);
324 #ifdef INFTIM
325                 if (tcp->u_arg[2] == INFTIM)
326                         tprintf("INFTIM");
327                 else
328 #endif
329                         tprintf("%ld", tcp->u_arg[2]);
330                 free(pollp);
331         }
332         return 0;
333 }
334
335 #ifndef linux
336
337 static struct xlat stream_flush_options[] = {
338         { FLUSHR,       "FLUSHR"        },
339         { FLUSHW,       "FLUSHW"        },
340         { FLUSHRW,      "FLUSHRW"       },
341 #ifdef FLUSHBAND
342         { FLUSHBAND,    "FLUSHBAND"     },
343 #endif
344         { 0,            NULL            },
345 };
346
347 static struct xlat stream_setsig_flags[] = {
348         { S_INPUT,      "S_INPUT"       },
349         { S_HIPRI,      "S_HIPRI"       },
350         { S_OUTPUT,     "S_OUTPUT"      },
351         { S_MSG,        "S_MSG"         },
352 #ifdef S_ERROR
353         { S_ERROR,      "S_ERROR"       },
354 #endif
355 #ifdef S_HANGUP
356         { S_HANGUP,     "S_HANGUP"      },
357 #endif
358 #ifdef S_RDNORM
359         { S_RDNORM,     "S_RDNORM"      },
360 #endif
361 #ifdef S_WRNORM
362         { S_WRNORM,     "S_WRNORM"      },
363 #endif
364 #ifdef S_RDBAND
365         { S_RDBAND,     "S_RDBAND"      },
366 #endif
367 #ifdef S_WRBAND
368         { S_WRBAND,     "S_WRBAND"      },
369 #endif
370 #ifdef S_BANDURG
371         { S_BANDURG,    "S_BANDURG"     },
372 #endif
373         { 0,            NULL            },
374 };
375
376 static struct xlat stream_read_options[] = {
377         { RNORM,        "RNORM"         },
378         { RMSGD,        "RMSGD"         },
379         { RMSGN,        "RMSGN"         },
380         { 0,            NULL            },
381 };
382
383 static struct xlat stream_read_flags[] = {
384 #ifdef RPROTDAT
385         { RPROTDAT,     "RPROTDAT"      },
386 #endif
387 #ifdef RPROTDIS
388         { RPROTDIS,     "RPROTDIS"      },
389 #endif
390 #ifdef RPROTNORM
391         { RPROTNORM,    "RPROTNORM"     },
392 #endif
393         { 0,            NULL            },
394 };
395
396 #ifndef RMODEMASK
397 #define RMODEMASK (~0)
398 #endif
399
400 #ifdef I_SWROPT
401 static struct xlat stream_write_flags[] = {
402         { SNDZERO,      "SNDZERO"       },
403         { SNDPIPE,      "SNDPIPE"       },
404         { 0,            NULL            },
405 };
406 #endif /* I_SWROPT */
407
408 #ifdef I_ATMARK
409 static struct xlat stream_atmark_options[] = {
410         { ANYMARK,      "ANYMARK"       },
411         { LASTMARK,     "LASTMARK"      },
412         { 0,            NULL            },
413 };
414 #endif /* I_ATMARK */
415
416 #ifdef TI_BIND
417 static struct xlat transport_user_options[] = {
418         { T_CONN_REQ,   "T_CONN_REQ"    },
419         { T_CONN_RES,   "T_CONN_RES"    },
420         { T_DISCON_REQ, "T_DISCON_REQ"  },
421         { T_DATA_REQ,   "T_DATA_REQ"    },
422         { T_EXDATA_REQ, "T_EXDATA_REQ"  },
423         { T_INFO_REQ,   "T_INFO_REQ"    },
424         { T_BIND_REQ,   "T_BIND_REQ"    },
425         { T_UNBIND_REQ, "T_UNBIND_REQ"  },
426         { T_UNITDATA_REQ,"T_UNITDATA_REQ"},
427         { T_OPTMGMT_REQ,"T_OPTMGMT_REQ" },
428         { T_ORDREL_REQ, "T_ORDREL_REQ"  },
429         { 0,            NULL            },
430 };
431
432 static struct xlat transport_provider_options[] = {
433         { T_CONN_IND,   "T_CONN_IND"    },
434         { T_CONN_CON,   "T_CONN_CON"    },
435         { T_DISCON_IND, "T_DISCON_IND"  },
436         { T_DATA_IND,   "T_DATA_IND"    },
437         { T_EXDATA_IND, "T_EXDATA_IND"  },
438         { T_INFO_ACK,   "T_INFO_ACK"    },
439         { T_BIND_ACK,   "T_BIND_ACK"    },
440         { T_ERROR_ACK,  "T_ERROR_ACK"   },
441         { T_OK_ACK,     "T_OK_ACK"      },
442         { T_UNITDATA_IND,"T_UNITDATA_IND"},
443         { T_UDERROR_IND,"T_UDERROR_IND" },
444         { T_OPTMGMT_ACK,"T_OPTMGMT_ACK" },
445         { T_ORDREL_IND, "T_ORDREL_IND"  },
446         { 0,            NULL            },
447 };
448 #endif /* TI_BIND */
449
450 static int
451 internal_stream_ioctl(tcp, arg)
452 struct tcb *tcp;
453 int arg;
454 {
455         struct strioctl si;
456         char *name;
457         int in_and_out;
458 #ifdef SI_GETUDATA
459         struct si_udata udata;
460 #endif /* SI_GETUDATA */
461
462         if (!arg)
463                 return 0;
464         if (umove(tcp, arg, &si) < 0) {
465                 if (entering(tcp))
466                         tprintf(", {...}");
467                 return 1;
468         }
469         if (entering(tcp)) {
470                 name = ioctl_lookup(si.ic_cmd);
471                 if (name)
472                         tprintf(", {ic_cmd=%s", name);
473                 else
474                         tprintf(", {ic_cmd=%#x", si.ic_cmd);
475                 if (si.ic_timout == INFTIM)
476                         tprintf(", ic_timout=INFTIM, ");
477                 else
478                         tprintf(" ic_timout=%d, ", si.ic_timout);
479         }
480         in_and_out = 1;
481         switch (si.ic_cmd) {
482 #ifdef SI_GETUDATA
483         case SI_GETUDATA:
484                 in_and_out = 0;
485                 break;
486 #endif /* SI_GETUDATA */
487         }
488         if (in_and_out) {
489                 if (entering(tcp))
490                         tprintf("/* in */ ");
491                 else
492                         tprintf(", /* out */ ");
493         }
494         if (in_and_out || entering(tcp))
495                 tprintf("ic_len=%d, ic_dp=", si.ic_len);
496         switch (si.ic_cmd) {
497 #ifdef TI_BIND
498         case TI_BIND:
499                 /* in T_BIND_REQ, out T_BIND_ACK */
500                 if (entering(tcp)) {
501                         struct T_bind_req data;
502
503 #if 0
504                         tprintf("struct T_bind_req ");
505 #endif
506                         if (umove(tcp, (int) si.ic_dp, &data) < 0)
507                                 tprintf("{...}");
508                         else {
509                                 tprintf("{PRIM_type=");
510                                 printxval(transport_user_options,
511                                           data.PRIM_type, "T_???");
512                                 tprintf(", ADDR_length=%ld, ADDR_offset=%ld",
513                                         data.ADDR_length, data.ADDR_offset);
514                                 tprintf(", CONIND_number=%ld}",
515                                         data.CONIND_number);
516                         }
517                 }
518                 else {
519                         struct T_bind_ack data;
520
521 #if 0
522                         tprintf("struct T_bind_ack ");
523 #endif
524                         if (umove(tcp, (int) si.ic_dp, &data) < 0)
525                                 tprintf("{...}");
526                         else {
527                                 tprintf("[");
528                                 tprintf("{PRIM_type=");
529                                 printxval(transport_provider_options,
530                                           data.PRIM_type, "T_???");
531                                 tprintf(", ADDR_length=%ld, ADDR_offset=%ld",
532                                         data.ADDR_length, data.ADDR_offset);
533                                 tprintf(", CONIND_number=%ld}",
534                                         data.CONIND_number);
535                                 tprintf(", ");
536                                 printstr(tcp,
537                                          (int) si.ic_dp + data.ADDR_offset,
538                                          data.ADDR_length);
539                                 tprintf("]");
540                         }
541                 }
542                 break;
543 #endif /* TI_BIND */
544 #if 0
545 #ifdef TI_UNBIND
546         case TI_UNBIND:
547                 /* in T_UNBIND_REQ, out T_OK_ACK */
548                 break;
549 #endif /* TI_UNBIND */
550 #ifdef TI_GETINFO
551         case TI_GETINFO:
552                 /* in T_INFO_REQ, out T_INFO_ACK */
553                 break;
554 #endif /* TI_GETINFO */
555 #ifdef TI_OPTMGMT
556         case TI_OPTMGMT:
557                 /* in T_OPTMGMT_REQ, out T_OPTMGMT_ACK */
558                 break;
559 #endif /* TI_OPTMGMT */
560 #endif
561 #ifdef SI_GETUDATA
562         case SI_GETUDATA:
563                 if (entering(tcp))
564                         break;
565 #if 0
566                 tprintf("struct si_udata ");
567 #endif
568                 if (umove(tcp, (int) si.ic_dp, &udata) < 0)
569                         tprintf("{...}");
570                 else {
571                         tprintf("{tidusize=%d, addrsize=%d, ",
572                                 udata.tidusize, udata.addrsize);
573                         tprintf("optsize=%d, etsdusize=%d, ",
574                                 udata.optsize, udata.etsdusize);
575                         tprintf("servtype=%d, so_state=%d, ",
576                                 udata.servtype, udata.so_state);
577                         tprintf("so_options=%d", udata.so_options);
578 #if 0
579                         tprintf(", tsdusize=%d", udata.tsdusize);
580 #endif
581                         tprintf("}");
582                 }
583                 break;
584 #endif /* SI_GETUDATA */
585         default:
586                 printstr(tcp, (int) si.ic_dp, si.ic_len);
587                 break;
588         }
589         if (exiting(tcp))
590                 tprintf("}");
591         return 1;
592 }
593
594 int
595 stream_ioctl(tcp, code, arg)
596 struct tcb *tcp;
597 int code, arg;
598 {
599 #ifdef I_LIST
600         int i;
601 #endif
602         int val;
603 #ifdef I_FLUSHBAND
604         struct bandinfo bi;
605 #endif
606         struct strpeek sp;
607         struct strfdinsert sfi;
608         struct strrecvfd srf;
609 #ifdef I_LIST
610         struct str_list sl;
611 #endif
612
613         /* I_STR is a special case because the data is read & written. */
614         if (code == I_STR)
615                 return internal_stream_ioctl(tcp, arg);
616         if (entering(tcp))
617                 return 0;
618
619         switch (code) {
620         case I_PUSH:
621         case I_LOOK:
622         case I_FIND:
623                 /* arg is a string */
624                 tprintf(", ");
625                 printpath(tcp, arg);
626                 return 1;
627         case I_POP:
628                 /* doesn't take an argument */
629                 return 1;
630         case I_FLUSH:
631                 /* argument is an option */
632                 tprintf(", ");
633                 printxval(stream_flush_options, arg, "FLUSH???");
634                 return 1;
635 #ifdef I_FLUSHBAND
636         case I_FLUSHBAND:
637                 /* argument is a pointer to a bandinfo struct */
638                 if (umove(tcp, arg, &bi) < 0)
639                         tprintf(", {...}");
640                 else {
641                         tprintf(", {bi_pri=%d, bi_flag=", bi.bi_pri);
642                         if (!printflags(stream_flush_options, bi.bi_flag))
643                                 tprintf("0");
644                         tprintf("}");
645                 }
646                 return 1;
647 #endif /* I_FLUSHBAND */
648         case I_SETSIG:
649                 /* argument is a set of flags */
650                 tprintf(", ");
651                 if (!printflags(stream_setsig_flags, arg))
652                         tprintf("0");
653                 return 1;
654         case I_GETSIG:
655                 /* argument is a pointer to a set of flags */
656                 if (syserror(tcp))
657                         return 0;
658                 tprintf(", [");
659                 if (umove(tcp, arg, &val) < 0)
660                         tprintf("?");
661                 else if (!printflags(stream_setsig_flags, val))
662                         tprintf("0");
663                 tprintf("]");
664                 return 1;
665         case I_PEEK:
666                 /* argument is a pointer to a strpeek structure */
667                 if (syserror(tcp) || !arg)
668                         return 0;
669                 if (umove(tcp, arg, &sp) < 0) {
670                         tprintf(", {...}");
671                         return 1;
672                 }
673                 tprintf(", {ctlbuf=");
674                 printstrbuf(tcp, &sp.ctlbuf, 1);
675                 tprintf(", databuf=");
676                 printstrbuf(tcp, &sp.databuf, 1);
677                 if (!printflags(msgflags, sp.flags))
678                         tprintf("0");
679                 return 1;
680         case I_SRDOPT:
681                 /* argument is an option with flags */
682                 tprintf(", ");
683                 printxval(stream_read_options, arg & RMODEMASK, "R???");
684                 addflags(stream_read_flags, arg & ~RMODEMASK);
685                 return 1;
686         case I_GRDOPT:
687                 /* argument is an pointer to an option with flags */
688                 if (syserror(tcp))
689                         return 0;
690                 tprintf(", [");
691                 if (umove(tcp, arg, &val) < 0)
692                         tprintf("?");
693                 else {
694                         printxval(stream_read_options,
695                                   arg & RMODEMASK, "R???");
696                         addflags(stream_read_flags, arg & ~RMODEMASK);
697                 }
698                 tprintf("]");
699                 return 1;
700         case I_NREAD:
701 #ifdef I_GETBAND
702         case I_GETBAND:
703 #endif
704 #ifdef I_SETCLTIME
705         case I_SETCLTIME:
706 #endif
707 #ifdef I_GETCLTIME
708         case I_GETCLTIME:
709 #endif
710                 /* argument is a pointer to a decimal integer */
711                 if (syserror(tcp))
712                         return 0;
713                 tprintf(", ");
714                 printnum(tcp, arg, "%d");
715                 return 1;
716         case I_FDINSERT:
717                 /* argument is a pointer to a strfdinsert structure */
718                 if (syserror(tcp) || !arg)
719                         return 0;
720                 if (umove(tcp, arg, &sfi) < 0) {
721                         tprintf(", {...}");
722                         return 1;
723                 }
724                 tprintf(", {ctlbuf=");
725                 printstrbuf(tcp, &sfi.ctlbuf, 1);
726                 tprintf(", databuf=");
727                 printstrbuf(tcp, &sfi.databuf, 1);
728                 if (!printflags(msgflags, sfi.flags))
729                         tprintf("0");
730                 tprintf(", filedes=%d, offset=%d}", sfi.fildes, sfi.offset);
731                 return 1;
732 #ifdef I_SWROPT
733         case I_SWROPT:
734                 /* argument is a set of flags */
735                 tprintf(", ");
736                 if (!printflags(stream_write_flags, arg))
737                         tprintf("0");
738                 return 1;
739 #endif /* I_SWROPT */
740 #ifdef I_GWROPT
741         case I_GWROPT:
742                 /* argument is an pointer to an option with flags */
743                 if (syserror(tcp))
744                         return 0;
745                 tprintf(", [");
746                 if (umove(tcp, arg, &val) < 0)
747                         tprintf("?");
748                 else if (!printflags(stream_write_flags, arg))
749                         tprintf("0");
750                 tprintf("]");
751                 return 1;
752 #endif /* I_GWROPT */
753         case I_SENDFD:
754 #ifdef I_CKBAND
755         case I_CKBAND:
756 #endif
757 #ifdef I_CANPUT
758         case I_CANPUT:
759 #endif
760         case I_LINK:
761         case I_UNLINK:
762         case I_PLINK:
763         case I_PUNLINK:
764                 /* argument is a decimal integer */
765                 tprintf(", %d", arg);
766                 return 1;
767         case I_RECVFD:
768                 /* argument is a pointer to a strrecvfd structure */
769                 if (syserror(tcp) || !arg)
770                         return 0;
771                 if (umove(tcp, arg, &srf) < 0) {
772                         tprintf(", {...}");
773                         return 1;
774                 }
775                 tprintf(", {fd=%d, uid=%lu, gid=%lu}", srf.fd,
776                         (unsigned long) srf.uid, (unsigned long) srf.gid);
777                 return 1;
778 #ifdef I_LIST
779         case I_LIST:
780                 if (syserror(tcp))
781                         return 0;
782                 if (arg == 0) {
783                         tprintf(", NULL");
784                         return 1;
785                 }
786                 if (umove(tcp, arg, &sl) < 0) {
787                         tprintf(", {...}");
788                         return 1;
789                 }
790                 tprintf(", {sl_nmods=%d, sl_modlist=[", sl.sl_nmods);
791                 for (i = 0; i < tcp->u_rval; i++) {
792                         if (i)
793                                 tprintf(", ");
794                         printpath(tcp, (int) sl.sl_modlist[i].l_name);
795                 }
796                 tprintf("]}");
797                 return 1;
798 #endif /* I_LIST */
799 #ifdef I_ATMARK
800         case I_ATMARK:
801                 tprintf(", ");
802                 printxval(stream_atmark_options, arg, "???MARK");
803                 return 1;
804 #endif /* I_ATMARK */
805         default:
806                 return 0;
807         }
808 }
809
810 #endif /* linux */
811
812 #endif /* LINUXSPARC && linux */
813