int cpt_open_object(cpt_object_t *obj, struct cpt_context *ctx) { if (ctx->file == NULL) return 0; cpt_close_object(ctx); ctx->current_object = ctx->file->f_pos; if (obj) cpt_obj_setpos(obj, ctx->current_object, ctx); return 0; }
int rst_sockets(struct cpt_context *ctx) { int err; loff_t sec = ctx->sections[CPT_SECT_SOCKET]; loff_t endsec; cpt_object_t *obj; struct cpt_section_hdr h; if (sec == CPT_NULL) return 0; err = ctx->pread(&h, sizeof(h), ctx, sec); if (err) { eprintk_ctx("rst_sockets: ctx->pread: %d\n", err); return err; } if (h.cpt_section != CPT_SECT_SOCKET || h.cpt_hdrlen < sizeof(h)) { eprintk_ctx("rst_sockets: hdr err\n"); return -EINVAL; } /* The first pass: we create socket index and open listening sockets. */ endsec = sec + h.cpt_next; sec += h.cpt_hdrlen; while (sec < endsec) { struct cpt_sock_image *sbuf = cpt_get_buf(ctx); err = rst_get_object(CPT_OBJ_SOCKET, sec, sbuf, ctx); if (err) { eprintk_ctx("rst_sockets: rst_get_object: %d\n", err); cpt_release_buf(ctx); return err; } if (sbuf->cpt_state == TCP_LISTEN) { err = open_listening_socket(sec, sbuf, ctx); cpt_release_buf(ctx); if (err) { eprintk_ctx("rst_sockets: open_listening_socket: %d\n", err); return err; } } else { cpt_release_buf(ctx); obj = alloc_cpt_object(GFP_KERNEL, ctx); if (obj == NULL) return -ENOMEM; cpt_obj_setindex(obj, sbuf->cpt_index, ctx); cpt_obj_setpos(obj, sec, ctx); obj->o_ppos = sbuf->cpt_file; intern_cpt_object(CPT_OBJ_SOCKET, obj, ctx); } sec += sbuf->cpt_next; } /* Pass 2: really restore sockets */ for_each_object(obj, CPT_OBJ_SOCKET) { struct cpt_sock_image *sbuf; if (obj->o_obj != NULL) continue; sbuf = cpt_get_buf(ctx); err = rst_get_object(CPT_OBJ_SOCKET, obj->o_pos, sbuf, ctx); if (err) { eprintk_ctx("rst_sockets: rst_get_object: %d\n", err); cpt_release_buf(ctx); return err; } if (sbuf->cpt_state == TCP_LISTEN) BUG(); err = open_socket(obj, sbuf, ctx); cpt_release_buf(ctx); if (err) { eprintk_ctx("rst_sockets: open_socket: %d\n", err); return err; } } return 0; }
static int open_listening_socket(loff_t pos, struct cpt_sock_image *si, struct cpt_context *ctx) { int err; struct socket *sock; struct file *file; cpt_object_t *obj, *fobj; err = sock_create(si->cpt_family, si->cpt_type, si->cpt_protocol, &sock); if (err) { eprintk_ctx("open_listening_socket: sock_create: %d\n", err); return err; } sock->sk->sk_reuse = 2; sock->sk->sk_bound_dev_if = si->cpt_bound_dev_if; if (sock->sk->sk_family == AF_UNIX) { err = bind_unix_socket(sock, si, ctx); } else if (si->cpt_laddrlen) { if (sock->sk->sk_family == AF_INET || sock->sk->sk_family == AF_INET6) inet_sk(sock->sk)->freebind = 1; err = sock->ops->bind(sock, (struct sockaddr *)&si->cpt_laddr, si->cpt_laddrlen); if (err) { eprintk_ctx("open_listening_socket: bind: %d\n", err); goto err_out; } } err = sock->ops->listen(sock, si->cpt_max_ack_backlog); if (err) { eprintk_ctx("open_listening_socket: listen: %d, %Ld, %d\n", err, pos, si->cpt_deleted); goto err_out; } /* Now we may access socket body directly and fixup all the things. */ file = sock_mapfile(sock); err = PTR_ERR(file); if (IS_ERR(file)) { eprintk_ctx("open_listening_socket: map: %d\n", err); goto err_out; } err = -ENOMEM; if ((fobj = cpt_object_add(CPT_OBJ_FILE, file, ctx)) == NULL) goto err_out; if ((obj = cpt_object_add(CPT_OBJ_SOCKET, sock->sk, ctx)) == NULL) goto err_out; cpt_obj_setpos(obj, pos, ctx); cpt_obj_setindex(obj, si->cpt_index, ctx); obj->o_parent = file; cpt_obj_setpos(fobj, si->cpt_file, ctx); cpt_obj_setindex(fobj, si->cpt_index, ctx); setup_sock_common(sock->sk, si, pos, ctx); if (si->cpt_family == AF_INET || si->cpt_family == AF_INET6) { rst_listen_socket_in(sock->sk, si, pos, ctx); rst_restore_synwait_queue(sock->sk, si, pos, ctx); } return 0; err_out: sock_release(sock); return err; }
static int open_socket(cpt_object_t *obj, struct cpt_sock_image *si, struct cpt_context *ctx) { int err; struct socket *sock; struct socket *sock2 = NULL; struct file *file; cpt_object_t *fobj; cpt_object_t *pobj = NULL; err = sock_create(si->cpt_family, si->cpt_type, si->cpt_protocol, &sock); if (err) return err; if (si->cpt_socketpair) { err = sock_create(si->cpt_family, si->cpt_type, si->cpt_protocol, &sock2); if (err) goto err_out; err = sock->ops->socketpair(sock, sock2); if (err < 0) goto err_out; /* Socketpair with a peer outside our environment. * So, we create real half-open pipe and do not worry * about dead end anymore. */ if (si->cpt_peer == -1) { sock_release(sock2); sock2 = NULL; } } cpt_obj_setobj(obj, sock->sk, ctx); if (si->cpt_file != CPT_NULL) { file = sock_mapfile(sock); err = PTR_ERR(file); if (IS_ERR(file)) goto err_out; err = -ENOMEM; obj->o_parent = file; if ((fobj = cpt_object_add(CPT_OBJ_FILE, file, ctx)) == NULL) goto err_out; cpt_obj_setpos(fobj, si->cpt_file, ctx); cpt_obj_setindex(fobj, si->cpt_index, ctx); } if (sock2) { struct file *file2; pobj = lookup_cpt_obj_byindex(CPT_OBJ_SOCKET, si->cpt_peer, ctx); if (!pobj) BUG(); if (pobj->o_obj) BUG(); cpt_obj_setobj(pobj, sock2->sk, ctx); if (pobj->o_ppos != CPT_NULL) { file2 = sock_mapfile(sock2); err = PTR_ERR(file2); if (IS_ERR(file2)) goto err_out; err = -ENOMEM; if ((fobj = cpt_object_add(CPT_OBJ_FILE, file2, ctx)) == NULL) goto err_out; cpt_obj_setpos(fobj, pobj->o_ppos, ctx); cpt_obj_setindex(fobj, si->cpt_peer, ctx); pobj->o_parent = file2; } } setup_sock_common(sock->sk, si, obj->o_pos, ctx); if (sock->sk->sk_family == AF_INET || sock->sk->sk_family == AF_INET6) { int saved_reuse = sock->sk->sk_reuse; inet_sk(sock->sk)->freebind = 1; sock->sk->sk_reuse = 2; if (si->cpt_laddrlen) { err = sock->ops->bind(sock, (struct sockaddr *)&si->cpt_laddr, si->cpt_laddrlen); if (err) { dprintk_ctx("binding failed: %d, do not worry\n", err); } } sock->sk->sk_reuse = saved_reuse; rst_socket_in(si, obj->o_pos, sock->sk, ctx); } else if (sock->sk->sk_family == AF_NETLINK) { struct sockaddr_nl *nl = (struct sockaddr_nl *)&si->cpt_laddr; if (nl->nl_pid) { err = sock->ops->bind(sock, (struct sockaddr *)&si->cpt_laddr, si->cpt_laddrlen); if (err) { eprintk_ctx("AF_NETLINK binding failed: %d\n", err); } } if (si->cpt_raddrlen && nl->nl_pid) { err = sock->ops->connect(sock, (struct sockaddr *)&si->cpt_raddr, si->cpt_raddrlen, O_NONBLOCK); if (err) { eprintk_ctx("oops, AF_NETLINK connect failed: %d\n", err); } } generic_restore_queues(sock->sk, si, obj->o_pos, ctx); } else if (sock->sk->sk_family == PF_PACKET) { struct sockaddr_ll *ll = (struct sockaddr_ll *)&si->cpt_laddr; if (ll->sll_protocol || ll->sll_ifindex) { int alen = si->cpt_laddrlen; if (alen < sizeof(struct sockaddr_ll)) alen = sizeof(struct sockaddr_ll); err = sock->ops->bind(sock, (struct sockaddr *)&si->cpt_laddr, alen); if (err) { eprintk_ctx("AF_PACKET binding failed: %d\n", err); } } generic_restore_queues(sock->sk, si, obj->o_pos, ctx); } fixup_unix_address(sock, si, ctx); if (sock2) { err = rst_get_object(CPT_OBJ_SOCKET, pobj->o_pos, si, ctx); if (err) return err; setup_sock_common(sock2->sk, si, pobj->o_pos, ctx); fixup_unix_address(sock2, si, ctx); } if ((sock->sk->sk_family == AF_INET || sock->sk->sk_family == AF_INET6) && (int)si->cpt_parent != -1) { cpt_object_t *lobj = lookup_cpt_obj_byindex(CPT_OBJ_SOCKET, si->cpt_parent, ctx); if (lobj && cpt_attach_accept(lobj->o_obj, sock->sk, ctx) == 0) sock->sk = NULL; } if (si->cpt_file == CPT_NULL && sock->sk && sock->sk->sk_family == AF_INET) { struct sock *sk = sock->sk; if (sk) { sock->sk = NULL; local_bh_disable(); bh_lock_sock(sk); if (sock_owned_by_user(sk)) eprintk_ctx("oops, sock is locked by user\n"); sock_hold(sk); sock_orphan(sk); ub_inc_orphan_count(sk); bh_unlock_sock(sk); local_bh_enable(); sock_put(sk); dprintk_ctx("orphaning socket %p\n", sk); } } if (si->cpt_file == CPT_NULL && sock->sk == NULL) sock_release(sock); return 0; err_out: if (sock2) sock_release(sock2); sock_release(sock); return err; }
struct file * rst_open_tty(cpt_object_t *mntobj, char *name, struct cpt_file_image *fi, struct cpt_inode_image *ii, unsigned flags, struct cpt_context *ctx) { int err; cpt_object_t *obj; struct file *master, *slave; struct tty_struct *stty; struct cpt_tty_image *pi; static char *a = "pqrstuvwxyzabcde"; static char *b = "0123456789abcdef"; char pairname[16]; unsigned master_flags, slave_flags; if (fi->cpt_priv == CPT_NULL) return ERR_PTR(-EINVAL); obj = lookup_cpt_obj_bypos(CPT_OBJ_TTY, fi->cpt_priv, ctx); if (obj && obj->o_parent) { dprintk_ctx("obtained pty as pair to existing\n"); master = obj->o_parent; stty = file_tty(master); if (stty->driver->subtype == PTY_TYPE_MASTER && (stty->driver->flags&TTY_DRIVER_DEVPTS_MEM)) { wprintk_ctx("cloning ptmx\n"); get_file(master); return master; } master = dentry_open(dget(master->f_dentry), mntget(master->f_vfsmnt), flags, current_cred()); if (!IS_ERR(master)) { stty = file_tty(master); if (stty->driver->subtype != PTY_TYPE_MASTER) fixup_tty_attrs(ii, master, ctx); } return master; } pi = cpt_get_buf(ctx); err = rst_get_object(CPT_OBJ_TTY, fi->cpt_priv, pi, ctx); if (err) { cpt_release_buf(ctx); return ERR_PTR(err); } if (MAJOR(ii->cpt_rdev) == TTY_MAJOR || ii->cpt_rdev == MKDEV(TTYAUX_MAJOR, 1)) { if (mntobj && (mntobj->o_flags & CPT_VFSMOUNT_DELAYFS)) return ERR_PTR(-ENOTSUPP); master = rst_open_file(mntobj, name, fi, flags|O_NONBLOCK|O_NOCTTY, ctx); if (IS_ERR(master)) { eprintk_ctx("rst_open_tty: %s %Ld %ld\n", name, (long long)fi->cpt_priv, PTR_ERR(master)); return master; } stty = file_tty(master); obj = cpt_object_add(CPT_OBJ_TTY, stty, ctx); obj->o_parent = master; cpt_obj_setpos(obj, fi->cpt_priv, ctx); obj = cpt_object_add(CPT_OBJ_FILE, master, ctx); cpt_obj_setpos(obj, CPT_NULL, ctx); get_file(master); /* Do not restore /dev/ttyX state */ cpt_release_buf(ctx); return master; } master_flags = slave_flags = 0; if (pi->cpt_drv_subtype == PTY_TYPE_MASTER) master_flags = flags; else slave_flags = flags; /* * Open pair master/slave. */ if (pi->cpt_drv_flags&TTY_DRIVER_DEVPTS_MEM) { master = ptmx_open(pi->cpt_index, master_flags); } else { sprintf(pairname, "/dev/pty%c%c", a[pi->cpt_index/16], b[pi->cpt_index%16]); master = filp_open(pairname, master_flags|O_NONBLOCK|O_NOCTTY|O_RDWR, 0); } if (IS_ERR(master)) { eprintk_ctx("filp_open master: %Ld %ld\n", (long long)fi->cpt_priv, PTR_ERR(master)); cpt_release_buf(ctx); return master; } stty = file_tty(master); clear_bit(TTY_PTY_LOCK, &stty->flags); if (pi->cpt_drv_flags&TTY_DRIVER_DEVPTS_MEM) sprintf(pairname, "/dev/pts/%d", stty->index); else sprintf(pairname, "/dev/tty%c%c", a[stty->index/16], b[stty->index%16]); slave = filp_open(pairname, slave_flags|O_NONBLOCK|O_NOCTTY|O_RDWR, 0); if (IS_ERR(slave)) { eprintk_ctx("filp_open slave %s: %ld\n", pairname, PTR_ERR(slave)); fput(master); cpt_release_buf(ctx); return slave; } if (pi->cpt_drv_subtype != PTY_TYPE_MASTER) fixup_tty_attrs(ii, slave, ctx); cpt_object_add(CPT_OBJ_TTY, file_tty(master), ctx); cpt_object_add(CPT_OBJ_TTY, file_tty(slave), ctx); cpt_object_add(CPT_OBJ_FILE, master, ctx); cpt_object_add(CPT_OBJ_FILE, slave, ctx); if (pi->cpt_drv_subtype == PTY_TYPE_MASTER) { loff_t pos; obj = lookup_cpt_object(CPT_OBJ_TTY, file_tty(master), ctx); obj->o_parent = master; cpt_obj_setpos(obj, fi->cpt_priv, ctx); pty_setup(stty, fi->cpt_priv, pi, ctx); obj = lookup_cpt_object(CPT_OBJ_TTY, file_tty(slave), ctx); obj->o_parent = slave; pos = find_pty_pair(stty->link, fi->cpt_priv, pi, ctx); cpt_obj_setpos(obj, pos, ctx); obj = lookup_cpt_object(CPT_OBJ_FILE, slave, ctx); cpt_obj_setpos(obj, CPT_NULL, ctx); get_file(master); cpt_release_buf(ctx); return master; } else { loff_t pos; obj = lookup_cpt_object(CPT_OBJ_TTY, file_tty(slave), ctx); obj->o_parent = slave; cpt_obj_setpos(obj, fi->cpt_priv, ctx); pty_setup(stty->link, fi->cpt_priv, pi, ctx); obj = lookup_cpt_object(CPT_OBJ_TTY, file_tty(master), ctx); obj->o_parent = master; pos = find_pty_pair(stty, fi->cpt_priv, pi, ctx); cpt_obj_setpos(obj, pos, ctx); obj = lookup_cpt_object(CPT_OBJ_FILE, master, ctx); cpt_obj_setpos(obj, CPT_NULL, ctx); get_file(slave); cpt_release_buf(ctx); return slave; } }