Merge from vendor branch BINUTILS:
[dragonfly.git] / sys / checkpt / checkpt.c
1 /*-
2  * Copyright (c) 2003 Kip Macy
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  *
26  * $DragonFly: src/sys/checkpt/Attic/checkpt.c,v 1.4 2003/12/20 04:07:03 dillon Exp $
27  */
28
29 #include <sys/types.h>
30 #include <sys/param.h>
31 #include <sys/proc.h>
32 #include <sys/module.h>
33 #include <sys/sysent.h>
34 #include <sys/kernel.h>
35 #include <sys/systm.h>
36
37 #include <sys/file.h>
38 /* only on dragonfly */
39 #include <sys/file2.h>
40 #include <sys/fcntl.h>
41 #include <sys/signal.h>
42 #include <vm/vm_param.h>
43 #include <vm/vm.h>
44 #include <sys/imgact_elf.h>
45 #include <sys/procfs.h>
46
47 #include <sys/lock.h>
48 #include <vm/pmap.h>
49 #include <vm/vm_map.h>
50
51 #include <sys/mman.h>
52 #include <sys/sysproto.h>
53 #include <sys/resource.h>
54 #include <sys/resourcevar.h>
55 #include <sys/malloc.h>
56 #include <sys/stat.h>
57 #include <sys/uio.h>
58 #include <sys/namei.h>
59 #include <sys/vnode.h>
60 #include <machine/limits.h>
61 #include <i386/include/frame.h>
62 #include <sys/signalvar.h>
63 #include <sys/syslog.h>
64 #include <sys/sysctl.h>
65 #include <i386/include/sigframe.h>
66 #include <sys/exec.h>
67 #include <sys/unistd.h>
68 #include <sys/time.h>
69 #include "checkpt.h"
70 #include <sys/mount.h>
71 #include <sys/ckpt.h>
72
73
74 static int elf_loadphdrs(struct file *fp,  Elf_Phdr *phdr, int numsegs);
75 static int elf_getnotes(struct proc *p, 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 proc *, prpsinfo_t *, prstatus_t *, 
79                  prfpregset_t *);
80 static int elf_getsigs(struct proc *p, struct file *fp); 
81 static int elf_getfiles(struct proc *p, struct file *fp);
82 static int elf_gettextvp(struct proc *p, struct file *fp);
83
84 static int ckptgroup = 0;       /* wheel only, -1 for any group */
85 SYSCTL_INT(_kern, OID_AUTO, ckptgroup, CTLFLAG_RW, &ckptgroup, 0, "");
86
87 static __inline
88 int
89 read_check(struct file *fp, void *buf, size_t nbyte)
90 {
91         size_t nread;
92         int error;
93
94         PRINTF(("reading %d bytes\n", nbyte));
95         error = fp_read(fp, buf, nbyte, &nread);
96         if (error) {
97                 PRINTF(("read failed - %d", error));
98         } else if (nread != nbyte) {
99                 PRINTF(("wanted to read %d - read %d\n", nbyte, nread));
100                 error = EINVAL;
101         }
102         return error;
103 }
104
105 static int
106 elf_gethdr(struct file *fp, Elf_Ehdr *ehdr) 
107 {
108         size_t nbyte = sizeof(Elf_Ehdr);
109         int error;
110
111         if ((error = read_check(fp, ehdr, nbyte)) != 0)
112                 goto done;
113         if (!(ehdr->e_ehsize == sizeof(Elf_Ehdr))) {
114                 PRINTF(("wrong elf header size: %d\n"
115                        "expected size        : %d\n", 
116                        ehdr->e_ehsize, sizeof(Elf_Ehdr)));
117                 return EINVAL;
118         }
119         if (!(ehdr->e_phentsize == sizeof(Elf_Phdr))) {
120                 PRINTF(("wrong program header size: %d\n"
121                        "expected size            : %d\n",  
122                        ehdr->e_phentsize, sizeof(Elf_Phdr)));
123                 return EINVAL;
124         }
125
126         if (!(ehdr->e_ident[EI_MAG0] == ELFMAG0 &&
127               ehdr->e_ident[EI_MAG1] == ELFMAG1 &&
128               ehdr->e_ident[EI_MAG2] == ELFMAG2 &&
129               ehdr->e_ident[EI_MAG3] == ELFMAG3 &&
130               ehdr->e_ident[EI_CLASS] == ELF_CLASS &&
131               ehdr->e_ident[EI_DATA] == ELF_DATA &&
132               ehdr->e_ident[EI_VERSION] == EV_CURRENT &&
133               ehdr->e_ident[EI_OSABI] == ELFOSABI_FREEBSD &&
134               ehdr->e_ident[EI_ABIVERSION] == 0)) {
135                 PRINTF(("bad elf header\n there are %d segments\n",
136                        ehdr->e_phnum));
137                 return EINVAL;
138
139         }
140         PRINTF(("Elf header size:           %d\n", ehdr->e_ehsize));
141         PRINTF(("Program header size:       %d\n", ehdr->e_phentsize));
142         PRINTF(("Number of Program headers: %d\n", ehdr->e_phnum));
143  done:
144         return error;
145
146
147 static int
148 elf_getphdrs(struct file *fp, Elf_Phdr *phdr, size_t nbyte) 
149 {
150         int i;
151         int error;
152         int nheaders = nbyte/sizeof(Elf_Phdr); 
153
154         PRINTF(("reading phdrs section\n"));
155         if ((error = read_check(fp, phdr, nbyte)) != 0)
156                 goto done;
157         printf("headers section:\n");
158         for (i = 0; i < nheaders; i++) {
159                 printf("entry type:   %d\n", phdr[i].p_type);
160                 printf("file offset:  %d\n", phdr[i].p_offset);
161                 printf("virt address: %p\n", (uint32_t *)phdr[i].p_vaddr);
162                 printf("file size:    %d\n", phdr[i].p_filesz);
163                 printf("memory size:  %d\n", phdr[i].p_memsz);
164                 printf("\n");
165         }
166  done:
167         return error;
168 }
169
170
171 static int
172 elf_getnotes(struct proc *p, struct file *fp, size_t notesz) 
173 {
174         int error;
175         int nthreads;
176         char *note;
177         prpsinfo_t *psinfo;
178         prstatus_t *status;
179         prfpregset_t *fpregset;
180
181         nthreads = (notesz - sizeof(prpsinfo_t))/(sizeof(prstatus_t) + 
182                                                   sizeof(prfpregset_t));
183         PRINTF(("reading notes header nthreads=%d\n", nthreads));
184         if (nthreads <= 0 || nthreads > CKPT_MAXTHREADS)
185                 return EINVAL;
186
187         psinfo  = malloc(sizeof(prpsinfo_t), M_TEMP, M_ZERO | M_WAITOK);
188         status  = malloc(nthreads*sizeof(prstatus_t), M_TEMP, M_WAITOK);
189         fpregset  = malloc(nthreads*sizeof(prfpregset_t), M_TEMP, M_WAITOK);
190         note = malloc(notesz, M_TEMP, M_WAITOK);
191
192         
193         PRINTF(("reading notes section\n"));
194         if ((error = read_check(fp, note, notesz)) != 0)
195                 goto done;
196         error = elf_demarshalnotes(note, psinfo, status, fpregset, nthreads);
197         if (error)
198                 goto done;
199         /* fetch register state from notes */
200         error = elf_loadnotes(p, psinfo, status, fpregset);
201  done:
202         if (psinfo)
203                 free(psinfo, M_TEMP);
204         if (status)
205                 free(status, M_TEMP);
206         if (fpregset)
207                 free(fpregset, M_TEMP);
208         if (note)
209                 free(note, M_TEMP);
210         return error;
211 }
212
213 static int
214 ckpt_thaw_proc(struct proc *p, struct file *fp)
215 {
216
217         Elf_Phdr *phdr = NULL;
218         Elf_Ehdr *ehdr = NULL;
219         int error;
220         size_t nbyte;
221
222         TRACE_ENTER;
223         
224         ehdr = malloc(sizeof(Elf_Ehdr), M_TEMP, M_ZERO | M_WAITOK);
225
226         if ((error = elf_gethdr(fp, ehdr)) != 0)
227                 goto done;
228         nbyte = sizeof(Elf_Phdr) * ehdr->e_phnum; 
229         phdr = malloc(nbyte, M_TEMP, M_WAITOK); 
230
231         /* fetch description of program writable mappings */
232         if ((error = elf_getphdrs(fp, phdr, nbyte)) != 0)
233                 goto done;
234
235         /* fetch notes section containing register state */
236         if ((error = elf_getnotes(p, fp, phdr->p_filesz)) != 0)
237                 goto done;
238
239         /* fetch program text vnodes */
240         if ((error = elf_gettextvp(p, fp)) != 0)
241                 goto done;
242
243         /* fetch signal disposition */
244         if ((error = elf_getsigs(p, fp)) != 0)
245                 goto done;
246
247         /* fetch open files */
248         if ((error = elf_getfiles(p, fp)) != 0)
249                 goto done;
250
251         /* handle mappings last in case we are reading from a socket */
252         error = elf_loadphdrs(fp, phdr, ehdr->e_phnum);
253 done:
254         if (ehdr)
255                 free(ehdr, M_TEMP);
256         if (phdr)
257                 free(phdr, M_TEMP);
258         TRACE_EXIT;
259         return error;
260 }
261
262 static int
263 elf_loadnotes(struct proc *p, prpsinfo_t *psinfo, prstatus_t *status, 
264            prfpregset_t *fpregset) 
265 {
266         int error;
267
268         /* validate status and psinfo */
269         TRACE_ENTER;
270         if (status->pr_version != PRSTATUS_VERSION ||
271             status->pr_statussz != sizeof(prstatus_t) ||
272             status->pr_gregsetsz != sizeof(gregset_t) ||
273             status->pr_fpregsetsz != sizeof(fpregset_t) ||
274             psinfo->pr_version != PRPSINFO_VERSION ||
275             psinfo->pr_psinfosz != sizeof(prpsinfo_t)) {
276                 PRINTF(("status check failed\n"));
277                 error = EINVAL;
278                 goto done;
279         }
280         if ((error = set_regs(p, &status->pr_reg)) != 0)
281                 goto done;
282         error = set_fpregs(p, fpregset);
283         /* strncpy(psinfo->pr_psargs, p->p_comm, PRARGSZ); */
284  done:  
285         TRACE_EXIT;
286         return error;
287 }
288
289 static int 
290 elf_getnote(void *src, size_t *off, const char *name, unsigned int type,
291             void **desc, size_t descsz) 
292 {
293         Elf_Note note;
294         int error;
295
296         TRACE_ENTER;
297         if (src == NULL) {
298                 error = EFAULT;
299                 goto done;
300         }
301         bcopy((char *)src + *off, &note, sizeof note);
302         
303         PRINTF(("at offset: %d expected note of type: %d - got: %d\n",
304                *off, type, note.n_type));
305         *off += sizeof note;
306         if (type != note.n_type) {
307                 TRACE_ERR;
308                 error = EINVAL;
309                 goto done;
310         }
311         if (strncmp(name, (char *) src + *off, note.n_namesz) != 0) {
312                 error = EINVAL;
313                 goto done;
314         }
315         *off += roundup2(note.n_namesz, sizeof(Elf_Size));
316         if (note.n_descsz != descsz) {
317                 TRACE_ERR;
318                 error = EINVAL;
319                 goto done;
320         }
321         if (desc)
322                 bcopy((char *)src + *off, *desc, note.n_descsz);
323         *off += roundup2(note.n_descsz, sizeof(Elf_Size));
324         error = 0;
325  done:
326         TRACE_EXIT;
327         return error;
328 }
329
330 static int
331 elf_demarshalnotes(void *src, prpsinfo_t *psinfo, prstatus_t *status, 
332                    prfpregset_t *fpregset, int nthreads) 
333 {
334         int i;
335         int error;
336         int off = 0;
337
338         TRACE_ENTER;
339         error = elf_getnote(src, &off, "FreeBSD", NT_PRSTATUS, 
340                            (void **)&status, sizeof(prstatus_t));
341         if (error)
342                 goto done;
343         error = elf_getnote(src, &off, "FreeBSD", NT_FPREGSET, 
344                            (void **)&fpregset, sizeof(prfpregset_t));
345         if (error)
346                 goto done;
347         error = elf_getnote(src, &off, "FreeBSD", NT_PRPSINFO, 
348                            (void **)&psinfo, sizeof(prpsinfo_t));
349         if (error)
350                 goto done;
351
352         /*
353          * The remaining portion needs to be an integer multiple
354          * of prstatus_t and prfpregset_t
355          */
356         for (i = 0 ; i < nthreads - 1; i++) {
357                 status++; fpregset++;
358                 error = elf_getnote(src, &off, "FreeBSD", NT_PRSTATUS, 
359                                    (void **)&status, sizeof (prstatus_t));
360                 if (error)
361                         goto done;
362                 error = elf_getnote(src, &off, "FreeBSD", NT_FPREGSET, 
363                                    (void **)&fpregset, sizeof(prfpregset_t));
364                 if (error)
365                         goto done;
366         }
367         
368  done:
369         TRACE_EXIT;
370         return error;
371 }
372
373
374 static int
375 mmap_phdr(struct file *fp, Elf_Phdr *phdr) 
376 {
377         int error;
378         size_t len;
379         int prot;
380         void *addr;
381         int flags;
382         off_t pos;
383
384         TRACE_ENTER;
385         pos = phdr->p_offset;
386         len = phdr->p_filesz;
387         addr = (void *)phdr->p_vaddr;
388         flags = MAP_FIXED | MAP_NOSYNC | MAP_PRIVATE;
389         prot = 0;
390         if (phdr->p_flags & PF_R)
391                 prot |= PROT_READ;
392         if (phdr->p_flags & PF_W)
393                 prot |= PROT_WRITE;
394         if (phdr->p_flags & PF_X)
395                 prot |= PROT_EXEC;      
396         if ((error = fp_mmap(addr, len, prot, flags, fp, pos, &addr)) != 0) {
397                 PRINTF(("mmap failed: %d\n", error);       );
398         }
399         PRINTF(("map @%08x-%08x fileoff %08x-%08x\n", (int)addr, (int)((char *)addr + len), (int)pos, (int)(pos + len)));
400         TRACE_EXIT;
401         return error;
402 }
403
404
405 static int
406 elf_loadphdrs(struct file *fp, Elf_Phdr *phdr, int numsegs) 
407 {
408         int i;
409         int error = 0;
410
411         TRACE_ENTER;
412         for (i = 1; i < numsegs; i++)  {
413                 if ((error = mmap_phdr(fp, &phdr[i])) != 0)
414                         break;
415         }
416         TRACE_EXIT;
417         return error;
418 }
419
420 static int
421 elf_getsigs(struct proc *p, struct file *fp) 
422 {
423         int error;
424         struct ckpt_siginfo *csi;
425         struct sigacts *tmpsigacts;
426
427         TRACE_ENTER;
428         csi = malloc(sizeof(struct ckpt_siginfo), M_TEMP, M_ZERO | M_WAITOK);
429         if ((error = read_check(fp, csi, sizeof(struct ckpt_siginfo))) != 0)
430                 goto done;
431
432         if (csi->csi_ckptpisz != sizeof(struct ckpt_siginfo)) {
433                 TRACE_ERR;
434                 error = EINVAL;
435                 goto done;
436         }
437         tmpsigacts = p->p_procsig->ps_sigacts;
438         bcopy(&csi->csi_procsig, p->p_procsig, sizeof(struct procsig));
439         p->p_procsig->ps_sigacts = tmpsigacts;
440         bcopy(&csi->csi_sigacts, p->p_procsig->ps_sigacts, sizeof(struct sigacts));
441         bcopy(&csi->csi_itimerval, &p->p_realtimer, sizeof(struct itimerval));
442         p->p_sigparent = csi->csi_sigparent;
443  done:
444         if (csi)
445                 free(csi, M_TEMP);
446         TRACE_EXIT;
447         return error;
448 }
449
450
451 static int
452 ckpt_fhtovp(fhandle_t *fh, struct vnode **vpp) 
453 {
454         struct mount *mp;
455         int error;
456
457         TRACE_ENTER;
458         mp = vfs_getvfs(&fh->fh_fsid);
459
460         if (!mp) {
461                 TRACE_ERR;
462                 PRINTF(("failed to get mount - ESTALE\n"));
463                 TRACE_EXIT;
464                 return ESTALE;
465         }
466         error = VFS_FHTOVP(mp, &fh->fh_fid, vpp);
467         if (error) {
468                 PRINTF(("failed with: %d\n", error));
469                 TRACE_ERR;
470                 TRACE_EXIT;
471                 return error;
472         }
473         TRACE_EXIT;
474         return 0;
475 }
476
477 static int
478 mmap_vp(struct vn_hdr *vnh) 
479 {
480         struct vnode **vpp, *vp;
481         Elf_Phdr *phdr;
482         struct file *fp;
483         int error;
484         TRACE_ENTER;
485         vpp = &vp;
486
487         phdr = &vnh->vnh_phdr;
488
489         if ((error = ckpt_fhtovp(&vnh->vnh_fh, vpp)) != 0)
490                 return error;
491         /*
492          * XXX O_RDONLY -> or O_RDWR if file is PROT_WRITE, MAP_SHARED
493          */
494         if ((error = fp_vpopen(*vpp, O_RDONLY, &fp)) != 0)
495                 return error;
496         error = mmap_phdr(fp, phdr);
497         fp_close(fp);
498         TRACE_EXIT;
499         return error;
500 }
501
502
503 static int
504 elf_gettextvp(struct proc *p, struct file *fp)
505 {
506         int i;
507         int error;
508         int vpcount;
509         struct ckpt_vminfo vminfo;
510         struct vn_hdr *vnh = NULL;
511
512         TRACE_ENTER;
513         if ((error = read_check(fp, &vminfo, sizeof(vminfo))) != 0)
514                 goto done;
515         if (vminfo.cvm_dsize < 0 || 
516             vminfo.cvm_dsize > p->p_rlimit[RLIMIT_DATA].rlim_cur ||
517             vminfo.cvm_tsize < 0 ||
518             (u_quad_t)vminfo.cvm_tsize > maxtsiz ||
519             vminfo.cvm_daddr >= (caddr_t)VM_MAXUSER_ADDRESS ||
520             vminfo.cvm_taddr >= (caddr_t)VM_MAXUSER_ADDRESS
521         ) {
522             error = ERANGE;
523             goto done;
524         }
525         p->p_vmspace->vm_daddr = vminfo.cvm_daddr;
526         p->p_vmspace->vm_dsize = vminfo.cvm_dsize;
527         p->p_vmspace->vm_taddr = vminfo.cvm_taddr;
528         p->p_vmspace->vm_tsize = vminfo.cvm_tsize;
529         if ((error = read_check(fp, &vpcount, sizeof(int))) != 0)
530                 goto done;
531         vnh = malloc(sizeof(struct vn_hdr) * vpcount, M_TEMP, M_WAITOK);
532         if ((error = read_check(fp, vnh, sizeof(struct vn_hdr)*vpcount)) != 0)
533                 goto done;
534         for (i = 0; i < vpcount; i++) {
535                 if ((error = mmap_vp(&vnh[i])) != 0)
536                         goto done;
537         }
538         
539  done:
540         if (vnh)
541                 free(vnh, M_TEMP);
542         TRACE_EXIT;
543         return error;
544 }
545
546
547
548 /* place holder */
549 static int
550 elf_getfiles(struct proc *p, struct file *fp)
551 {
552         int error;
553         int i;
554         int filecount;
555         struct ckpt_filehdr filehdr;
556         struct ckpt_fileinfo *cfi_base = NULL;
557         struct vnode *vp;
558         struct file *tempfp;
559
560         TRACE_ENTER;
561         if ((error = read_check(fp, &filehdr, sizeof(filehdr))) != 0)
562                 goto done;
563         filecount = filehdr.cfh_nfiles;
564         cfi_base = malloc(filecount*sizeof(struct ckpt_fileinfo), M_TEMP, M_WAITOK);
565         error = read_check(fp, cfi_base, filecount*sizeof(struct ckpt_fileinfo));
566         if (error)
567                 goto done;
568
569         for (i = 0; i < filecount; i++) {
570                 struct ckpt_fileinfo *cfi= &cfi_base[i];
571                 /*
572                  * Ignore placeholder entries where cfi_index is less then
573                  * zero.  This will occur if the elf core dump code thinks
574                  * it can save a vnode but winds up not being able to.
575                  */
576                 if (cfi->cfi_index < 0)
577                         continue;
578                 if (cfi->cfi_index >=  p->p_fd->fd_nfiles) {
579                         PRINTF(("can't currently restore fd: %d\n",
580                                cfi->cfi_index));
581                         goto done;
582                 }
583                 if ((error = ckpt_fhtovp(&cfi->cfi_fh, &vp)) != 0)
584                         break;
585                 if ((error = fp_vpopen(vp, OFLAGS(cfi->cfi_flags), &tempfp)) != 0)
586                         break;
587                 tempfp->f_offset = cfi->cfi_offset;
588                 /*  XXX bail for now if we the index is 
589                  *  larger than the current file table 
590                  */
591
592                 PRINTF(("restoring %d\n", cfi->cfi_index));
593                 p->p_fd->fd_ofiles[cfi->cfi_index] = tempfp;            
594                 cfi++;
595         }
596
597  done:
598         if (cfi_base)
599                 free(cfi_base, M_TEMP);
600         TRACE_EXIT;
601         return error;
602 }
603
604 static int
605 ckpt_freeze_proc (struct proc *p, struct file *fp)
606 {
607         rlim_t limit;
608         int error;
609
610         PRINTF(("calling generic_elf_coredump\n"));
611         limit = p->p_rlimit[RLIMIT_CORE].rlim_cur;
612         if (limit) {
613                 error = generic_elf_coredump(p, fp, limit);
614         } else {
615                 error = ERANGE;
616         }
617         return error;
618 }
619
620 #if 0
621 /* THIS CAN'T WORK */
622 static int
623 ckpt_freeze_pid(int pid, struct file *fp) 
624 {
625         struct proc *p;
626
627         if ((p = pfind(pid)) == NULL)
628                 return ESRCH;
629         return ckpt_freeze_proc(p, fp);
630 }
631 #endif
632
633 static int 
634 ckpt_proc(void *uap /* struct ckpt_args */)
635 {
636         int error = 0;
637         int *res;
638         struct proc *p = curthread->td_proc;
639         struct ckpt_args *ca = (struct ckpt_args *)uap; 
640         struct file *fp;
641
642         res = &((struct nosys_args *)uap)->sysmsg_result;
643
644         /*
645          * Only certain groups (to reduce our security exposure).  -1
646          * allows any group.
647          */
648         if (ckptgroup >= 0 && groupmember(ckptgroup, p->p_ucred) == 0) {
649                 error = EPERM;
650                 goto done;
651         }
652         switch (ca->args.gen.type) {
653         case CKPT_FREEZE:
654                 if ((fp = holdfp(p->p_fd, ca->args.gen.fd, FWRITE)) == NULL)
655                         return EBADF;
656                 error = ckpt_freeze_proc(p, fp);
657                 fdrop(fp, curthread);
658                 break;
659         case CKPT_THAW:
660                 if ((fp = holdfp(p->p_fd, ca->args.gen.fd, FREAD)) == NULL)
661                         return EBADF;
662                 *res = ca->args.cta.retval;
663                 error = ckpt_thaw_proc(p, fp);
664                 fdrop(fp, curthread);
665                 break;
666         case CKPT_FREEZEPID:
667                 error = ENOSYS;
668                 break; 
669 #if 0
670                 /* doesn't work */
671                 if ((fp = holdfp(p->p_fd, ca->args.gen.fd, FWRITE)) == NULL)
672                         return EBADF;
673                 error = ckpt_freeze_pid(ca->args.cfpa.pid, fp);
674                 fdrop(fp, curthread);
675                 break;
676 #endif
677         case CKPT_THAWBIN:
678                 error = ENOSYS;
679                 break;
680 #if 0
681                 /* not supported */
682                 if ((fp = holdfp(p->p_fd, ca->args.gen.fd, FREAD)) == NULL)
683                         return EBADF;
684                 error = ckpt_thaw_bin(p, fp,
685                                 ca->args.ctba.bin, ca->args.ctba.binlen);
686                 fdrop(fp, curthread);
687                 break;
688 #endif
689         default:
690                 error = ENOSYS;
691                 break;
692         }
693 done:
694         PRINTF(("error of ckpt_proc is %d, retval is %d\n", error, *res));
695         return error;
696 }
697
698 static void
699 ckpt_handler(struct proc *p) 
700 {
701         char *buf;
702         struct file *fp;
703         int error;
704
705         /*
706          * Being able to checkpoint an suid or sgid program is not a good
707          * idea.
708          */
709         if (sugid_coredump == 0 && (p->p_flag & P_SUGID))
710                 return;
711
712         buf = ckpt_expand_name(p->p_comm, p->p_ucred->cr_uid, p->p_pid);
713         if (buf == NULL)
714                 return;
715
716         log(LOG_INFO, "pid %d (%s), uid %d: checkpointing to %s\n",
717                 p->p_pid, p->p_comm, 
718                 (p->p_ucred ? p->p_ucred->cr_uid : -1),
719                 buf);
720
721         PRINTF(("ckpt handler called, using '%s'\n", buf));
722
723         /*
724          * Use the same safety flags that the coredump code uses.
725          */
726         error = fp_open(buf, O_WRONLY|O_CREAT|O_NOFOLLOW, 0600, &fp);
727         if (error == 0) {
728                 (void)ckpt_freeze_proc(p, fp);
729                 fp_close(fp);
730         } else {
731                 printf("checkpoint failed with open - error: %d\n", error);
732         }
733         free(buf, M_TEMP);
734 }
735
736
737 /*
738  * The `sysent' for the new syscall
739  */
740 static struct sysent ckpt_sysent = {
741         4,              /* sy_narg */
742         ckpt_proc       /* sy_call */
743 };
744
745 static int ckpt_offset = 210;
746
747 static int
748 load (struct module *module, int cmd, void *arg)
749 {
750         int error = 0;
751        
752         switch (cmd) {
753         case MOD_LOAD :         
754                 PRINTF( ("ckpt loaded at %d\n", ckpt_offset));
755                 (void)register_ckpt_func(ckpt_handler);
756                 break;
757         case MOD_UNLOAD :
758                 PRINTF( ("ckpt unloaded from %d\n", ckpt_offset);       );
759                 /* if we are unloaded while a process is being checkpointed
760                  * the kernel will likely crash  XXX
761                  */
762                 (void)register_ckpt_func(NULL);
763                 break;
764         default :
765                 error = EINVAL;
766                 break;
767         }
768         return error;
769 }
770
771 SYSCALL_MODULE(syscall, &ckpt_offset, &ckpt_sysent, load, NULL);