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 * Copyright (c) 1999-2021 The strace developers.
7 * All rights reserved.
8 *
9 * SPDX-License-Identifier: LGPL-2.1-or-later
10 */
11
12 #include "defs.h"
13 #include "xstring.h"
14
15 SYS_FUNC(close)
16 {
17 printfd(tcp, tcp->u_arg[0]);
18
19 return RVAL_DECODED;
20 }
21
22 static int
23 decode_select(struct tcb *const tcp, const kernel_ulong_t *const args,
24 const print_obj_by_addr_fn print_tv_ts,
25 const sprint_obj_by_addr_fn sprint_tv_ts)
26 {
27 /* Kernel truncates args[0] to int, we do the same. */
28 int nfds = (int) args[0];
29
30 /* Kernel rejects negative nfds, so we don't parse it either. */
31 if (nfds < 0)
32 nfds = 0;
33
34 /* Beware of select(2^31-1, NULL, NULL, NULL) and similar... */
35 if (nfds > 1024*1024)
36 nfds = 1024*1024;
37
38 /*
39 * We had bugs a-la "while (j < args[0])" and "umoven(args[0])" below.
40 * Instead of args[0], use nfds for fd count, fdsize for array lengths.
41 */
42 int fdsize = (((nfds + 7) / 8) + current_wordsize-1) & -current_wordsize;
43 fd_set *fds = NULL;
44
45 if (entering(tcp)) {
46 PRINT_VAL_D((int) args[0]);
47
48 if (verbose(tcp) && fdsize > 0)
49 fds = malloc(fdsize);
50 for (unsigned int i = 0; i < 3; ++i) {
51 kernel_ulong_t addr = args[i + 1];
52
53 tprint_arg_next();
54 if (!fds) {
55 printaddr(addr);
56 continue;
57 }
58 if (umoven_or_printaddr(tcp, addr, fdsize, fds))
59 continue;
60 tprint_bitset_begin();
61 bool next = false;
62 for (int j = 0;; ++j) {
63 j = next_set_bit(fds, j, nfds);
64 if (j < 0)
65 break;
66 if (next)
67 tprint_bitset_next();
68 else
69 next = true;
70 printfd(tcp, j);
71 }
72 tprint_bitset_end();
73 }
74 free(fds);
75 tprint_arg_next();
76 print_tv_ts(tcp, args[4]);
77 } else {
78 static char outstr[1024];
79 char *outptr;
80 #define end_outstr (outstr + sizeof(outstr))
81 int ready_fds;
82
83 if (syserror(tcp))
84 return 0;
85
86 ready_fds = tcp->u_rval;
87 if (ready_fds == 0) {
88 tcp->auxstr = "Timeout";
89 return RVAL_STR;
90 }
91
92 fds = malloc(fdsize);
93
94 outptr = outstr;
95 const char *sep = "";
96 for (unsigned int i = 0; i < 3 && ready_fds > 0; ++i) {
97 int first = 1;
98 kernel_ulong_t addr = args[i + 1];
99
100 if (!addr || !fds || umoven(tcp, addr, fdsize, fds) < 0)
101 continue;
102 for (int j = 0;; ++j) {
103 j = next_set_bit(fds, j, nfds);
104 if (j < 0)
105 break;
106 /* +2 chars needed at the end: ']',NUL */
107 if (outptr < end_outstr - (sizeof(", except [") + sizeof(int)*3 + 2)) {
108 if (first) {
109 outptr = xappendstr(outstr,
110 outptr,
111 "%s%s [%u",
112 sep,
113 i == 0 ? "in" : i == 1 ? "out" : "except",
114 j
115 );
116 first = 0;
117 sep = ", ";
118 } else {
119 outptr = xappendstr(outstr,
120 outptr,
121 " %u", j);
122 }
123 }
124 if (--ready_fds == 0)
125 break;
126 }
127 if (outptr != outstr)
128 *outptr++ = ']';
129 }
130 free(fds);
131 /* This contains no useful information on SunOS. */
132 if (args[4]) {
133 const char *str = sprint_tv_ts(tcp, args[4]);
134 if (outptr + sizeof("left ") + strlen(sep) + strlen(str) < end_outstr) {
135 outptr = xappendstr(outstr, outptr,
136 "%sleft %s", sep, str);
137 }
138 }
139 *outptr = '\0';
140 tcp->auxstr = outstr;
141 return RVAL_STR;
142 #undef end_outstr
143 }
144 return 0;
145 }
146
147 #if HAVE_ARCH_OLD_SELECT
148 SYS_FUNC(oldselect)
149 {
150 kernel_ulong_t *args =
151 fetch_indirect_syscall_args(tcp, tcp->u_arg[0], 5);
152
153 if (args) {
154 return decode_select(tcp, args, print_timeval, sprint_timeval);
155 } else {
156 if (entering(tcp))
157 printaddr(tcp->u_arg[0]);
158 return RVAL_DECODED;
159 }
160 }
161 #endif /* HAVE_ARCH_OLD_SELECT */
162
163 #ifdef ALPHA
164 SYS_FUNC(osf_select)
165 {
166 return decode_select(tcp, tcp->u_arg, print_timeval32, sprint_timeval32);
167 }
168 #endif
169
170 SYS_FUNC(select)
171 {
172 return decode_select(tcp, tcp->u_arg, print_timeval, sprint_timeval);
173 }
174
175 static int
176 do_pselect6(struct tcb *const tcp, const print_obj_by_addr_fn print_ts,
177 const sprint_obj_by_addr_fn sprint_ts)
178 {
179 int rc = decode_select(tcp, tcp->u_arg, print_ts, sprint_ts);
180 if (entering(tcp)) {
181 tprint_arg_next();
182 print_kernel_sigset(tcp, tcp->u_arg[5]);
183 }
184
185 return rc;
186 }
187
188 #if HAVE_ARCH_TIME32_SYSCALLS
189 SYS_FUNC(pselect6_time32)
190 {
191 return do_pselect6(tcp, print_timespec32, sprint_timespec32);
192 }
193 #endif
194
195 SYS_FUNC(pselect6_time64)
196 {
197 return do_pselect6(tcp, print_timespec64, sprint_timespec64);
198 }