Do a bit of cleanup and add a bit of debugging to the checkpoint module.
[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.2 2003/10/20 06:50:49 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         psinfo  = malloc(sizeof(prpsinfo_t), M_TEMP, M_ZERO | M_WAITOK);
184         status  = malloc(nthreads*sizeof(prstatus_t), M_TEMP, M_WAITOK);
185         fpregset  = malloc(nthreads*sizeof(prfpregset_t), M_TEMP, M_WAITOK);
186         note = malloc(notesz, M_TEMP, M_WAITOK);
187
188         
189         PRINTF(("reading notes section\n"));
190         if ((error = read_check(fp, note, notesz)) != 0)
191                 goto done;
192         error = elf_demarshalnotes(note, psinfo, status, fpregset, nthreads);
193         if (error)
194                 goto done;
195         /* fetch register state from notes */
196         error = elf_loadnotes(p, psinfo, status, fpregset);
197  done:
198         if (psinfo)
199                 free(psinfo, M_TEMP);
200         if (status)
201                 free(status, M_TEMP);
202         if (fpregset)
203                 free(fpregset, M_TEMP);
204         if (note)
205                 free(note, M_TEMP);
206         return error;
207 }
208
209 static int
210 ckpt_thaw_proc(struct proc *p, struct file *fp)
211 {
212
213         Elf_Phdr *phdr = NULL;
214         Elf_Ehdr *ehdr = NULL;
215         int error;
216         size_t nbyte;
217
218         TRACE_ENTER;
219         
220         ehdr = malloc(sizeof(Elf_Ehdr), 
221                                    M_TEMP, M_ZERO | M_WAITOK);
222
223         if ((error = elf_gethdr(fp, ehdr)) != 0)
224                 goto done;
225         nbyte = sizeof(Elf_Phdr) * ehdr->e_phnum; 
226         phdr = malloc(nbyte, M_TEMP, M_WAITOK); 
227
228         /* fetch description of program writable mappings */
229         if ((error = elf_getphdrs(fp, phdr, nbyte)) != 0)
230                 goto done;
231
232         /* fetch notes section containing register state */
233         if ((error = elf_getnotes(p, fp, phdr->p_filesz)) != 0)
234                 goto done;
235
236         /* fetch program text vnodes */
237         if ((error = elf_gettextvp(p, fp)) != 0)
238                 goto done;
239
240         /* fetch signal disposition */
241         if ((error = elf_getsigs(p, fp)) != 0)
242                 goto done;
243
244         /* fetch open files */
245         if ((error = elf_getfiles(p, fp)) != 0)
246                 goto done;
247
248         /* handle mappings last in case we are reading from a socket */
249         error = elf_loadphdrs(fp, phdr, ehdr->e_phnum);
250 done:
251         if (ehdr)
252                 free(ehdr, M_TEMP);
253         if (phdr)
254                 free(phdr, M_TEMP);
255         TRACE_EXIT;
256         return error;
257 }
258
259 static int
260 elf_loadnotes(struct proc *p, prpsinfo_t *psinfo, prstatus_t *status, 
261            prfpregset_t *fpregset) 
262 {
263         int error;
264
265         /* validate status and psinfo */
266         TRACE_ENTER;
267         if (status->pr_version != PRSTATUS_VERSION ||
268             status->pr_statussz != sizeof(prstatus_t) ||
269             status->pr_gregsetsz != sizeof(gregset_t) ||
270             status->pr_fpregsetsz != sizeof(fpregset_t) ||
271             psinfo->pr_version != PRPSINFO_VERSION ||
272             psinfo->pr_psinfosz != sizeof(prpsinfo_t)) {
273                 PRINTF(("status check failed\n"));
274                 error = EINVAL;
275                 goto done;
276         }
277         if ((error = set_regs(p, &status->pr_reg)) != 0)
278                 goto done;
279         error = set_fpregs(p, fpregset);
280         /* strncpy(psinfo->pr_psargs, p->p_comm, PRARGSZ); */
281  done:  
282         TRACE_EXIT;
283         return error;
284 }
285
286 static int 
287 elf_getnote(void *src, size_t *off, const char *name, unsigned int type,
288             void **desc, size_t descsz) 
289 {
290         Elf_Note note;
291         int error;
292
293         TRACE_ENTER;
294         if (src == NULL) {
295                 error = EFAULT;
296                 goto done;
297         }
298         bcopy((char *)src + *off, &note, sizeof note);
299         
300         PRINTF(("at offset: %d expected note of type: %d - got: %d\n",
301                *off, type, note.n_type));
302         *off += sizeof note;
303         if (type != note.n_type) {
304                 TRACE_ERR;
305                 error = EINVAL;
306                 goto done;
307         }
308         if (strncmp(name, (char *) src + *off, note.n_namesz) != 0) {
309                 error = EINVAL;
310                 goto done;
311         }
312         *off += roundup2(note.n_namesz, sizeof(Elf_Size));
313         if (note.n_descsz != descsz) {
314                 TRACE_ERR;
315                 error = EINVAL;
316                 goto done;
317         }
318         if (desc)
319                 bcopy((char *)src + *off, *desc, note.n_descsz);
320         *off += roundup2(note.n_descsz, sizeof(Elf_Size));
321         error = 0;
322  done:
323         TRACE_EXIT;
324         return error;
325 }
326
327 static int
328 elf_demarshalnotes(void *src, prpsinfo_t *psinfo, prstatus_t *status, 
329                    prfpregset_t *fpregset, int nthreads) 
330 {
331         int i;
332         int error;
333         int off = 0;
334
335         TRACE_ENTER;
336         error = elf_getnote(src, &off, "FreeBSD", NT_PRSTATUS, 
337                            (void **)&status, sizeof(prstatus_t));
338         if (error)
339                 goto done;
340         error = elf_getnote(src, &off, "FreeBSD", NT_FPREGSET, 
341                            (void **)&fpregset, sizeof(prfpregset_t));
342         if (error)
343                 goto done;
344         error = elf_getnote(src, &off, "FreeBSD", NT_PRPSINFO, 
345                            (void **)&psinfo, sizeof(prpsinfo_t));
346         if (error)
347                 goto done;
348
349         /*
350          * The remaining portion needs to be an integer multiple
351          * of prstatus_t and prfpregset_t
352          */
353         for (i = 0 ; i < nthreads - 1; i++) {
354                 status++; fpregset++;
355                 error = elf_getnote(src, &off, "FreeBSD", NT_PRSTATUS, 
356                                    (void **)&status, sizeof (prstatus_t));
357                 if (error)
358                         goto done;
359                 error = elf_getnote(src, &off, "FreeBSD", NT_FPREGSET, 
360                                    (void **)&fpregset, sizeof(prfpregset_t));
361                 if (error)
362                         goto done;
363         }
364         
365  done:
366         TRACE_EXIT;
367         return error;
368 }
369
370
371 static int
372 mmap_phdr(struct file *fp, Elf_Phdr *phdr) 
373 {
374         int error;
375         size_t len;
376         int prot;
377         void *addr;
378         int flags;
379         off_t pos;
380
381         TRACE_ENTER;
382         pos = phdr->p_offset;
383         len = phdr->p_filesz;
384         addr = (void *)phdr->p_vaddr;
385         flags = MAP_FIXED | MAP_NOSYNC | MAP_PRIVATE;
386         prot = 0;
387         if (phdr->p_flags & PF_R)
388                 prot |= PROT_READ;
389         if (phdr->p_flags & PF_W)
390                 prot |= PROT_WRITE;
391         if (phdr->p_flags & PF_X)
392                 prot |= PROT_EXEC;      
393         if ((error = fp_mmap(addr, len, prot, flags, fp, pos, &addr)) != 0) {
394                 PRINTF(("mmap failed: %d\n", error);       );
395         }
396         PRINTF(("map @%08x-%08x fileoff %08x-%08x\n", (int)addr, (int)((char *)addr + len), (int)pos, (int)(pos + len)));
397         TRACE_EXIT;
398         return error;
399 }
400
401
402 static int
403 elf_loadphdrs(struct file *fp, Elf_Phdr *phdr, int numsegs) 
404 {
405         int i;
406         int error = 0;
407
408         TRACE_ENTER;
409         for (i = 1; i < numsegs; i++)  {
410                 if ((error = mmap_phdr(fp, &phdr[i])) != 0)
411                         break;
412         }
413         TRACE_EXIT;
414         return error;
415 }
416
417 static int
418 elf_getsigs(struct proc *p, struct file *fp) 
419 {
420         int error;
421         struct ckpt_siginfo *csi;
422         struct sigacts *tmpsigacts;
423
424         TRACE_ENTER;
425         csi = malloc(sizeof(struct ckpt_siginfo), M_TEMP, M_ZERO | M_WAITOK);
426         if ((error = read_check(fp, csi, sizeof(struct ckpt_siginfo))) != 0)
427                 goto done;
428
429         if (csi->csi_ckptpisz != sizeof(struct ckpt_siginfo)) {
430                 TRACE_ERR;
431                 error = EINVAL;
432                 goto done;
433         }
434         tmpsigacts = p->p_procsig->ps_sigacts;
435         bcopy(&csi->csi_procsig, p->p_procsig, sizeof(struct procsig));
436         p->p_procsig->ps_sigacts = tmpsigacts;
437         bcopy(&csi->csi_sigacts, p->p_procsig->ps_sigacts, sizeof(struct sigacts));
438         bcopy(&csi->csi_itimerval, &p->p_realtimer, sizeof(struct itimerval));
439         p->p_sigparent = csi->csi_sigparent;
440  done:
441         if (csi)
442                 free(csi, M_TEMP);
443         TRACE_EXIT;
444         return error;
445 }
446
447
448 static int
449 ckpt_fhtovp(fhandle_t *fh, struct vnode **vpp) 
450 {
451         struct mount *mp;
452         int error;
453
454         TRACE_ENTER;
455         mp = vfs_getvfs(&fh->fh_fsid);
456
457         if (!mp) {
458                 TRACE_ERR;
459                 PRINTF(("failed to get mount - ESTALE\n"));
460                 TRACE_EXIT;
461                 return ESTALE;
462         }
463         error = VFS_FHTOVP(mp, &fh->fh_fid, vpp);
464         if (error) {
465                 PRINTF(("failed with: %d\n", error));
466                 TRACE_ERR;
467                 TRACE_EXIT;
468                 return error;
469         }
470         TRACE_EXIT;
471         return 0;
472 }
473
474 static int
475 mmap_vp(struct vn_hdr *vnh) 
476 {
477         struct vnode **vpp, *vp;
478         Elf_Phdr *phdr;
479         struct file *fp;
480         int error;
481         TRACE_ENTER;
482         vpp = &vp;
483
484         phdr = &vnh->vnh_phdr;
485
486         if ((error = ckpt_fhtovp(&vnh->vnh_fh, vpp)) != 0)
487                 return error;
488         /*
489          * XXX O_RDONLY -> or O_RDWR if file is PROT_WRITE, MAP_SHARED
490          */
491         if ((error = fp_vpopen(*vpp, O_RDONLY, &fp)) != 0)
492                 return error;
493         error = mmap_phdr(fp, phdr);
494         fp_close(fp);
495         TRACE_EXIT;
496         return error;
497 }
498
499
500 static int
501 elf_gettextvp(struct proc *p, struct file *fp)
502 {
503         int i;
504         int error;
505         int vpcount;
506         struct ckpt_vminfo vminfo;
507         struct vn_hdr *vnh = NULL;
508
509         TRACE_ENTER;
510         if ((error = read_check(fp, &vminfo, sizeof(vminfo))) != 0)
511                 goto done;
512         if (vminfo.cvm_dsize < 0 || 
513             vminfo.cvm_dsize > p->p_rlimit[RLIMIT_DATA].rlim_cur ||
514             vminfo.cvm_tsize < 0 ||
515             (u_quad_t)vminfo.cvm_tsize > maxtsiz ||
516             vminfo.cvm_daddr >= (caddr_t)VM_MAXUSER_ADDRESS ||
517             vminfo.cvm_taddr >= (caddr_t)VM_MAXUSER_ADDRESS
518         ) {
519             error = ERANGE;
520             goto done;
521         }
522         p->p_vmspace->vm_daddr = vminfo.cvm_daddr;
523         p->p_vmspace->vm_dsize = vminfo.cvm_dsize;
524         p->p_vmspace->vm_taddr = vminfo.cvm_taddr;
525         p->p_vmspace->vm_tsize = vminfo.cvm_tsize;
526         if ((error = read_check(fp, &vpcount, sizeof(int))) != 0)
527                 goto done;
528         vnh = malloc(sizeof(struct vn_hdr) * vpcount, M_TEMP, M_WAITOK);
529         if ((error = read_check(fp, vnh, sizeof(struct vn_hdr)*vpcount)) != 0)
530                 goto done;
531         for (i = 0; i < vpcount; i++) {
532                 if ((error = mmap_vp(&vnh[i])) != 0)
533                         goto done;
534         }
535         
536  done:
537         if (vnh)
538                 free(vnh, M_TEMP);
539         TRACE_EXIT;
540         return error;
541 }
542
543
544
545 /* place holder */
546 static int
547 elf_getfiles(struct proc *p, struct file *fp)
548 {
549         int error;
550         int i;
551         int filecount;
552         struct ckpt_filehdr filehdr;
553         struct ckpt_fileinfo *cfi_base = NULL;
554         struct vnode *vp;
555         struct file *tempfp;
556
557         TRACE_ENTER;
558         if ((error = read_check(fp, &filehdr, sizeof(filehdr))) != 0)
559                 goto done;
560         filecount = filehdr.cfh_nfiles;
561         cfi_base = malloc(filecount*sizeof(struct ckpt_fileinfo), M_TEMP, M_WAITOK);
562         error = read_check(fp, cfi_base, filecount*sizeof(struct ckpt_fileinfo));
563         if (error)
564                 goto done;
565
566         for (i = 0; i < filecount; i++) {
567                 struct ckpt_fileinfo *cfi= &cfi_base[i];
568                 if (cfi->cfi_index < 0 || cfi->cfi_index >=  p->p_fd->fd_nfiles) {
569                         PRINTF(("can't currently restore fd: %d\n",
570                                cfi->cfi_index));
571                         goto done;
572                 }
573                 if ((error = ckpt_fhtovp(&cfi->cfi_fh, &vp)) != 0)
574                         break;
575                 if ((error = fp_vpopen(vp, OFLAGS(cfi->cfi_flags), &tempfp)) != 0)
576                         break;
577                 tempfp->f_offset = cfi->cfi_offset;
578                 /*  XXX bail for now if we the index is 
579                  *  larger than the current file table 
580                  */
581
582                 PRINTF(("restoring %d\n", cfi->cfi_index));
583                 p->p_fd->fd_ofiles[cfi->cfi_index] = tempfp;            
584                 cfi++;
585         }
586
587  done:
588         if (cfi_base)
589                 free(cfi_base, M_TEMP);
590         TRACE_EXIT;
591         return error;
592 }
593
594 static int
595 ckpt_freeze_proc (struct proc *p, struct file *fp)
596 {
597         rlim_t limit;
598         int error;
599
600         PRINTF(("calling generic_elf_coredump\n"));
601         limit = p->p_rlimit[RLIMIT_CORE].rlim_cur;
602         if (limit) {
603                 error = generic_elf_coredump(p, fp, limit);
604         } else {
605                 error = ERANGE;
606         }
607         return error;
608 }
609
610 #if 0
611 /* THIS CAN'T WORK */
612 static int
613 ckpt_freeze_pid(int pid, struct file *fp) 
614 {
615         struct proc *p;
616
617         if ((p = pfind(pid)) == NULL)
618                 return ESRCH;
619         return ckpt_freeze_proc(p, fp);
620 }
621 #endif
622
623 static int 
624 ckpt_proc(void *uap /* struct ckpt_args */)
625 {
626         int error = 0;
627         int *res;
628         struct proc *p = curthread->td_proc;
629         struct ckpt_args *ca = (struct ckpt_args *)uap; 
630         struct file *fp;
631
632         res = &((struct nosys_args *)uap)->sysmsg_result;
633
634         /*
635          * Only certain groups (to reduce our security exposure).  -1
636          * allows any group.
637          */
638         if (ckptgroup >= 0 && groupmember(ckptgroup, p->p_ucred) == 0) {
639                 error = EPERM;
640                 goto done;
641         }
642         switch (ca->args.gen.type) {
643         case CKPT_FREEZE:
644                 if ((fp = holdfp(p->p_fd, ca->args.gen.fd, FWRITE)) == NULL)
645                         return EBADF;
646                 error = ckpt_freeze_proc(p, fp);
647                 fdrop(fp, curthread);
648                 break;
649         case CKPT_THAW:
650                 if ((fp = holdfp(p->p_fd, ca->args.gen.fd, FREAD)) == NULL)
651                         return EBADF;
652                 *res = ca->args.cta.retval;
653                 error = ckpt_thaw_proc(p, fp);
654                 fdrop(fp, curthread);
655                 break;
656         case CKPT_FREEZEPID:
657                 error = ENOSYS;
658                 break; 
659 #if 0
660                 /* doesn't work */
661                 if ((fp = holdfp(p->p_fd, ca->args.gen.fd, FWRITE)) == NULL)
662                         return EBADF;
663                 error = ckpt_freeze_pid(ca->args.cfpa.pid, fp);
664                 fdrop(fp, curthread);
665                 break;
666 #endif
667         case CKPT_THAWBIN:
668                 error = ENOSYS;
669                 break;
670 #if 0
671                 /* not supported */
672                 if ((fp = holdfp(p->p_fd, ca->args.gen.fd, FREAD)) == NULL)
673                         return EBADF;
674                 error = ckpt_thaw_bin(p, fp,
675                                 ca->args.ctba.bin, ca->args.ctba.binlen);
676                 fdrop(fp, curthread);
677                 break;
678 #endif
679         default:
680                 error = ENOSYS;
681                 break;
682         }
683 done:
684         PRINTF(("error of ckpt_proc is %d, retval is %d\n", error, *res));
685         return error;
686 }
687
688 static void
689 ckpt_handler(struct proc *p) 
690 {
691         char *buf;
692         struct file *fp;
693         int error;
694
695         buf = ckpt_expand_name(p->p_comm, p->p_ucred->cr_uid, p->p_pid);
696         if (buf == NULL)
697                 return;
698
699         log(LOG_INFO, "pid %d (%s), uid %d: checkpointing to %s\n",
700                 p->p_pid, p->p_comm, 
701                 (p->p_ucred ? p->p_ucred->cr_uid : -1),
702                 buf);
703
704         /*
705          * Being able to checkpoint an suid or sgid program is not a good
706          * idea.
707          */
708         if (sugid_coredump == 0 && (p->p_flag & P_SUGID))
709                 return;
710
711         PRINTF(("ckpt handler called, using '%s'\n", buf));
712
713         /*
714          * Use the same safety flags that the coredump code uses.
715          */
716         error = fp_open(buf, O_WRONLY|O_CREAT|O_NOFOLLOW, 0600, &fp);
717         if (error == 0) {
718                 (void)ckpt_freeze_proc(p, fp);
719                 fp_close(fp);
720         } else {
721                 printf("checkpoint failed with open - error: %d\n", error);
722         }
723         free(buf, M_TEMP);
724 }
725
726
727 /*
728  * The `sysent' for the new syscall
729  */
730 static struct sysent ckpt_sysent = {
731         4,              /* sy_narg */
732         ckpt_proc       /* sy_call */
733 };
734
735 static int ckpt_offset = 210;
736
737 static int
738 load (struct module *module, int cmd, void *arg)
739 {
740         int error = 0;
741        
742         switch (cmd) {
743         case MOD_LOAD :         
744                 PRINTF( ("ckpt loaded at %d\n", ckpt_offset));
745                 (void)register_ckpt_func(ckpt_handler);
746                 break;
747         case MOD_UNLOAD :
748                 PRINTF( ("ckpt unloaded from %d\n", ckpt_offset);       );
749                 /* if we are unloaded while a process is being checkpointed
750                  * the kernel will likely crash  XXX
751                  */
752                 (void)register_ckpt_func(NULL);
753                 break;
754         default :
755                 error = EINVAL;
756                 break;
757         }
758         return error;
759 }
760
761 SYSCALL_MODULE(syscall, &ckpt_offset, &ckpt_sysent, load, NULL);