2 * Copyright (c) 2003 Kip Macy
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/types.h>
28 #include <sys/param.h>
30 #include <sys/module.h>
31 #include <sys/sysent.h>
32 #include <sys/kernel.h>
33 #include <sys/systm.h>
34 #include <sys/nlookup.h>
37 #include <sys/fcntl.h>
38 #include <sys/signal.h>
39 #include <vm/vm_param.h>
41 #include <sys/imgact_elf.h>
42 #include <sys/procfs.h>
46 #include <vm/vm_map.h>
47 #include <vm/vm_extern.h>
49 #include <sys/sysmsg.h>
50 #include <sys/resource.h>
51 #include <sys/resourcevar.h>
52 #include <sys/malloc.h>
55 #include <sys/vnode.h>
56 #include <machine/inttypes.h>
57 #include <machine/limits.h>
58 #include <machine/frame.h>
59 #include <sys/signalvar.h>
60 #include <sys/syslog.h>
61 #include <sys/sysctl.h>
62 #include <machine/sigframe.h>
64 #include <sys/unistd.h>
66 #include <sys/kern_syscall.h>
67 #include <sys/checkpoint.h>
68 #include <sys/mount.h>
71 #include <sys/mplock2.h>
72 #include <sys/file2.h>
74 static int elf_loadphdrs(struct file
*fp
, Elf_Phdr
*phdr
, int numsegs
);
75 static int elf_getnotes(struct lwp
*lp
, struct file
*fp
, size_t notesz
);
76 static int elf_demarshalnotes(void *src
, prpsinfo_t
*psinfo
,
77 prstatus_t
*status
, prfpregset_t
*fpregset
, int nthreads
);
78 static int elf_loadnotes(struct lwp
*, prpsinfo_t
*, prstatus_t
*,
80 static int elf_getsigs(struct lwp
*lp
, struct file
*fp
);
81 static int elf_getfiles(struct lwp
*lp
, struct file
*fp
);
82 static int elf_gettextvp(struct proc
*p
, struct file
*fp
);
83 static char *ckpt_expand_name(const char *name
, uid_t uid
, pid_t pid
);
85 static int ckptgroup
= 0; /* wheel only, -1 for any group */
86 SYSCTL_INT(_kern
, OID_AUTO
, ckptgroup
, CTLFLAG_RW
, &ckptgroup
, 0, "");
88 /* ref count to see how many processes that are being checkpointed */
89 static int chptinuse
= 0;
93 read_check(struct file
*fp
, void *buf
, size_t nbyte
)
98 PRINTF(("reading %zd bytes\n", nbyte
));
99 error
= fp_read(fp
, buf
, nbyte
, &nread
, 1, UIO_SYSSPACE
);
101 PRINTF(("read failed - %d", error
));
102 } else if (nread
!= nbyte
) {
103 PRINTF(("wanted to read %zd - read %zd\n", nbyte
, nread
));
110 elf_gethdr(struct file
*fp
, Elf_Ehdr
*ehdr
)
112 size_t nbyte
= sizeof(Elf_Ehdr
);
115 if ((error
= read_check(fp
, ehdr
, nbyte
)) != 0)
117 if (!(ehdr
->e_ehsize
== sizeof(Elf_Ehdr
))) {
118 PRINTF(("wrong elf header size: %d\n"
119 "expected size : %zd\n",
120 ehdr
->e_ehsize
, sizeof(Elf_Ehdr
)));
123 if (!(ehdr
->e_phentsize
== sizeof(Elf_Phdr
))) {
124 PRINTF(("wrong program header size: %d\n"
125 "expected size : %zd\n",
126 ehdr
->e_phentsize
, sizeof(Elf_Phdr
)));
130 if (!(ehdr
->e_ident
[EI_MAG0
] == ELFMAG0
&&
131 ehdr
->e_ident
[EI_MAG1
] == ELFMAG1
&&
132 ehdr
->e_ident
[EI_MAG2
] == ELFMAG2
&&
133 ehdr
->e_ident
[EI_MAG3
] == ELFMAG3
&&
134 ehdr
->e_ident
[EI_CLASS
] == ELF_CLASS
&&
135 ehdr
->e_ident
[EI_DATA
] == ELF_DATA
&&
136 ehdr
->e_ident
[EI_VERSION
] == EV_CURRENT
&&
137 ehdr
->e_ident
[EI_OSABI
] == ELFOSABI_NONE
&&
138 ehdr
->e_ident
[EI_ABIVERSION
] == 0)) {
139 PRINTF(("bad elf header\n there are %d segments\n",
144 PRINTF(("Elf header size: %d\n", ehdr
->e_ehsize
));
145 PRINTF(("Program header size: %d\n", ehdr
->e_phentsize
));
146 PRINTF(("Number of Program headers: %d\n", ehdr
->e_phnum
));
152 elf_getphdrs(struct file
*fp
, Elf_Phdr
*phdr
, size_t nbyte
)
156 int nheaders
= nbyte
/sizeof(Elf_Phdr
);
158 PRINTF(("reading phdrs section\n"));
159 if ((error
= read_check(fp
, phdr
, nbyte
)) != 0)
161 PRINTF(("headers section:\n"));
162 for (i
= 0; i
< nheaders
; i
++) {
163 PRINTF(("entry type: %d\n", phdr
[i
].p_type
));
164 PRINTF(("file offset: %jd\n", (intmax_t)phdr
[i
].p_offset
));
165 PRINTF(("virt address: %p\n", (uint32_t *)phdr
[i
].p_vaddr
));
166 PRINTF(("file size: %jd\n", (intmax_t)phdr
[i
].p_filesz
));
167 PRINTF(("memory size: %jd\n", (intmax_t)phdr
[i
].p_memsz
));
176 elf_getnotes(struct lwp
*lp
, struct file
*fp
, size_t notesz
)
183 prfpregset_t
*fpregset
;
185 nthreads
= (notesz
- sizeof(prpsinfo_t
))/(sizeof(prstatus_t
) +
186 sizeof(prfpregset_t
));
187 PRINTF(("reading notes header nthreads=%d\n", nthreads
));
188 if (nthreads
<= 0 || nthreads
> CKPT_MAXTHREADS
)
191 psinfo
= kmalloc(sizeof(prpsinfo_t
), M_TEMP
, M_ZERO
| M_WAITOK
);
192 status
= kmalloc(nthreads
*sizeof(prstatus_t
), M_TEMP
, M_WAITOK
);
193 fpregset
= kmalloc(nthreads
*sizeof(prfpregset_t
), M_TEMP
, M_WAITOK
);
194 note
= kmalloc(notesz
, M_TEMP
, M_WAITOK
);
197 PRINTF(("reading notes section\n"));
198 if ((error
= read_check(fp
, note
, notesz
)) != 0)
200 error
= elf_demarshalnotes(note
, psinfo
, status
, fpregset
, nthreads
);
203 /* fetch register state from notes */
204 error
= elf_loadnotes(lp
, psinfo
, status
, fpregset
);
207 kfree(psinfo
, M_TEMP
);
209 kfree(status
, M_TEMP
);
211 kfree(fpregset
, M_TEMP
);
218 ckpt_thaw_proc(struct lwp
*lp
, struct file
*fp
)
220 struct proc
*p
= lp
->lwp_proc
;
221 Elf_Phdr
*phdr
= NULL
;
222 Elf_Ehdr
*ehdr
= NULL
;
228 ehdr
= kmalloc(sizeof(Elf_Ehdr
), M_TEMP
, M_ZERO
| M_WAITOK
);
230 if ((error
= elf_gethdr(fp
, ehdr
)) != 0)
232 nbyte
= sizeof(Elf_Phdr
) * ehdr
->e_phnum
;
233 phdr
= kmalloc(nbyte
, M_TEMP
, M_WAITOK
);
235 /* fetch description of program writable mappings */
236 if ((error
= elf_getphdrs(fp
, phdr
, nbyte
)) != 0)
239 /* fetch notes section containing register state */
240 if ((error
= elf_getnotes(lp
, fp
, phdr
->p_filesz
)) != 0)
243 /* fetch program text vnodes */
244 if ((error
= elf_gettextvp(p
, fp
)) != 0)
247 /* fetch signal disposition */
248 if ((error
= elf_getsigs(lp
, fp
)) != 0) {
249 kprintf("failure in recovering signals\n");
253 /* fetch open files */
254 if ((error
= elf_getfiles(lp
, fp
)) != 0)
257 /* handle mappings last in case we are reading from a socket */
258 error
= elf_loadphdrs(fp
, phdr
, ehdr
->e_phnum
);
261 * Set the textvp to the checkpoint file and mark the vnode so
262 * a future checkpointing of this checkpoint-restored program
263 * will copy out the contents of the mappings rather then trying
264 * to record the vnode info related to the checkpoint file, which
265 * is likely going to be destroyed when the program is re-checkpointed.
267 if (error
== 0 && fp
->f_data
&& fp
->f_type
== DTYPE_VNODE
) {
270 p
->p_textvp
= (struct vnode
*)fp
->f_data
;
271 vsetflags(p
->p_textvp
, VCKPT
);
284 elf_loadnotes(struct lwp
*lp
, prpsinfo_t
*psinfo
, prstatus_t
*status
,
285 prfpregset_t
*fpregset
)
287 struct proc
*p
= lp
->lwp_proc
;
290 /* validate status and psinfo */
292 if (status
->pr_version
!= PRSTATUS_VERSION
||
293 status
->pr_statussz
!= sizeof(prstatus_t
) ||
294 status
->pr_gregsetsz
!= sizeof(gregset_t
) ||
295 status
->pr_fpregsetsz
!= sizeof(fpregset_t
) ||
296 psinfo
->pr_version
!= PRPSINFO_VERSION
||
297 psinfo
->pr_psinfosz
!= sizeof(prpsinfo_t
)) {
298 PRINTF(("status check failed\n"));
302 /* XXX lwp handle more than one lwp*/
303 if ((error
= set_regs(lp
, &status
->pr_reg
)) != 0)
305 error
= set_fpregs(lp
, fpregset
);
306 strlcpy(p
->p_comm
, psinfo
->pr_fname
, sizeof(p
->p_comm
));
307 /* XXX psinfo->pr_psargs not yet implemented */
314 elf_getnote(void *src
, size_t *off
, const char *name
, unsigned int type
,
315 void **desc
, size_t descsz
)
325 bcopy((char *)src
+ *off
, ¬e
, sizeof note
);
327 PRINTF(("at offset: %zd expected note of type: %d - got: %d\n",
328 *off
, type
, note
.n_type
));
330 if (type
!= note
.n_type
) {
335 if (strncmp(name
, (char *) src
+ *off
, note
.n_namesz
) != 0) {
339 *off
+= roundup2(note
.n_namesz
, sizeof(Elf_Size
));
340 if (note
.n_descsz
!= descsz
) {
346 bcopy((char *)src
+ *off
, *desc
, note
.n_descsz
);
347 *off
+= roundup2(note
.n_descsz
, sizeof(Elf_Size
));
355 elf_demarshalnotes(void *src
, prpsinfo_t
*psinfo
, prstatus_t
*status
,
356 prfpregset_t
*fpregset
, int nthreads
)
363 error
= elf_getnote(src
, &off
, "CORE", NT_PRPSINFO
,
364 (void **)&psinfo
, sizeof(prpsinfo_t
));
367 error
= elf_getnote(src
, &off
, "CORE", NT_PRSTATUS
,
368 (void **)&status
, sizeof(prstatus_t
));
371 error
= elf_getnote(src
, &off
, "CORE", NT_FPREGSET
,
372 (void **)&fpregset
, sizeof(prfpregset_t
));
377 * The remaining portion needs to be an integer multiple
378 * of prstatus_t and prfpregset_t
380 for (i
= 0 ; i
< nthreads
- 1; i
++) {
381 status
++; fpregset
++;
382 error
= elf_getnote(src
, &off
, "CORE", NT_PRSTATUS
,
383 (void **)&status
, sizeof (prstatus_t
));
386 error
= elf_getnote(src
, &off
, "CORE", NT_FPREGSET
,
387 (void **)&fpregset
, sizeof(prfpregset_t
));
399 mmap_phdr(struct file
*fp
, Elf_Phdr
*phdr
)
409 pos
= phdr
->p_offset
;
410 len
= phdr
->p_filesz
;
411 addr
= (void *)phdr
->p_vaddr
;
412 flags
= MAP_FIXED
| MAP_NOSYNC
| MAP_PRIVATE
;
414 if (phdr
->p_flags
& PF_R
)
416 if (phdr
->p_flags
& PF_W
)
418 if (phdr
->p_flags
& PF_X
)
420 if ((error
= fp_mmap(addr
, len
, prot
, flags
, fp
, pos
, &addr
)) != 0) {
421 PRINTF(("mmap failed: %d\n", error
); );
423 PRINTF(("map @%08"PRIxPTR
"-%08"PRIxPTR
" fileoff %08x-%08x\n", (uintptr_t)addr
,
424 (uintptr_t)((char *)addr
+ len
), (int)pos
, (int)(pos
+ len
)));
430 * Load memory mapped segments. The segments are backed by the checkpoint
434 elf_loadphdrs(struct file
*fp
, Elf_Phdr
*phdr
, int numsegs
)
440 for (i
= 1; i
< numsegs
; i
++) {
441 if ((error
= mmap_phdr(fp
, &phdr
[i
])) != 0)
449 elf_getsigs(struct lwp
*lp
, struct file
*fp
)
451 struct proc
*p
= lp
->lwp_proc
;
453 struct ckpt_siginfo
*csi
;
456 csi
= kmalloc(sizeof(struct ckpt_siginfo
), M_TEMP
, M_ZERO
| M_WAITOK
);
457 if ((error
= read_check(fp
, csi
, sizeof(struct ckpt_siginfo
))) != 0)
460 if (csi
->csi_ckptpisz
!= sizeof(struct ckpt_siginfo
)) {
465 bcopy(&csi
->csi_sigacts
, p
->p_sigacts
, sizeof(struct sigacts
));
466 bcopy(&csi
->csi_itimerval
, &p
->p_realtimer
, sizeof(struct itimerval
));
467 SIG_CANTMASK(csi
->csi_sigmask
);
468 /* XXX lwp handle more than one lwp */
469 bcopy(&csi
->csi_sigmask
, &lp
->lwp_sigmask
, sizeof(sigset_t
));
470 p
->p_sigparent
= csi
->csi_sigparent
;
479 * Returns a locked, refd vnode
482 ckpt_fhtovp(fhandle_t
*fh
, struct vnode
**vpp
)
488 mp
= vfs_getvfs(&fh
->fh_fsid
);
492 PRINTF(("failed to get mount - ESTALE\n"));
496 error
= VFS_FHTOVP(mp
, NULL
, &fh
->fh_fid
, vpp
);
499 PRINTF(("failed with: %d\n", error
));
507 mmap_vp(struct vn_hdr
*vnh
)
515 phdr
= &vnh
->vnh_phdr
;
517 if ((error
= ckpt_fhtovp(&vnh
->vnh_fh
, &vp
)) != 0)
520 * XXX O_RDONLY -> or O_RDWR if file is PROT_WRITE, MAP_SHARED
522 if ((error
= fp_vpopen(vp
, O_RDONLY
, &fp
)) != 0) {
526 error
= mmap_phdr(fp
, phdr
);
534 elf_gettextvp(struct proc
*p
, struct file
*fp
)
539 struct ckpt_vminfo vminfo
;
540 struct vn_hdr
*vnh
= NULL
;
543 if ((error
= read_check(fp
, &vminfo
, sizeof(vminfo
))) != 0)
545 if (vminfo
.cvm_dsize
< 0 ||
546 vminfo
.cvm_dsize
> p
->p_rlimit
[RLIMIT_DATA
].rlim_cur
||
547 vminfo
.cvm_tsize
< 0 ||
548 (u_quad_t
)vminfo
.cvm_tsize
> maxtsiz
||
549 vminfo
.cvm_daddr
>= (caddr_t
)VM_MAX_USER_ADDRESS
||
550 vminfo
.cvm_taddr
>= (caddr_t
)VM_MAX_USER_ADDRESS
556 vmspace_exec(p
, NULL
);
557 p
->p_vmspace
->vm_daddr
= vminfo
.cvm_daddr
;
558 p
->p_vmspace
->vm_dsize
= ctob(vminfo
.cvm_dsize
); /* in bytes */
559 p
->p_vmspace
->vm_taddr
= vminfo
.cvm_taddr
;
560 p
->p_vmspace
->vm_tsize
= ctob(vminfo
.cvm_tsize
); /* in bytes */
561 if ((error
= read_check(fp
, &vpcount
, sizeof(int))) != 0)
563 vnh
= kmalloc(sizeof(struct vn_hdr
) * vpcount
, M_TEMP
, M_WAITOK
);
564 if ((error
= read_check(fp
, vnh
, sizeof(struct vn_hdr
)*vpcount
)) != 0)
566 for (i
= 0; i
< vpcount
; i
++) {
567 if ((error
= mmap_vp(&vnh
[i
])) != 0)
582 elf_getfiles(struct lwp
*lp
, struct file
*fp
)
588 struct ckpt_filehdr filehdr
;
589 struct ckpt_fileinfo
*cfi_base
= NULL
;
590 struct filedesc
*fdp
= lp
->lwp_proc
->p_fd
;
596 if ((error
= read_check(fp
, &filehdr
, sizeof(filehdr
))) != 0)
598 filecount
= filehdr
.cfh_nfiles
;
599 cfi_base
= kmalloc(filecount
*sizeof(struct ckpt_fileinfo
), M_TEMP
, M_WAITOK
);
600 error
= read_check(fp
, cfi_base
, filecount
*sizeof(struct ckpt_fileinfo
));
605 * Close all file descriptors >= 3. These descriptors are from the
606 * checkpt(1) program itself and should not be retained.
608 * XXX we need a flag so a checkpoint restore can opt to supply the
609 * descriptors, or the non-regular-file descripors.
611 for (i
= 3; i
< fdp
->fd_nfiles
; ++i
)
617 for (i
= 0; i
< filecount
; i
++) {
618 struct ckpt_fileinfo
*cfi
= &cfi_base
[i
];
620 * Ignore placeholder entries where cfi_index is less then
621 * zero. This will occur if the elf core dump code thinks
622 * it can save a vnode but winds up not being able to.
624 if (cfi
->cfi_index
< 0)
628 * Restore a saved file descriptor. If CKFIF_ISCKPTFD is
629 * set the descriptor represents the checkpoint file itself,
630 * probably due to the user calling sys_checkpoint(). We
631 * want to use the fp being used to restore the checkpoint
632 * instead of trying to restore the original filehandle.
634 if (cfi
->cfi_ckflags
& CKFIF_ISCKPTFD
) {
639 error
= ckpt_fhtovp(&cfi
->cfi_fh
, &vp
);
641 error
= fp_vpopen(vp
, OFLAGS(cfi
->cfi_flags
),
649 tempfp
->f_offset
= cfi
->cfi_offset
;
652 * If overwriting a descriptor close the old descriptor. This
653 * only occurs if the saved core saved descriptors that we
654 * have not already closed.
656 if (cfi
->cfi_index
< fdp
->fd_nfiles
&&
657 (ofp
= fdp
->fd_files
[cfi
->cfi_index
].fp
) != NULL
) {
658 kern_close(cfi
->cfi_index
);
662 * Allocate the descriptor we want.
664 if (fdalloc(lp
->lwp_proc
, cfi
->cfi_index
, &fd
) != 0) {
665 PRINTF(("can't currently restore fd: %d\n",
670 KKASSERT(fd
== cfi
->cfi_index
);
671 fsetfd(fdp
, tempfp
, fd
);
674 PRINTF(("restoring %d\n", cfi
->cfi_index
));
679 kfree(cfi_base
, M_TEMP
);
685 ckpt_freeze_proc(struct lwp
*lp
, struct file
*fp
)
687 struct proc
*p
= lp
->lwp_proc
;
691 lwkt_gettoken(&p
->p_token
); /* needed for proc_*() calls */
693 PRINTF(("calling generic_elf_coredump\n"));
694 limit
= p
->p_rlimit
[RLIMIT_CORE
].rlim_cur
;
696 if (p
->p_stat
!= SCORE
) {
698 while (p
->p_nstopped
< p
->p_nthreads
- 1)
699 tsleep(&p
->p_nstopped
, 0, "freeze", 1);
700 error
= generic_elf_coredump(lp
, SIGCKPT
, fp
, limit
);
701 proc_unstop(p
, SCORE
);
708 lwkt_reltoken(&p
->p_token
);
716 sys_sys_checkpoint(struct sysmsg
*sysmsg
,
717 const struct sys_checkpoint_args
*uap
)
720 struct thread
*td
= curthread
;
721 struct proc
*p
= td
->td_proc
;
725 * Only certain groups (to reduce our security exposure). -1
728 if (ckptgroup
>= 0 && groupmember(ckptgroup
, td
->td_ucred
) == 0)
732 * For now we can only checkpoint the current process
734 if (uap
->pid
!= -1 && uap
->pid
!= p
->p_pid
)
742 if (uap
->fd
== -1 && uap
->pid
== (pid_t
)-1)
743 error
= checkpoint_signal_handler(td
->td_lwp
);
744 else if ((fp
= holdfp(td
, uap
->fd
, FWRITE
)) == NULL
)
747 error
= ckpt_freeze_proc(td
->td_lwp
, fp
);
749 dropfp(td
, uap
->fd
, fp
);
752 if (uap
->pid
!= -1) {
756 if ((fp
= holdfp(td
, uap
->fd
, FREAD
)) == NULL
) {
760 sysmsg
->sysmsg_result
= uap
->retval
;
761 error
= ckpt_thaw_proc(td
->td_lwp
, fp
);
762 dropfp(td
, uap
->fd
, fp
);
773 checkpoint_signal_handler(struct lwp
*lp
)
775 struct thread
*td
= lp
->lwp_thread
;
776 struct proc
*p
= lp
->lwp_proc
;
779 struct nlookupdata nd
;
785 * Being able to checkpoint an suid or sgid program is not a good
788 if (sugid_coredump
== 0 && (p
->p_flags
& P_SUGID
)) {
793 buf
= ckpt_expand_name(p
->p_comm
, td
->td_ucred
->cr_uid
, p
->p_pid
);
799 log(LOG_INFO
, "pid %d (%s), uid %d: checkpointing to %s\n",
801 (td
->td_ucred
? td
->td_ucred
->cr_uid
: -1),
804 PRINTF(("ckpt handler called, using '%s'\n", buf
));
807 * Use the same safety flags that the coredump code uses. Remove
808 * any previous checkpoint file before writing out the new one in
809 * case we are re-checkpointing a program that had been checkpt
810 * restored. Otherwise we will corrupt the program space (which is
811 * made up of mmap()ings of the previous checkpoint file) while we
812 * write out the new one.
814 error
= nlookup_init(&nd
, buf
, UIO_SYSSPACE
, 0);
816 error
= kern_unlink(&nd
);
818 error
= fp_open(buf
, O_WRONLY
|O_CREAT
|O_TRUNC
|O_NOFOLLOW
, 0600, &fp
);
820 error
= ckpt_freeze_proc(lp
, fp
);
823 kprintf("checkpoint failed with open - error: %d\n", error
);
830 static char ckptfilename
[MAXPATHLEN
] = {"%N.ckpt"};
831 SYSCTL_STRING(_kern
, OID_AUTO
, ckptfile
, CTLFLAG_RW
, ckptfilename
,
832 sizeof(ckptfilename
), "process checkpoint name format string");
835 * expand_name(name, uid, pid)
836 * Expand the name described in corefilename, using name, uid, and pid.
837 * corefilename is a kprintf-like string, with three format specifiers:
838 * %N name of process ("name")
839 * %P process id (pid)
841 * For example, "%N.core" is the default; they can be disabled completely
842 * by using "/dev/null", or all core files can be stored in "/cores/%U/%N-%P".
843 * This is controlled by the sysctl variable kern.corefile (see above).
845 * -- taken from the coredump code
850 ckpt_expand_name(const char *name
, uid_t uid
, pid_t pid
)
854 char buf
[11]; /* Buffer for pid/uid -- max 4B */
858 char *format
= ckptfilename
;
861 temp
= kmalloc(MAXPATHLEN
+ 1, M_TEMP
, M_NOWAIT
);
864 namelen
= strlen(name
);
866 if (ckptfilename
[0] != '/') {
867 if ((bp
= kern_getcwd(temp
, MAXPATHLEN
- 1, &error
)) == NULL
) {
872 bcopy(bp
, temp
, n
+ 1); /* normalize location of the path */
876 for (i
= 0; n
< MAXPATHLEN
&& format
[i
]; i
++) {
879 case '%': /* Format character */
885 case 'N': /* process name */
886 if ((n
+ namelen
) > MAXPATHLEN
) {
887 log(LOG_ERR
, "pid %d (%s), uid (%u): Path `%s%s' is too long\n",
888 pid
, name
, uid
, temp
, name
);
892 memcpy(temp
+n
, name
, namelen
);
895 case 'P': /* process id */
896 l
= ksprintf(buf
, "%u", pid
);
897 if ((n
+ l
) > MAXPATHLEN
) {
898 log(LOG_ERR
, "pid %d (%s), uid (%u): Path `%s%s' is too long\n",
899 pid
, name
, uid
, temp
, name
);
903 memcpy(temp
+n
, buf
, l
);
906 case 'U': /* user id */
907 l
= ksprintf(buf
, "%u", uid
);
908 if ((n
+ l
) > MAXPATHLEN
) {
909 log(LOG_ERR
, "pid %d (%s), uid (%u): Path `%s%s' is too long\n",
910 pid
, name
, uid
, temp
, name
);
914 memcpy(temp
+n
, buf
, l
);
918 log(LOG_ERR
, "Unknown format character %c in `%s'\n", format
[i
], format
);
922 temp
[n
++] = format
[i
];