Bug Summary

File:obj-scan-build/proc/../../proc/info.c
Location:line 612, column 5
Description:Function call argument is an uninitialized value

Annotated Source Code

1/* Process information queries
2 Copyright (C) 1992,93,94,95,96,99,2000,01,02 Free Software Foundation, Inc.
3
4This file is part of the GNU Hurd.
5
6The GNU Hurd is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11The GNU Hurd is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with the GNU Hurd; see the file COPYING. If not, write to
18the 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. */
40int
41check_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>. */
51kern_return_t
52S_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>. */
81kern_return_t
82S_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>. */
99kern_return_t
100S_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>. */
117kern_return_t
118S_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>. */
128kern_return_t
129S_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. */
158static error_t
159get_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. */
204static error_t
205get_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. */
258static error_t
259get_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>. */
331kern_return_t
332S_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>. */
348kern_return_t
349S_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>. */
369kern_return_t
370S_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;
1
Variable 'thds' declared without an initial value
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)
2
Assuming 'p' is non-null
3
Taking false branch
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))
4
Taking false branch
403 *flags |= PI_FETCH_THREADS0x0002;
404
405 if (*flags & PI_FETCH_THREADS0x0002)
5
Taking false branch
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))
6
Taking false branch
418 structsize += nthreads * sizeof (pi->threadinfos[0]);
419
420 if (structsize / sizeof (int) > *piarraylen)
7
Taking false branch
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)
8
'?' condition is false
441 | (p->p_exec ? PI_EXECED0x00000002 : 0)
9
'?' condition is false
442 | (p->p_waiting ? PI_WAITING0x00000004 : 0)
10
'?' condition is false
443 | (!p->p_pgrp->pg_orphcnt ? PI_ORPHAN0x00000008 : 0)
11
'?' condition is false
444 | (p->p_msgport == MACH_PORT_NULL((mach_port_t) 0) ? PI_NOMSG0x00000010 : 0)
12
'?' condition is false
445 | (p->p_pgrp->pg_session->s_sid == p->p_pid ? PI_SESSLD0x00000020 : 0)
13
'?' condition is false
446 | (p->p_noowner ? PI_NOTOWNED0x0000040 : 0)
14
'?' condition is false
447 | (!p->p_parentset ? PI_NOPARENT0x0000080 : 0)
15
'?' condition is false
448 | (p->p_traced ? PI_TRACED0x00000200 : 0)
16
'?' condition is false
449 | (p->p_msgportwait ? PI_GETMSG0x00000400 : 0)
17
'?' condition is false
450 | (p->p_loginleader ? PI_LOGINLD0x00000800 : 0));
18
'?' condition is true
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)
19
Loop condition is false. Execution continues on line 457
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)
20
Taking false branch
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)
21
Taking true branch
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)
22
Assuming 'err' is not equal to 268435459
23
Taking false branch
499 err = ESRCH((0x10 << 26) | ((3) & 0x3fff));
500 if (err)
24
Assuming 'err' is not equal to 0
25
Taking true branch
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++)
26
Loop condition is false. Execution continues on line 611
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)
27
Taking true branch
612 munmap (thds, nthreads * sizeof (thread_t));
28
Function call argument is an uninitialized value
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>. */
627kern_return_t
628S_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>. */
637kern_return_t
638S_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>. */
658kern_return_t
659S_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>. */
728kern_return_t
729S_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>. */
753kern_return_t
754S_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>. */
764kern_return_t
765S_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>. */
772kern_return_t
773S_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}