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