File: | obj-scan-build/proc/../../proc/info.c |
Location: | line 612, column 5 |
Description: | Function call argument is an uninitialized value |
1 | /* Process information queries | |||
2 | Copyright (C) 1992,93,94,95,96,99,2000,01,02 Free Software Foundation, Inc. | |||
3 | ||||
4 | This file is part of the GNU Hurd. | |||
5 | ||||
6 | The GNU Hurd is free software; you can redistribute it and/or modify | |||
7 | it under the terms of the GNU General Public License as published by | |||
8 | the Free Software Foundation; either version 2, or (at your option) | |||
9 | any later version. | |||
10 | ||||
11 | The GNU Hurd is distributed in the hope that it will be useful, | |||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
14 | GNU General Public License for more details. | |||
15 | ||||
16 | You should have received a copy of the GNU General Public License | |||
17 | along with the GNU Hurd; see the file COPYING. If not, write to | |||
18 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |||
19 | ||||
20 | /* Written by Michael I. Bushnell. */ | |||
21 | ||||
22 | #include <mach.h> | |||
23 | #include <sys/types.h> | |||
24 | #include <sys/mman.h> | |||
25 | #include <hurd/hurd_types.h> | |||
26 | #include <stdlib.h> | |||
27 | #include <errno(*__errno_location ()).h> | |||
28 | #include <string.h> | |||
29 | #include <sys/resource.h> | |||
30 | #include <assert.h> | |||
31 | #include <hurd/msg.h> | |||
32 | ||||
33 | #include "proc.h" | |||
34 | #include "process_S.h" | |||
35 | ||||
36 | ||||
37 | /* Returns true if PROC1 has `owner' privileges over PROC2 (and can thus get | |||
38 | its task port &c). If PROC2 has an owner, then PROC1 must have that uid; | |||
39 | otherwise, both must be in the same login collection. */ | |||
40 | int | |||
41 | check_owner (struct proc *proc1, struct proc *proc2) | |||
42 | { | |||
43 | return | |||
44 | proc2->p_noowner | |||
45 | ? check_uid (proc1, 0) || proc1->p_login == proc2->p_login | |||
46 | : check_uid (proc1, proc2->p_owner); | |||
47 | } | |||
48 | ||||
49 | ||||
50 | /* Implement S_proc_pid2task as described in <hurd/process.defs>. */ | |||
51 | kern_return_t | |||
52 | S_proc_pid2task (struct proc *callerp, | |||
53 | pid_t pid, | |||
54 | task_t *t) | |||
55 | { | |||
56 | struct proc *p; | |||
57 | ||||
58 | if (!callerp) | |||
59 | return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); | |||
60 | ||||
61 | p = pid_find_allow_zombie (pid); | |||
62 | if (!p) | |||
63 | return ESRCH((0x10 << 26) | ((3) & 0x3fff)); | |||
64 | ||||
65 | if (p->p_dead) | |||
66 | { | |||
67 | *t = MACH_PORT_NULL((mach_port_t) 0); | |||
68 | return 0; | |||
69 | } | |||
70 | ||||
71 | if (! check_owner (callerp, p)) | |||
72 | return EPERM((0x10 << 26) | ((1) & 0x3fff)); | |||
73 | ||||
74 | assert (MACH_PORT_VALID (p->p_task))(((((p->p_task) != ((mach_port_t) 0)) && ((p->p_task ) != ((mach_port_t) ~0)))) ? (void) (0) : __assert_fail ("(((p->p_task) != ((mach_port_t) 0)) && ((p->p_task) != ((mach_port_t) ~0)))" , "../../proc/info.c", 74, __PRETTY_FUNCTION__)); | |||
75 | *t = p->p_task; | |||
76 | ||||
77 | return 0; | |||
78 | } | |||
79 | ||||
80 | /* Implement proc_task2pid as described in <hurd/process.defs>. */ | |||
81 | kern_return_t | |||
82 | S_proc_task2pid (struct proc *callerp, | |||
83 | task_t t, | |||
84 | pid_t *pid) | |||
85 | { | |||
86 | struct proc *p = task_find (t); | |||
87 | ||||
88 | /* No need to check CALLERP here; we don't use it. */ | |||
89 | ||||
90 | if (!p) | |||
91 | return ESRCH((0x10 << 26) | ((3) & 0x3fff)); | |||
92 | ||||
93 | *pid = p->p_pid; | |||
94 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), t); | |||
95 | return 0; | |||
96 | } | |||
97 | ||||
98 | /* Implement proc_task2proc as described in <hurd/process.defs>. */ | |||
99 | kern_return_t | |||
100 | S_proc_task2proc (struct proc *callerp, | |||
101 | task_t t, | |||
102 | mach_port_t *outproc) | |||
103 | { | |||
104 | struct proc *p = task_find (t); | |||
105 | ||||
106 | /* No need to check CALLERP here; we don't use it. */ | |||
107 | ||||
108 | if (!p) | |||
109 | return ESRCH((0x10 << 26) | ((3) & 0x3fff)); | |||
110 | ||||
111 | *outproc = ports_get_right (p); | |||
112 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), t); | |||
113 | return 0; | |||
114 | } | |||
115 | ||||
116 | /* Implement proc_proc2task as described in <hurd/process.defs>. */ | |||
117 | kern_return_t | |||
118 | S_proc_proc2task (struct proc *p, | |||
119 | task_t *t) | |||
120 | { | |||
121 | if (!p) | |||
122 | return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); | |||
123 | *t = p->p_task; | |||
124 | return 0; | |||
125 | } | |||
126 | ||||
127 | /* Implement proc_pid2proc as described in <hurd/process.defs>. */ | |||
128 | kern_return_t | |||
129 | S_proc_pid2proc (struct proc *callerp, | |||
130 | pid_t pid, | |||
131 | mach_port_t *outproc) | |||
132 | { | |||
133 | struct proc *p; | |||
134 | ||||
135 | if (!callerp) | |||
136 | return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); | |||
137 | ||||
138 | p = pid_find_allow_zombie (pid); | |||
139 | if (!p) | |||
140 | return ESRCH((0x10 << 26) | ((3) & 0x3fff)); | |||
141 | ||||
142 | if (p->p_dead) | |||
143 | { | |||
144 | *outproc = MACH_PORT_NULL((mach_port_t) 0); | |||
145 | return 0; | |||
146 | } | |||
147 | ||||
148 | if (! check_owner (callerp, p)) | |||
149 | return EPERM((0x10 << 26) | ((1) & 0x3fff)); | |||
150 | ||||
151 | *outproc = ports_get_right (p); | |||
152 | return 0; | |||
153 | } | |||
154 | ||||
155 | ||||
156 | /* Read a string starting at address ADDR in task T; set *STR to point at | |||
157 | newly malloced storage holding it, and *LEN to its length with null. */ | |||
158 | static error_t | |||
159 | get_string (task_t t, | |||
160 | vm_address_t addr, | |||
161 | char **str, size_t *len) | |||
162 | { | |||
163 | /* This version assumes that a string is never more than one | |||
164 | page in length. */ | |||
165 | ||||
166 | vm_address_t readaddr; | |||
167 | vm_address_t data; | |||
168 | size_t readlen; | |||
169 | error_t err; | |||
170 | char *c; | |||
171 | ||||
172 | readaddr = trunc_page (addr)((((vm_offset_t) (addr)) / __vm_page_size) * __vm_page_size); | |||
173 | err = vm_read (t, readaddr, vm_page_size * 2, &data, &readlen); | |||
174 | if (err == KERN_INVALID_ADDRESS1) | |||
175 | err = vm_read (t, readaddr, vm_page_size, &data, &readlen); | |||
176 | if (err == MACH_SEND_INVALID_DEST0x10000003) | |||
177 | err = ESRCH((0x10 << 26) | ((3) & 0x3fff)); | |||
178 | if (err) | |||
179 | return err; | |||
180 | ||||
181 | /* Scan for a null. */ | |||
182 | c = memchr ((char *) (data + (addr - readaddr)), '\0', | |||
183 | readlen - (addr - readaddr)); | |||
184 | if (c == NULL((void*)0)) | |||
185 | err = KERN_INVALID_ADDRESS1; | |||
186 | else | |||
187 | { | |||
188 | c++; /* Include the null. */ | |||
189 | *len = c - (char *) (data + (addr - readaddr)); | |||
190 | *str = malloc (*len); | |||
191 | if (*str == NULL((void*)0)) | |||
192 | err = ENOMEM((0x10 << 26) | ((12) & 0x3fff)); | |||
193 | else | |||
194 | memcpy (*str, (char *) data + (addr - readaddr), *len); | |||
195 | } | |||
196 | ||||
197 | munmap ((caddr_t) data, readlen); | |||
198 | return err; | |||
199 | } | |||
200 | ||||
201 | /* Read a vector of addresses (stored as are argv and envp) from task TASK | |||
202 | found at address ADDR. Set *VEC to point to newly malloced storage holding | |||
203 | the addresses. */ | |||
204 | static error_t | |||
205 | get_vector (task_t task, | |||
206 | vm_address_t addr, | |||
207 | int **vec) | |||
208 | { | |||
209 | vm_address_t readaddr; | |||
210 | vm_size_t readsize; | |||
211 | vm_address_t scanned; | |||
212 | error_t err; | |||
213 | ||||
214 | *vec = NULL((void*)0); | |||
215 | readaddr = trunc_page (addr)((((vm_offset_t) (addr)) / __vm_page_size) * __vm_page_size); | |||
216 | readsize = 0; | |||
217 | scanned = addr; | |||
218 | do | |||
219 | { | |||
220 | vm_address_t data; | |||
221 | mach_msg_type_number_t readlen = 0; | |||
222 | vm_address_t *t; | |||
223 | ||||
224 | readsize += vm_page_size; | |||
225 | err = vm_read (task, readaddr, readsize, &data, &readlen); | |||
226 | if (err == MACH_SEND_INVALID_DEST0x10000003) | |||
227 | err = ESRCH((0x10 << 26) | ((3) & 0x3fff)); | |||
228 | if (err) | |||
229 | return err; | |||
230 | ||||
231 | /* Scan for a null. */ | |||
232 | for (t = (vm_address_t *) (data + (scanned - readaddr)); | |||
233 | t < (vm_address_t *) (data + readlen); | |||
234 | ++t) | |||
235 | if (*t == 0) | |||
236 | { | |||
237 | ++t; /* Include the null. */ | |||
238 | *vec = malloc ((char *)t - (char *)(data + (addr - readaddr))); | |||
239 | if (*vec == NULL((void*)0)) | |||
240 | err = ENOMEM((0x10 << 26) | ((12) & 0x3fff)); | |||
241 | else | |||
242 | memcpy (*vec, (char *)(data + (addr - readaddr)), | |||
243 | (char *)t - (char *)(data + (addr - readaddr))); | |||
244 | break; | |||
245 | } | |||
246 | ||||
247 | /* If we didn't find the null terminator, then we will loop | |||
248 | to read an additional page. */ | |||
249 | scanned = readaddr + readlen; | |||
250 | munmap ((caddr_t) data, readlen); | |||
251 | } while (!err && *vec == NULL((void*)0)); | |||
252 | ||||
253 | return err; | |||
254 | } | |||
255 | ||||
256 | /* Fetch an array of strings at address LOC in task T into | |||
257 | BUF of size BUFLEN. */ | |||
258 | static error_t | |||
259 | get_string_array (task_t t, | |||
260 | vm_address_t loc, | |||
261 | vm_address_t *buf, | |||
262 | size_t *buflen) | |||
263 | { | |||
264 | char *bp; | |||
265 | int *vector, *vp; | |||
266 | error_t err; | |||
267 | vm_address_t origbuf = *buf; | |||
268 | ||||
269 | err = get_vector (t, loc, &vector); | |||
270 | if (err) | |||
271 | return err; | |||
272 | ||||
273 | bp = (char *) *buf; | |||
274 | for (vp = vector; *vp; ++vp) | |||
275 | { | |||
276 | char *string; | |||
277 | size_t len; | |||
278 | ||||
279 | err = get_string (t, *vp, &string, &len); | |||
280 | if (err) | |||
281 | { | |||
282 | free (vector); | |||
283 | if (*buf != origbuf) | |||
284 | munmap ((caddr_t) *buf, *buflen); | |||
285 | return err; | |||
286 | } | |||
287 | ||||
288 | if (len > (char *) *buf + *buflen - bp) | |||
289 | { | |||
290 | char *newbuf; | |||
291 | vm_size_t prev_len = bp - (char *) *buf; | |||
292 | vm_size_t newsize = *buflen * 2; | |||
293 | ||||
294 | if (newsize < prev_len + len) | |||
295 | /* Since we will mmap whole pages anyway, | |||
296 | notice how much space we really have. */ | |||
297 | newsize = round_page (prev_len + len)((((vm_offset_t) (prev_len + len) + __vm_page_size - 1) / __vm_page_size ) * __vm_page_size); | |||
298 | ||||
299 | newbuf = mmap (0, newsize, PROT_READ0x04|PROT_WRITE0x02, MAP_ANON0x0002, 0, 0); | |||
300 | if (newbuf == MAP_FAILED((void *) -1)) | |||
301 | { | |||
302 | err = errno(*__errno_location ()); | |||
303 | free (string); | |||
304 | free (vector); | |||
305 | if (*buf != origbuf) | |||
306 | munmap ((caddr_t) *buf, *buflen); | |||
307 | return err; | |||
308 | } | |||
309 | ||||
310 | memcpy (newbuf, (char *) *buf, prev_len); | |||
311 | bp = newbuf + prev_len; | |||
312 | if (*buf != origbuf) | |||
313 | munmap ((caddr_t) *buf, *buflen); | |||
314 | ||||
315 | *buf = (vm_address_t) newbuf; | |||
316 | *buflen = newsize; | |||
317 | } | |||
318 | ||||
319 | memcpy (bp, string, len); | |||
320 | bp += len; | |||
321 | free (string); | |||
322 | } | |||
323 | ||||
324 | free (vector); | |||
325 | *buflen = bp - (char *) *buf; | |||
326 | return 0; | |||
327 | } | |||
328 | ||||
329 | ||||
330 | /* Implement proc_getprocargs as described in <hurd/process.defs>. */ | |||
331 | kern_return_t | |||
332 | S_proc_getprocargs (struct proc *callerp, | |||
333 | pid_t pid, | |||
334 | char **buf, | |||
335 | size_t *buflen) | |||
336 | { | |||
337 | struct proc *p = pid_find (pid); | |||
338 | ||||
339 | /* No need to check CALLERP here; we don't use it. */ | |||
340 | ||||
341 | if (!p) | |||
342 | return ESRCH((0x10 << 26) | ((3) & 0x3fff)); | |||
343 | ||||
344 | return get_string_array (p->p_task, p->p_argv, (vm_address_t *) buf, buflen); | |||
345 | } | |||
346 | ||||
347 | /* Implement proc_getprocenv as described in <hurd/process.defs>. */ | |||
348 | kern_return_t | |||
349 | S_proc_getprocenv (struct proc *callerp, | |||
350 | pid_t pid, | |||
351 | char **buf, | |||
352 | size_t *buflen) | |||
353 | { | |||
354 | struct proc *p = pid_find (pid); | |||
355 | ||||
356 | /* No need to check CALLERP here; we don't use it. */ | |||
357 | ||||
358 | if (!p) | |||
359 | return ESRCH((0x10 << 26) | ((3) & 0x3fff)); | |||
360 | ||||
361 | return get_string_array (p->p_task, p->p_envp, (vm_address_t *)buf, buflen); | |||
362 | } | |||
363 | ||||
364 | /* Handy abbreviation for all the various thread details. */ | |||
365 | #define PI_FETCH_THREAD_DETAILS(0x0008 | 0x0004 | 0x0010) \ | |||
366 | (PI_FETCH_THREAD_SCHED0x0008 | PI_FETCH_THREAD_BASIC0x0004 | PI_FETCH_THREAD_WAITS0x0010) | |||
367 | ||||
368 | /* Implement proc_getprocinfo as described in <hurd/process.defs>. */ | |||
369 | kern_return_t | |||
370 | S_proc_getprocinfo (struct proc *callerp, | |||
371 | pid_t pid, | |||
372 | int *flags, | |||
373 | int **piarray, | |||
374 | size_t *piarraylen, | |||
375 | char **waits, mach_msg_type_number_t *waits_len) | |||
376 | { | |||
377 | struct proc *p = pid_find (pid); | |||
378 | struct procinfo *pi; | |||
379 | size_t nthreads; | |||
380 | thread_t *thds; | |||
| ||||
381 | error_t err = 0; | |||
382 | size_t structsize; | |||
383 | int i; | |||
384 | int pi_alloced = 0, waits_alloced = 0; | |||
385 | /* The amount of WAITS we've filled in so far. */ | |||
386 | mach_msg_type_number_t waits_used = 0; | |||
387 | size_t tkcount, thcount; | |||
388 | struct proc *tp; | |||
389 | task_t task; /* P's task port. */ | |||
390 | mach_port_t msgport; /* P's msgport, or MACH_PORT_NULL if none. */ | |||
391 | ||||
392 | /* No need to check CALLERP here; we don't use it. */ | |||
393 | ||||
394 | if (!p) | |||
395 | return ESRCH((0x10 << 26) | ((3) & 0x3fff)); | |||
396 | ||||
397 | task = p->p_task; | |||
398 | ||||
399 | check_msgport_death (p); | |||
400 | msgport = p->p_msgport; | |||
401 | ||||
402 | if (*flags & PI_FETCH_THREAD_DETAILS(0x0008 | 0x0004 | 0x0010)) | |||
403 | *flags |= PI_FETCH_THREADS0x0002; | |||
404 | ||||
405 | if (*flags & PI_FETCH_THREADS0x0002) | |||
406 | { | |||
407 | err = task_threads (p->p_task, &thds, &nthreads); | |||
408 | if (err == MACH_SEND_INVALID_DEST0x10000003) | |||
409 | err = ESRCH((0x10 << 26) | ((3) & 0x3fff)); | |||
410 | if (err) | |||
411 | return err; | |||
412 | } | |||
413 | else | |||
414 | nthreads = 0; | |||
415 | ||||
416 | structsize = sizeof (struct procinfo); | |||
417 | if (*flags & PI_FETCH_THREAD_DETAILS(0x0008 | 0x0004 | 0x0010)) | |||
418 | structsize += nthreads * sizeof (pi->threadinfos[0]); | |||
419 | ||||
420 | if (structsize / sizeof (int) > *piarraylen) | |||
421 | { | |||
422 | *piarray = mmap (0, structsize, PROT_READ0x04|PROT_WRITE0x02, MAP_ANON0x0002, 0, 0); | |||
423 | if (*piarray == MAP_FAILED((void *) -1)) | |||
424 | { | |||
425 | err = errno(*__errno_location ()); | |||
426 | if (*flags & PI_FETCH_THREADS0x0002) | |||
427 | { | |||
428 | for (i = 0; i < nthreads; i++) | |||
429 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), thds[i]); | |||
430 | munmap (thds, nthreads * sizeof (thread_t)); | |||
431 | } | |||
432 | return err; | |||
433 | } | |||
434 | pi_alloced = 1; | |||
435 | } | |||
436 | *piarraylen = structsize / sizeof (int); | |||
437 | pi = (struct procinfo *) *piarray; | |||
438 | ||||
439 | pi->state = | |||
440 | ((p->p_stopped ? PI_STOPPED0x00000001 : 0) | |||
441 | | (p->p_exec ? PI_EXECED0x00000002 : 0) | |||
442 | | (p->p_waiting ? PI_WAITING0x00000004 : 0) | |||
443 | | (!p->p_pgrp->pg_orphcnt ? PI_ORPHAN0x00000008 : 0) | |||
444 | | (p->p_msgport == MACH_PORT_NULL((mach_port_t) 0) ? PI_NOMSG0x00000010 : 0) | |||
445 | | (p->p_pgrp->pg_session->s_sid == p->p_pid ? PI_SESSLD0x00000020 : 0) | |||
446 | | (p->p_noowner ? PI_NOTOWNED0x0000040 : 0) | |||
447 | | (!p->p_parentset ? PI_NOPARENT0x0000080 : 0) | |||
448 | | (p->p_traced ? PI_TRACED0x00000200 : 0) | |||
449 | | (p->p_msgportwait ? PI_GETMSG0x00000400 : 0) | |||
450 | | (p->p_loginleader ? PI_LOGINLD0x00000800 : 0)); | |||
451 | pi->owner = p->p_owner; | |||
452 | pi->ppid = p->p_parent->p_pid; | |||
453 | pi->pgrp = p->p_pgrp->pg_pgid; | |||
454 | pi->session = p->p_pgrp->pg_session->s_sid; | |||
455 | for (tp = p; !tp->p_loginleader; tp = tp->p_parent) | |||
456 | assert (tp)((tp) ? (void) (0) : __assert_fail ("tp", "../../proc/info.c" , 456, __PRETTY_FUNCTION__)); | |||
457 | pi->logincollection = tp->p_pid; | |||
458 | if (p->p_dead || p->p_stopped) | |||
459 | { | |||
460 | pi->exitstatus = p->p_status; | |||
461 | pi->sigcode = p->p_sigcode; | |||
462 | } | |||
463 | else | |||
464 | pi->exitstatus = pi->sigcode = 0; | |||
465 | ||||
466 | pi->nthreads = nthreads; | |||
467 | ||||
468 | /* Release GLOBAL_LOCK around time consuming bits, and more importatantly, | |||
469 | potential calls to P's msgport, which can block. */ | |||
470 | pthread_mutex_unlock (&global_lock); | |||
471 | ||||
472 | if (*flags & PI_FETCH_TASKINFO0x0001) | |||
473 | { | |||
474 | tkcount = TASK_BASIC_INFO_COUNT(sizeof(task_basic_info_data_t) / sizeof(natural_t)); | |||
475 | err = task_info (task, TASK_BASIC_INFO1, | |||
476 | (task_info_t) &pi->taskinfo, &tkcount); | |||
477 | if (err == MACH_SEND_INVALID_DEST0x10000003) | |||
478 | err = ESRCH((0x10 << 26) | ((3) & 0x3fff)); | |||
479 | #ifdef TASK_SCHED_TIMESHARE_INFO | |||
480 | if (!err) | |||
481 | { | |||
482 | tkcount = TASK_SCHED_TIMESHARE_INFO_COUNT; | |||
483 | err = task_info (task, TASK_SCHED_TIMESHARE_INFO, | |||
484 | (int *)&pi->timeshare_base_info, &tkcount); | |||
485 | if (err == KERN_INVALID_POLICY) | |||
486 | { | |||
487 | pi->timeshare_base_info.base_priority = -1; | |||
488 | err = 0; | |||
489 | } | |||
490 | } | |||
491 | #endif | |||
492 | } | |||
493 | if (*flags & PI_FETCH_TASKEVENTS0x0020) | |||
494 | { | |||
495 | tkcount = TASK_EVENTS_INFO_COUNT(sizeof(task_events_info_data_t) / sizeof(natural_t)); | |||
496 | err = task_info (task, TASK_EVENTS_INFO2, | |||
497 | (task_info_t) &pi->taskevents, &tkcount); | |||
498 | if (err == MACH_SEND_INVALID_DEST0x10000003) | |||
499 | err = ESRCH((0x10 << 26) | ((3) & 0x3fff)); | |||
500 | if (err) | |||
501 | { | |||
502 | /* Something screwy, give up on this bit of info. */ | |||
503 | *flags &= ~PI_FETCH_TASKEVENTS0x0020; | |||
504 | err = 0; | |||
505 | } | |||
506 | } | |||
507 | ||||
508 | for (i = 0; i < nthreads; i++) | |||
509 | { | |||
510 | if (*flags & PI_FETCH_THREAD_DETAILS(0x0008 | 0x0004 | 0x0010)) | |||
511 | pi->threadinfos[i].died = 0; | |||
512 | if (*flags & PI_FETCH_THREAD_BASIC0x0004) | |||
513 | { | |||
514 | thcount = THREAD_BASIC_INFO_COUNT(sizeof(thread_basic_info_data_t) / sizeof(natural_t)); | |||
515 | err = thread_info (thds[i], THREAD_BASIC_INFO1, | |||
516 | (thread_info_t) &pi->threadinfos[i].pis_bi, | |||
517 | &thcount); | |||
518 | if (err == MACH_SEND_INVALID_DEST0x10000003) | |||
519 | { | |||
520 | pi->threadinfos[i].died = 1; | |||
521 | err = 0; | |||
522 | continue; | |||
523 | } | |||
524 | else if (err) | |||
525 | /* Something screwy, give up on this bit of info. */ | |||
526 | { | |||
527 | *flags &= ~PI_FETCH_THREAD_BASIC0x0004; | |||
528 | err = 0; | |||
529 | } | |||
530 | } | |||
531 | ||||
532 | if (*flags & PI_FETCH_THREAD_SCHED0x0008) | |||
533 | { | |||
534 | thcount = THREAD_SCHED_INFO_COUNT(sizeof(thread_sched_info_data_t) / sizeof(natural_t)); | |||
535 | err = thread_info (thds[i], THREAD_SCHED_INFO2, | |||
536 | (thread_info_t) &pi->threadinfos[i].pis_si, | |||
537 | &thcount); | |||
538 | if (err == MACH_SEND_INVALID_DEST0x10000003) | |||
539 | { | |||
540 | pi->threadinfos[i].died = 1; | |||
541 | err = 0; | |||
542 | continue; | |||
543 | } | |||
544 | if (err) | |||
545 | /* Something screwy, give up on this bit of info. */ | |||
546 | { | |||
547 | *flags &= ~PI_FETCH_THREAD_SCHED0x0008; | |||
548 | err = 0; | |||
549 | } | |||
550 | } | |||
551 | ||||
552 | /* Note that there are thread wait entries only for those threads | |||
553 | not marked dead. */ | |||
554 | ||||
555 | if (*flags & PI_FETCH_THREAD_WAITS0x0010) | |||
556 | { | |||
557 | /* See what thread I is waiting on. */ | |||
558 | if (msgport == MACH_PORT_NULL((mach_port_t) 0)) | |||
559 | *flags &= ~PI_FETCH_THREAD_WAITS0x0010; /* Can't return much... */ | |||
560 | else | |||
561 | { | |||
562 | string_t desc; | |||
563 | size_t desc_len; | |||
564 | ||||
565 | if (msg_report_wait (msgport, thds[i], | |||
566 | desc, &pi->threadinfos[i].rpc_block)) | |||
567 | desc[0] = '\0'; /* Don't know. */ | |||
568 | ||||
569 | /* See how long DESC is, being sure not to barf if it's | |||
570 | unterminated (string_t's are fixed length). */ | |||
571 | desc_len = strnlen (desc, sizeof desc); | |||
572 | ||||
573 | if (waits_used + desc_len + 1 > *waits_len) | |||
574 | /* Not enough room in WAITS, we must allocate more. */ | |||
575 | { | |||
576 | char *new_waits = 0; | |||
577 | mach_msg_type_number_t new_len = | |||
578 | round_page (waits_used + desc_len + 1)((((vm_offset_t) (waits_used + desc_len + 1) + __vm_page_size - 1) / __vm_page_size) * __vm_page_size); | |||
579 | ||||
580 | new_waits = mmap (0, new_len, PROT_READ0x04|PROT_WRITE0x02, | |||
581 | MAP_ANON0x0002, 0, 0); | |||
582 | err = (new_waits == MAP_FAILED((void *) -1)) ? errno(*__errno_location ()) : 0; | |||
583 | if (err) | |||
584 | /* Just don't return any more waits information. */ | |||
585 | *flags &= ~PI_FETCH_THREAD_WAITS0x0010; | |||
586 | else | |||
587 | { | |||
588 | if (waits_used > 0) | |||
589 | memcpy (new_waits, *waits, waits_used); | |||
590 | if (*waits_len > 0 && waits_alloced) | |||
591 | munmap (*waits, *waits_len); | |||
592 | *waits = new_waits; | |||
593 | *waits_len = new_len; | |||
594 | waits_alloced = 1; | |||
595 | } | |||
596 | } | |||
597 | ||||
598 | if (waits_used + desc_len + 1 <= *waits_len) | |||
599 | /* Append DESC to WAITS. */ | |||
600 | { | |||
601 | memcpy (*waits + waits_used, desc, desc_len); | |||
602 | waits_used += desc_len; | |||
603 | (*waits)[waits_used++] = '\0'; | |||
604 | } | |||
605 | } | |||
606 | } | |||
607 | ||||
608 | mach_port_deallocate (mach_task_self ()((__mach_task_self_ + 0)), thds[i]); | |||
609 | } | |||
610 | ||||
611 | if (*flags & PI_FETCH_THREADS0x0002) | |||
612 | munmap (thds, nthreads * sizeof (thread_t)); | |||
| ||||
613 | if (err && pi_alloced) | |||
614 | munmap (*piarray, structsize); | |||
615 | if (err && waits_alloced) | |||
616 | munmap (*waits, *waits_len); | |||
617 | else | |||
618 | *waits_len = waits_used; | |||
619 | ||||
620 | /* Reacquire GLOBAL_LOCK to make the central locking code happy. */ | |||
621 | pthread_mutex_lock (&global_lock); | |||
622 | ||||
623 | return err; | |||
624 | } | |||
625 | ||||
626 | /* Implement proc_make_login_coll as described in <hurd/process.defs>. */ | |||
627 | kern_return_t | |||
628 | S_proc_make_login_coll (struct proc *p) | |||
629 | { | |||
630 | if (!p) | |||
631 | return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); | |||
632 | p->p_loginleader = 1; | |||
633 | return 0; | |||
634 | } | |||
635 | ||||
636 | /* Implement proc_getloginid as described in <hurd/process.defs>. */ | |||
637 | kern_return_t | |||
638 | S_proc_getloginid (struct proc *callerp, | |||
639 | pid_t pid, | |||
640 | pid_t *leader) | |||
641 | { | |||
642 | struct proc *proc = pid_find (pid); | |||
643 | struct proc *p; | |||
644 | ||||
645 | /* No need to check CALLERP here; we don't use it. */ | |||
646 | ||||
647 | if (!proc) | |||
648 | return ESRCH((0x10 << 26) | ((3) & 0x3fff)); | |||
649 | ||||
650 | for (p = proc; !p->p_loginleader; p = p->p_parent) | |||
651 | assert (p)((p) ? (void) (0) : __assert_fail ("p", "../../proc/info.c", 651 , __PRETTY_FUNCTION__)); | |||
652 | ||||
653 | *leader = p->p_pid; | |||
654 | return 0; | |||
655 | } | |||
656 | ||||
657 | /* Implement proc_getloginpids as described in <hurd/process.defs>. */ | |||
658 | kern_return_t | |||
659 | S_proc_getloginpids (struct proc *callerp, | |||
660 | pid_t id, | |||
661 | pid_t **pids, | |||
662 | size_t *npids) | |||
663 | { | |||
664 | error_t err = 0; | |||
665 | struct proc *l = pid_find (id); | |||
666 | struct proc *p; | |||
667 | struct proc **tail, **new, **parray; | |||
668 | int parraysize; | |||
669 | int i; | |||
670 | ||||
671 | /* No need to check CALLERP here; we don't use it. */ | |||
672 | ||||
673 | if (!l || !l->p_loginleader) | |||
674 | return ESRCH((0x10 << 26) | ((3) & 0x3fff)); | |||
675 | ||||
676 | /* Simple breadth first search of the children of L. */ | |||
677 | parraysize = 50; | |||
678 | parray = malloc (sizeof (struct proc *) * parraysize); | |||
679 | if (! parray) | |||
680 | return ENOMEM((0x10 << 26) | ((12) & 0x3fff)); | |||
681 | ||||
682 | parray[0] = l; | |||
683 | for (tail = parray, new = &parray[1]; tail != new; tail++) | |||
684 | { | |||
685 | for (p = (*tail)->p_ochild; p; p = p->p_sib) | |||
686 | if (!p->p_loginleader) | |||
687 | { | |||
688 | /* Add P to the list at NEW */ | |||
689 | if (new - parray > parraysize) | |||
690 | { | |||
691 | struct proc **newparray; | |||
692 | newparray = realloc (parray, ((parraysize *= 2) | |||
693 | * sizeof (struct proc *))); | |||
694 | if (! newparray) | |||
695 | { | |||
696 | free (parray); | |||
697 | return ENOMEM((0x10 << 26) | ((12) & 0x3fff)); | |||
698 | } | |||
699 | ||||
700 | tail = newparray + (tail - parray); | |||
701 | new = newparray + (new - parray); | |||
702 | parray = newparray; | |||
703 | } | |||
704 | *new++ = p; | |||
705 | } | |||
706 | } | |||
707 | ||||
708 | if (*npids < new - parray) | |||
709 | { | |||
710 | *pids = mmap (0, (new - parray) * sizeof (pid_t), PROT_READ0x04|PROT_WRITE0x02, | |||
711 | MAP_ANON0x0002, 0, 0); | |||
712 | if (*pids == MAP_FAILED((void *) -1)) | |||
713 | err = errno(*__errno_location ()); | |||
714 | } | |||
715 | ||||
716 | if (! err) | |||
717 | { | |||
718 | *npids = new - parray; | |||
719 | for (i = 0; i < *npids; i++) | |||
720 | (*pids)[i] = parray[i]->p_pid; | |||
721 | } | |||
722 | ||||
723 | free (parray); | |||
724 | return err; | |||
725 | } | |||
726 | ||||
727 | /* Implement proc_setlogin as described in <hurd/process.defs>. */ | |||
728 | kern_return_t | |||
729 | S_proc_setlogin (struct proc *p, | |||
730 | char *login) | |||
731 | { | |||
732 | struct login *l; | |||
733 | ||||
734 | if (!p) | |||
735 | return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); | |||
736 | ||||
737 | if (!check_uid (p, 0)) | |||
738 | return EPERM((0x10 << 26) | ((1) & 0x3fff)); | |||
739 | ||||
740 | l = malloc (sizeof (struct login) + strlen (login) + 1); | |||
741 | if (! l) | |||
742 | return ENOMEM((0x10 << 26) | ((12) & 0x3fff)); | |||
743 | ||||
744 | l->l_refcnt = 1; | |||
745 | strcpy (l->l_name, login); | |||
746 | if (!--p->p_login->l_refcnt) | |||
747 | free (p->p_login); | |||
748 | p->p_login = l; | |||
749 | return 0; | |||
750 | } | |||
751 | ||||
752 | /* Implement proc_getlogin as described in <hurd/process.defs>. */ | |||
753 | kern_return_t | |||
754 | S_proc_getlogin (struct proc *p, | |||
755 | char *login) | |||
756 | { | |||
757 | if (!p) | |||
758 | return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); | |||
759 | strcpy (login, p->p_login->l_name); | |||
760 | return 0; | |||
761 | } | |||
762 | ||||
763 | /* Implement proc_get_tty as described in <hurd/process.defs>. */ | |||
764 | kern_return_t | |||
765 | S_proc_get_tty (struct proc *p, pid_t pid, | |||
766 | mach_port_t *tty, mach_msg_type_name_t *tty_type) | |||
767 | { | |||
768 | return EOPNOTSUPP((0x10 << 26) | ((45) & 0x3fff)); /* XXX */ | |||
769 | } | |||
770 | ||||
771 | /* Implement proc_getnports as described in <hurd/process.defs>. */ | |||
772 | kern_return_t | |||
773 | S_proc_getnports (struct proc *callerp, | |||
774 | pid_t pid, | |||
775 | mach_msg_type_number_t *nports) | |||
776 | { | |||
777 | struct proc *p = pid_find (pid); | |||
778 | mach_port_array_t names; | |||
779 | mach_msg_type_number_t ncount; | |||
780 | mach_port_type_array_t types; | |||
781 | mach_msg_type_number_t tcount; | |||
782 | error_t err = 0; | |||
783 | ||||
784 | /* No need to check CALLERP here; we don't use it. */ | |||
785 | ||||
786 | if (!p) | |||
787 | return ESRCH((0x10 << 26) | ((3) & 0x3fff)); | |||
788 | ||||
789 | err = mach_port_names (p->p_task, &names, &ncount, &types, &tcount); | |||
790 | if (err == KERN_INVALID_TASK16) | |||
791 | err = ESRCH((0x10 << 26) | ((3) & 0x3fff)); | |||
792 | ||||
793 | if (!err) { | |||
794 | *nports = ncount; | |||
795 | ||||
796 | munmap (names, ncount * sizeof (mach_port_t)); | |||
797 | munmap (types, tcount * sizeof (mach_port_type_t)); | |||
798 | } | |||
799 | ||||
800 | return err; | |||
801 | } |