]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_proc.c
714f85f85fddd3b799793c1a5e9cf5974889c88d
[apple/xnu.git] / bsd / kern / kern_proc.c
1 /*
2 * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
24 /*
25 * Copyright (c) 1982, 1986, 1989, 1991, 1993
26 * The Regents of the University of California. All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. All advertising materials mentioning features or use of this software
37 * must display the following acknowledgement:
38 * This product includes software developed by the University of
39 * California, Berkeley and its contributors.
40 * 4. Neither the name of the University nor the names of its contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
55 *
56 * @(#)kern_proc.c 8.4 (Berkeley) 1/4/94
57 */
58 /* HISTORY
59 * 04-Aug-97 Umesh Vaishampayan (umeshv@apple.com)
60 * Added current_proc_EXTERNAL() function for the use of kernel
61 * lodable modules.
62 *
63 * 05-Jun-95 Mac Gillon (mgillon) at NeXT
64 * New version based on 3.3NS and 4.4
65 */
66
67
68 #include <sys/param.h>
69 #include <sys/systm.h>
70 #include <sys/kernel.h>
71 #include <sys/proc_internal.h>
72 #include <sys/acct.h>
73 #include <sys/wait.h>
74 #include <sys/file_internal.h>
75 #include <ufs/ufs/quota.h>
76 #include <sys/uio.h>
77 #include <sys/malloc.h>
78 #include <sys/mbuf.h>
79 #include <sys/ioctl.h>
80 #include <sys/tty.h>
81 #include <sys/signalvar.h>
82 #include <sys/syslog.h>
83 #include <sys/kernel_types.h>
84
85 /*
86 * Structure associated with user cacheing.
87 */
88 struct uidinfo {
89 LIST_ENTRY(uidinfo) ui_hash;
90 uid_t ui_uid;
91 long ui_proccnt;
92 };
93 #define UIHASH(uid) (&uihashtbl[(uid) & uihash])
94 LIST_HEAD(uihashhead, uidinfo) *uihashtbl;
95 u_long uihash; /* size of hash table - 1 */
96
97 /*
98 * Other process lists
99 */
100 struct pidhashhead *pidhashtbl;
101 u_long pidhash;
102 struct pgrphashhead *pgrphashtbl;
103 u_long pgrphash;
104 struct proclist allproc;
105 struct proclist zombproc;
106 extern struct tty cons;
107
108 /* Name to give to core files */
109 __private_extern__ char corefilename[MAXPATHLEN+1] = {"/cores/core.%P"};
110
111 static void orphanpg(struct pgrp *pg);
112
113 /*
114 * Initialize global process hashing structures.
115 */
116 void
117 procinit()
118 {
119
120 LIST_INIT(&allproc);
121 LIST_INIT(&zombproc);
122 pidhashtbl = hashinit(maxproc / 4, M_PROC, &pidhash);
123 pgrphashtbl = hashinit(maxproc / 4, M_PROC, &pgrphash);
124 uihashtbl = hashinit(maxproc / 16, M_PROC, &uihash);
125 }
126
127 /*
128 * Change the count associated with number of processes
129 * a given user is using.
130 */
131 int
132 chgproccnt(uid, diff)
133 uid_t uid;
134 int diff;
135 {
136 register struct uidinfo *uip;
137 register struct uihashhead *uipp;
138
139 uipp = UIHASH(uid);
140 for (uip = uipp->lh_first; uip != 0; uip = uip->ui_hash.le_next)
141 if (uip->ui_uid == uid)
142 break;
143 if (uip) {
144 uip->ui_proccnt += diff;
145 if (uip->ui_proccnt > 0)
146 return (uip->ui_proccnt);
147 if (uip->ui_proccnt < 0)
148 panic("chgproccnt: procs < 0");
149 LIST_REMOVE(uip, ui_hash);
150 FREE_ZONE(uip, sizeof *uip, M_PROC);
151 return (0);
152 }
153 if (diff <= 0) {
154 if (diff == 0)
155 return(0);
156 panic("chgproccnt: lost user");
157 }
158 MALLOC_ZONE(uip, struct uidinfo *, sizeof(*uip), M_PROC, M_WAITOK);
159 if (uip == NULL)
160 panic("chgproccnt: M_PROC zone depleted");
161 LIST_INSERT_HEAD(uipp, uip, ui_hash);
162 uip->ui_uid = uid;
163 uip->ui_proccnt = diff;
164 return (diff);
165 }
166
167 /*
168 * Is p an inferior of the current process?
169 */
170 int
171 inferior(p)
172 register struct proc *p;
173 {
174
175 for (; p != current_proc(); p = p->p_pptr)
176 if (p->p_pid == 0)
177 return (0);
178 return (1);
179 }
180 /*
181 * Is p an inferior of t ?
182 */
183 int
184 isinferior(struct proc *p, struct proc *t)
185 {
186
187 /* if p==t they are not inferior */
188 if (p == t)
189 return(0);
190 for (; p != t; p = p->p_pptr)
191 if (p->p_pid == 0)
192 return (0);
193 return (1);
194 }
195
196 int
197 proc_isinferior(int pid1, int pid2)
198 {
199 proc_t p;
200 proc_t t;
201
202 if (((p = pfind(pid1)) != (struct proc *)0 ) && ((t = pfind(pid2)) != (struct proc *)0))
203 return (isinferior(p, t));
204 return(0);
205 }
206
207 proc_t
208 proc_find(int pid)
209 {
210 return(pfind(pid));
211 }
212
213 int
214 proc_rele(__unused proc_t p)
215 {
216 return(0);
217 }
218
219 proc_t
220 proc_self()
221 {
222 return(current_proc());
223 }
224
225 proc_t
226 proc_findref(int pid)
227 {
228 boolean_t funnel_state;
229 proc_t p;
230
231 funnel_state = thread_funnel_set(kernel_flock,TRUE);
232 p = pfind(pid);
233
234 if (p != proc_refinternal(p, 1))
235 p = PROC_NULL;
236
237 thread_funnel_set(kernel_flock, funnel_state);
238 return(p);
239 }
240
241 void
242 proc_dropref(proc_t p)
243 {
244
245 proc_dropinternal(p, 0);
246 }
247
248
249 proc_t
250 proc_refinternal(proc_t p, int funneled)
251 {
252
253 proc_t p1 = p;
254 boolean_t funnel_state = TRUE; /* need to init just to avoid warnings and build failure */
255
256 if (funneled == 0)
257 funnel_state = thread_funnel_set(kernel_flock,TRUE);
258
259 if ((p != PROC_NULL) &&(p->p_stat != SZOMB) && ((p->p_lflag & (P_LREFDRAINWAIT | P_LREFDRAIN | P_LREFDEAD)) == 0))
260 p->p_internalref++;
261 else
262 p1 = PROC_NULL;
263
264 if (funneled == 0)
265 thread_funnel_set(kernel_flock,funnel_state);
266 return(p1);
267 }
268
269 void
270 proc_dropinternal(proc_t p, int funneled)
271 {
272 boolean_t funnel_state = TRUE; /* need to init just to avoid warnings and build failure */
273
274 if (funneled == 0)
275 funnel_state = thread_funnel_set(kernel_flock,TRUE);
276
277 if (p->p_internalref > 0) {
278 p->p_internalref--;
279 if ((p->p_internalref == 0) && ((p->p_lflag & P_LREFDRAINWAIT) == P_LREFDRAINWAIT)) {
280 p->p_lflag &= ~P_LREFDRAINWAIT;
281 wakeup(&p->p_internalref);
282 }
283 } else
284 printf("proc_dropreg -ve ref\n");
285
286 if (funneled == 0)
287 thread_funnel_set(kernel_flock,funnel_state);
288 }
289
290
291 int
292 proc_pid(proc_t p)
293 {
294 return(p->p_pid);
295 }
296
297 int
298 proc_ppid(proc_t p)
299 {
300 if (p->p_pptr != (struct proc *)0)
301 return(p->p_pptr->p_pid);
302 return(0);
303 }
304
305 int
306 proc_selfpid(void)
307 {
308 struct proc *p = current_proc();
309 return(p->p_pid);
310 }
311
312
313 int
314 proc_selfppid(void)
315 {
316 struct proc *p = current_proc();
317 if (p->p_pptr)
318 return(p->p_pptr->p_pid);
319 else
320 return(0);
321 }
322
323 void
324 proc_name(int pid, char * buf, int size)
325 {
326 struct proc *p;
327
328 if ((p = pfind(pid))!= (struct proc *)0) {
329 strncpy(buf, &p->p_comm[0], size);
330 buf[size-1] = 0;
331 }
332 }
333
334 void
335 proc_selfname(char * buf, int size)
336 {
337 struct proc *p;
338
339 if ((p = current_proc())!= (struct proc *)0) {
340 strncpy(buf, &p->p_comm[0], size);
341 buf[size-1] = 0;
342 }
343 }
344
345 void
346 proc_signal(int pid, int signum)
347 {
348 proc_t p;
349
350 if ((p = pfind(pid))!= (struct proc *)0) {
351 psignal(p, signum);
352 }
353 }
354
355 int
356 proc_issignal(int pid, sigset_t mask)
357 {
358 proc_t p;
359
360 if ((p = pfind(pid))!= (struct proc *)0) {
361 return(proc_pendingsignals(p, mask));
362 }
363 return(0);
364 }
365
366 int
367 proc_noremotehang(proc_t p)
368 {
369 int retval = 0;
370
371 if (p)
372 retval = p->p_flag & P_NOREMOTEHANG;
373 return(retval? 1: 0);
374
375 }
376
377 int
378 proc_exiting(proc_t p)
379 {
380 int retval = 0;
381
382 if (p)
383 retval = p->p_flag & P_WEXIT;
384 return(retval? 1: 0);
385 }
386
387
388 int
389 proc_forcequota(proc_t p)
390 {
391 int retval = 0;
392
393 if (p)
394 retval = p->p_flag & P_FORCEQUOTA;
395 return(retval? 1: 0);
396
397 }
398
399 int
400 proc_tbe(proc_t p)
401 {
402 int retval = 0;
403
404 if (p)
405 retval = p->p_flag & P_TBE;
406 return(retval? 1: 0);
407
408 }
409
410 int
411 proc_suser(proc_t p)
412 {
413 return(suser(p->p_ucred, NULL));
414
415 }
416
417 kauth_cred_t
418 proc_ucred(proc_t p)
419 {
420 return(p->p_ucred);
421 }
422
423
424 int
425 proc_is64bit(proc_t p)
426 {
427 return(IS_64BIT_PROCESS(p));
428 }
429
430 /* LP64todo - figure out how to identify 64-bit processes if NULL procp */
431 int
432 IS_64BIT_PROCESS(proc_t p)
433 {
434 if (p && (p->p_flag & P_LP64))
435 return(1);
436 else
437 return(0);
438 }
439
440
441 /*
442 * Locate a process by number
443 */
444 struct proc *
445 pfind(pid)
446 register pid_t pid;
447 {
448 register struct proc *p;
449
450 if (!pid)
451 return (kernproc);
452
453 for (p = PIDHASH(pid)->lh_first; p != 0; p = p->p_hash.le_next)
454 if (p->p_pid == pid)
455 return (p);
456 return (NULL);
457 }
458
459 /*
460 * Locate a zombie by PID
461 */
462 __private_extern__ struct proc *
463 pzfind(pid)
464 register pid_t pid;
465 {
466 register struct proc *p;
467
468 for (p = zombproc.lh_first; p != 0; p = p->p_list.le_next)
469 if (p->p_pid == pid)
470 return (p);
471 return (NULL);
472 }
473
474 /*
475 * Locate a process group by number
476 */
477 struct pgrp *
478 pgfind(pgid)
479 register pid_t pgid;
480 {
481 register struct pgrp *pgrp;
482
483 for (pgrp = PGRPHASH(pgid)->lh_first; pgrp != 0; pgrp = pgrp->pg_hash.le_next)
484 if (pgrp->pg_id == pgid)
485 return (pgrp);
486 return (NULL);
487 }
488
489
490 /*
491 * Move p to a new or existing process group (and session)
492 */
493 int
494 enterpgrp(p, pgid, mksess)
495 register struct proc *p;
496 pid_t pgid;
497 int mksess;
498 {
499 register struct pgrp *pgrp = pgfind(pgid);
500
501 #if DIAGNOSTIC
502 if (pgrp != NULL && mksess) /* firewalls */
503 panic("enterpgrp: setsid into non-empty pgrp");
504 if (SESS_LEADER(p))
505 panic("enterpgrp: session leader attempted setpgrp");
506 #endif
507 if (pgrp == NULL) {
508 pid_t savepid = p->p_pid;
509 struct proc *np;
510 /*
511 * new process group
512 */
513 #if DIAGNOSTIC
514 if (p->p_pid != pgid)
515 panic("enterpgrp: new pgrp and pid != pgid");
516 #endif
517 MALLOC_ZONE(pgrp, struct pgrp *, sizeof(struct pgrp), M_PGRP,
518 M_WAITOK);
519 if (pgrp == NULL)
520 panic("enterpgrp: M_PGRP zone depleted");
521 if ((np = pfind(savepid)) == NULL || np != p) {
522 FREE_ZONE(pgrp, sizeof(struct pgrp), M_PGRP);
523 return (ESRCH);
524 }
525 if (mksess) {
526 register struct session *sess;
527
528 /*
529 * new session
530 */
531 MALLOC_ZONE(sess, struct session *,
532 sizeof(struct session), M_SESSION, M_WAITOK);
533 if (sess == NULL)
534 panic("enterpgrp: M_SESSION zone depleted");
535 sess->s_leader = p;
536 sess->s_sid = p->p_pid;
537 sess->s_count = 1;
538 sess->s_ttyvp = NULL;
539 sess->s_ttyp = NULL;
540 bcopy(p->p_session->s_login, sess->s_login,
541 sizeof(sess->s_login));
542 p->p_flag &= ~P_CONTROLT;
543 pgrp->pg_session = sess;
544 #if DIAGNOSTIC
545 if (p != current_proc())
546 panic("enterpgrp: mksession and p != curproc");
547 #endif
548 } else {
549 pgrp->pg_session = p->p_session;
550 pgrp->pg_session->s_count++;
551 }
552 pgrp->pg_id = pgid;
553 LIST_INIT(&pgrp->pg_members);
554 LIST_INSERT_HEAD(PGRPHASH(pgid), pgrp, pg_hash);
555 pgrp->pg_jobc = 0;
556 } else if (pgrp == p->p_pgrp)
557 return (0);
558
559 /*
560 * Adjust eligibility of affected pgrps to participate in job control.
561 * Increment eligibility counts before decrementing, otherwise we
562 * could reach 0 spuriously during the first call.
563 */
564 fixjobc(p, pgrp, 1);
565 fixjobc(p, p->p_pgrp, 0);
566
567 LIST_REMOVE(p, p_pglist);
568 if (p->p_pgrp->pg_members.lh_first == 0)
569 pgdelete(p->p_pgrp);
570 p->p_pgrp = pgrp;
571 LIST_INSERT_HEAD(&pgrp->pg_members, p, p_pglist);
572 return (0);
573 }
574
575 /*
576 * remove process from process group
577 */
578 int
579 leavepgrp(p)
580 register struct proc *p;
581 {
582
583 LIST_REMOVE(p, p_pglist);
584 if (p->p_pgrp->pg_members.lh_first == 0)
585 pgdelete(p->p_pgrp);
586 p->p_pgrp = 0;
587 return (0);
588 }
589
590 /*
591 * delete a process group
592 */
593 void
594 pgdelete(pgrp)
595 register struct pgrp *pgrp;
596 {
597 struct tty * ttyp;
598 int removettypgrp = 0;
599
600 ttyp = pgrp->pg_session->s_ttyp;
601 if (pgrp->pg_session->s_ttyp != NULL &&
602 pgrp->pg_session->s_ttyp->t_pgrp == pgrp) {
603 pgrp->pg_session->s_ttyp->t_pgrp = NULL;
604 removettypgrp = 1;
605 }
606 LIST_REMOVE(pgrp, pg_hash);
607 if (--pgrp->pg_session->s_count == 0) {
608 if (removettypgrp && (ttyp == &cons) && (ttyp->t_session == pgrp->pg_session))
609 ttyp->t_session = 0;
610 FREE_ZONE(pgrp->pg_session, sizeof(struct session), M_SESSION);
611 }
612 FREE_ZONE(pgrp, sizeof *pgrp, M_PGRP);
613 }
614
615 void
616 sessrele(sess)
617 struct session *sess;
618 {
619 if (--sess->s_count == 0)
620 FREE_ZONE(sess, sizeof (struct session), M_SESSION);
621 }
622
623 /*
624 * Adjust pgrp jobc counters when specified process changes process group.
625 * We count the number of processes in each process group that "qualify"
626 * the group for terminal job control (those with a parent in a different
627 * process group of the same session). If that count reaches zero, the
628 * process group becomes orphaned. Check both the specified process'
629 * process group and that of its children.
630 * entering == 0 => p is leaving specified group.
631 * entering == 1 => p is entering specified group.
632 */
633 void
634 fixjobc(struct proc *p, struct pgrp *pgrp, int entering)
635 {
636 register struct pgrp *hispgrp;
637 register struct session *mysession = pgrp->pg_session;
638
639 /*
640 * Check p's parent to see whether p qualifies its own process
641 * group; if so, adjust count for p's process group.
642 */
643 if ((hispgrp = p->p_pptr->p_pgrp) != pgrp &&
644 hispgrp->pg_session == mysession) {
645 if (entering)
646 pgrp->pg_jobc++;
647 else if (--pgrp->pg_jobc == 0)
648 orphanpg(pgrp);
649 }
650
651 /*
652 * Check this process' children to see whether they qualify
653 * their process groups; if so, adjust counts for children's
654 * process groups.
655 */
656 for (p = p->p_children.lh_first; p != 0; p = p->p_sibling.le_next)
657 if ((hispgrp = p->p_pgrp) != pgrp &&
658 hispgrp->pg_session == mysession &&
659 p->p_stat != SZOMB) {
660 if (entering)
661 hispgrp->pg_jobc++;
662 else if (--hispgrp->pg_jobc == 0)
663 orphanpg(hispgrp);
664 }
665 }
666
667 /*
668 * A process group has become orphaned;
669 * if there are any stopped processes in the group,
670 * hang-up all process in that group.
671 */
672 static void
673 orphanpg(struct pgrp *pg)
674 {
675 register struct proc *p;
676
677 for (p = pg->pg_members.lh_first; p != 0; p = p->p_pglist.le_next) {
678 if (p->p_stat == SSTOP) {
679 for (p = pg->pg_members.lh_first; p != 0;
680 p = p->p_pglist.le_next) {
681 pt_setrunnable(p);
682 psignal(p, SIGHUP);
683 psignal(p, SIGCONT);
684 }
685 return;
686 }
687 }
688 }
689
690 #ifdef DEBUG
691 void pgrpdump(void); /* forward declare here (called from debugger) */
692
693 void
694 pgrpdump(void)
695 {
696 struct pgrp *pgrp;
697 struct proc *p;
698 u_long i;
699
700 for (i = 0; i <= pgrphash; i++) {
701 if ((pgrp = pgrphashtbl[i].lh_first) != NULL) {
702 printf("\tindx %d\n", i);
703 for (; pgrp != 0; pgrp = pgrp->pg_hash.le_next) {
704 printf("\tpgrp 0x%08x, pgid %d, sess %p, sesscnt %d, mem %p\n",
705 pgrp, pgrp->pg_id, pgrp->pg_session,
706 pgrp->pg_session->s_count,
707 pgrp->pg_members.lh_first);
708 for (p = pgrp->pg_members.lh_first; p != 0;
709 p = p->p_pglist.le_next) {
710 printf("\t\tpid %d addr 0x%08x pgrp 0x%08x\n",
711 p->p_pid, p, p->p_pgrp);
712 }
713 }
714 }
715 }
716 }
717 #endif /* DEBUG */
718
719 /* XXX should be __private_extern__ */
720 int
721 proc_is_classic(struct proc *p)
722 {
723 return (p->p_flag & P_CLASSIC) ? 1 : 0;
724 }
725
726 /* XXX Why does this function exist? Need to kill it off... */
727 struct proc *
728 current_proc_EXTERNAL(void)
729 {
730 return (current_proc());
731 }
732
733 /*
734 * proc_core_name(name, uid, pid)
735 * Expand the name described in corefilename, using name, uid, and pid.
736 * corefilename is a printf-like string, with three format specifiers:
737 * %N name of process ("name")
738 * %P process id (pid)
739 * %U user id (uid)
740 * For example, "%N.core" is the default; they can be disabled completely
741 * by using "/dev/null", or all core files can be stored in "/cores/%U/%N-%P".
742 * This is controlled by the sysctl variable kern.corefile (see above).
743 */
744 __private_extern__ char *
745 proc_core_name(const char *name, uid_t uid, pid_t pid)
746 {
747 const char *format, *appendstr;
748 char *temp;
749 char id_buf[11]; /* Buffer for pid/uid -- max 4B */
750 size_t i, l, n;
751
752 format = corefilename;
753 MALLOC(temp, char *, MAXPATHLEN, M_TEMP, M_NOWAIT | M_ZERO);
754 if (temp == NULL)
755 return (NULL);
756 for (i = 0, n = 0; n < MAXPATHLEN && format[i]; i++) {
757 switch (format[i]) {
758 case '%': /* Format character */
759 i++;
760 switch (format[i]) {
761 case '%':
762 appendstr = "%";
763 break;
764 case 'N': /* process name */
765 appendstr = name;
766 break;
767 case 'P': /* process id */
768 sprintf(id_buf, "%u", pid);
769 appendstr = id_buf;
770 break;
771 case 'U': /* user id */
772 sprintf(id_buf, "%u", uid);
773 appendstr = id_buf;
774 break;
775 default:
776 appendstr = "";
777 log(LOG_ERR,
778 "Unknown format character %c in `%s'\n",
779 format[i], format);
780 }
781 l = strlen(appendstr);
782 if ((n + l) >= MAXPATHLEN)
783 goto toolong;
784 bcopy(appendstr, temp + n, l);
785 n += l;
786 break;
787 default:
788 temp[n++] = format[i];
789 }
790 }
791 if (format[i] != '\0')
792 goto toolong;
793 return (temp);
794 toolong:
795 log(LOG_ERR, "pid %ld (%s), uid (%lu): corename is too long\n",
796 (long)pid, name, (u_long)uid);
797 FREE(temp, M_TEMP);
798 return (NULL);
799 }