int rst_sockets_complete(struct cpt_context *ctx) { int err; cpt_object_t *obj; for_each_object(obj, CPT_OBJ_SOCKET) { struct cpt_sock_image *sbuf; struct sock *sk = obj->o_obj; struct sock *peer; if (!sk) BUG(); if (sk->sk_family != AF_UNIX) continue; sbuf = cpt_get_buf(ctx); err = rst_get_object(CPT_OBJ_SOCKET, obj->o_pos, sbuf, ctx); if (err) { cpt_release_buf(ctx); return err; } if (sbuf->cpt_next > sbuf->cpt_hdrlen) restore_unix_rqueue(sk, sbuf, obj->o_pos, ctx); cpt_release_buf(ctx); if (sk->sk_type == SOCK_DGRAM && unix_peer(sk) == NULL) { cpt_object_t *pobj; sbuf = cpt_get_buf(ctx); err = rst_get_object(CPT_OBJ_SOCKET, obj->o_pos, sbuf, ctx); if (err) { cpt_release_buf(ctx); return err; } if (sbuf->cpt_peer != -1) { pobj = lookup_cpt_obj_byindex(CPT_OBJ_SOCKET, sbuf->cpt_peer, ctx); if (pobj) { peer = pobj->o_obj; sock_hold(peer); unix_peer(sk) = peer; } } cpt_release_buf(ctx); } } rst_orphans(ctx); return 0; }
int rst_tty_jobcontrol(struct cpt_context *ctx) { int err; loff_t sec = ctx->sections[CPT_SECT_TTY]; loff_t endsec; struct cpt_section_hdr h; err = ctx->pread(&h, sizeof(h), ctx, sec); if (err) return err; if (h.cpt_section != CPT_SECT_TTY || h.cpt_hdrlen < sizeof(h)) return -EINVAL; endsec = sec + h.cpt_next; sec += h.cpt_hdrlen; while (sec < endsec) { cpt_object_t *obj; struct cpt_tty_image *pibuf = cpt_get_buf(ctx); if (rst_get_object(CPT_OBJ_TTY, sec, pibuf, ctx)) { cpt_release_buf(ctx); return -EINVAL; } obj = lookup_cpt_obj_bypos(CPT_OBJ_TTY, sec, ctx); if (obj) { struct tty_struct *stty = obj->o_obj; if ((int)pibuf->cpt_pgrp > 0) { stty->pgrp = alloc_vpid_safe(pibuf->cpt_pgrp); if (!stty->pgrp) dprintk_ctx("unknown tty pgrp %d\n", pibuf->cpt_pgrp); } else if (pibuf->cpt_pgrp) { stty->pgrp = alloc_pid(current->nsproxy->pid_ns, 0); if (!stty->pgrp) { eprintk_ctx("cannot allocate stray tty->pgr\n"); cpt_release_buf(ctx); return -EINVAL; } } if ((int)pibuf->cpt_session > 0) { stty->session = alloc_vpid_safe(pibuf->cpt_session); if (!stty->session) dprintk_ctx("unknown tty session %d\n", pibuf->cpt_session); } } sec += pibuf->cpt_next; cpt_release_buf(ctx); } return 0; }
int rst_orphans(struct cpt_context *ctx) { int err; loff_t sec = ctx->sections[CPT_SECT_ORPHANS]; 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) return err; if (h.cpt_section != CPT_SECT_ORPHANS || h.cpt_hdrlen < sizeof(h)) return -EINVAL; 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) { cpt_release_buf(ctx); return err; } obj = alloc_cpt_object(GFP_KERNEL, ctx); if (obj == NULL) { cpt_release_buf(ctx); return -ENOMEM; } obj->o_pos = sec; obj->o_ppos = sbuf->cpt_file; err = open_socket(obj, sbuf, ctx); dprintk_ctx("Restoring orphan: %d\n", err); free_cpt_object(obj, ctx); cpt_release_buf(ctx); if (err) return err; sec += sbuf->cpt_next; } return 0; }
int rst_eventpoll(cpt_context_t *ctx) { int err; loff_t sec = ctx->sections[CPT_SECT_EPOLL]; loff_t endsec; struct cpt_section_hdr h; if (sec == CPT_NULL) return 0; err = ctx->pread(&h, sizeof(h), ctx, sec); if (err) return err; if (h.cpt_section != CPT_SECT_EPOLL || h.cpt_hdrlen < sizeof(h)) return -EINVAL; endsec = sec + h.cpt_next; sec += h.cpt_hdrlen; while (sec < endsec) { cpt_object_t *obj; struct cpt_epoll_image *ebuf = cpt_get_buf(ctx); err = rst_get_object(CPT_OBJ_EPOLL, sec, ebuf, ctx); if (err) { cpt_release_buf(ctx); return err; } obj = lookup_cpt_obj_bypos(CPT_OBJ_FILE, ebuf->cpt_file, ctx); if (obj == NULL) { eprintk_ctx("cannot find epoll file object\n"); cpt_release_buf(ctx); return -EINVAL; } err = restore_one_epoll(obj, sec, ebuf, ctx); cpt_release_buf(ctx); if (err) return err; sec += ebuf->cpt_next; } return 0; }
static int rst_restore_netstats(loff_t pos, struct net_device *dev, struct cpt_context * ctx) { struct cpt_netstats_image *n; struct net_device_stats *stats = NULL; int err; if (!dev->netdev_ops->ndo_get_stats) return 0; n = cpt_get_buf(ctx); err = rst_get_object(CPT_OBJ_NET_STATS, pos, n, ctx); if (err) goto out; BUG_ON(sizeof(struct cpt_netstats_image) != n->cpt_hdrlen); preempt_disable(); if (dev->netdev_ops->ndo_cpt == NULL) { err = -ENODEV; eprintk_ctx("Network device %s is not supported\n", dev->name); goto out; } stats = dev->netdev_ops->ndo_get_stats(dev); stats->rx_packets = n->cpt_rx_packets; stats->tx_packets = n->cpt_tx_packets; stats->rx_bytes = n->cpt_rx_bytes; stats->tx_bytes = n->cpt_tx_bytes; stats->rx_errors = n->cpt_rx_errors; stats->tx_errors = n->cpt_tx_errors; stats->rx_dropped = n->cpt_rx_dropped; stats->tx_dropped = n->cpt_tx_dropped; stats->multicast = n->cpt_multicast; stats->collisions = n->cpt_collisions; stats->rx_length_errors = n->cpt_rx_length_errors; stats->rx_over_errors = n->cpt_rx_over_errors; stats->rx_crc_errors = n->cpt_rx_crc_errors; stats->rx_frame_errors = n->cpt_rx_frame_errors; stats->rx_fifo_errors = n->cpt_rx_fifo_errors; stats->rx_missed_errors = n->cpt_rx_missed_errors; stats->tx_aborted_errors = n->cpt_tx_aborted_errors; stats->tx_carrier_errors = n->cpt_tx_carrier_errors; stats->tx_fifo_errors = n->cpt_tx_fifo_errors; stats->tx_heartbeat_errors = n->cpt_tx_heartbeat_errors; stats->tx_window_errors = n->cpt_tx_window_errors; stats->rx_compressed = n->cpt_rx_compressed; stats->tx_compressed = n->cpt_tx_compressed; out: preempt_enable(); cpt_release_buf(ctx); return err; }
static void cpt_dump_netstats(struct net_device *dev, struct cpt_context * ctx) { struct cpt_netstats_image *n; struct net_device_stats *stats; if (!dev->netdev_ops->ndo_get_stats) return; n = cpt_get_buf(ctx); stats = dev->netdev_ops->ndo_get_stats(dev); cpt_open_object(NULL, ctx); n->cpt_next = CPT_NULL; n->cpt_object = CPT_OBJ_NET_STATS; n->cpt_hdrlen = sizeof(*n); n->cpt_content = CPT_CONTENT_VOID; n->cpt_rx_packets = stats->rx_packets; n->cpt_tx_packets = stats->tx_packets; n->cpt_rx_bytes = stats->rx_bytes; n->cpt_tx_bytes = stats->tx_bytes; n->cpt_rx_errors = stats->rx_errors; n->cpt_tx_errors = stats->tx_errors; n->cpt_rx_dropped = stats->rx_dropped; n->cpt_tx_dropped = stats->tx_dropped; n->cpt_multicast = stats->multicast; n->cpt_collisions = stats->collisions; n->cpt_rx_length_errors = stats->rx_length_errors; n->cpt_rx_over_errors = stats->rx_over_errors; n->cpt_rx_crc_errors = stats->rx_crc_errors; n->cpt_rx_frame_errors = stats->rx_frame_errors; n->cpt_rx_fifo_errors = stats->rx_fifo_errors; n->cpt_rx_missed_errors = stats->rx_missed_errors; n->cpt_tx_aborted_errors = stats->tx_aborted_errors; n->cpt_tx_carrier_errors = stats->tx_carrier_errors; n->cpt_tx_fifo_errors = stats->tx_fifo_errors; n->cpt_tx_heartbeat_errors = stats->tx_heartbeat_errors; n->cpt_tx_window_errors = stats->tx_window_errors; n->cpt_rx_compressed = stats->rx_compressed; n->cpt_tx_compressed = stats->tx_compressed; ctx->write(n, sizeof(*n), ctx); cpt_close_object(ctx); cpt_release_buf(ctx); return; }
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; }
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; } }
int cpt_dump_tty(cpt_object_t *obj, struct cpt_context *ctx) { struct tty_struct *tty = obj->o_obj; struct cpt_tty_image *v; if (tty->link) { if (lookup_cpt_object(CPT_OBJ_TTY, tty->link, ctx) == NULL) { eprintk_ctx("orphan pty %s %d\n", tty->name, tty->driver->subtype == PTY_TYPE_SLAVE); return -EINVAL; } if (tty->link->link != tty) { eprintk_ctx("bad pty pair\n"); return -EINVAL; } if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_SLAVE && tty->link->count) obj->o_count++; } if (obj->o_count != tty->count) { eprintk_ctx("tty %s is referenced outside %d %d\n", tty->name, obj->o_count, tty->count); return -EBUSY; } cpt_open_object(obj, ctx); v = cpt_get_buf(ctx); v->cpt_next = -1; v->cpt_object = CPT_OBJ_TTY; v->cpt_hdrlen = sizeof(*v); v->cpt_content = CPT_CONTENT_ARRAY; v->cpt_index = tty->index; v->cpt_link = -1; if (tty->link) v->cpt_link = tty->link->index; v->cpt_drv_type = tty->driver->type; v->cpt_drv_subtype = tty->driver->subtype; v->cpt_drv_flags = tty->driver->flags; v->cpt_packet = tty->packet; v->cpt_stopped = tty->stopped; v->cpt_hw_stopped = tty->hw_stopped; v->cpt_flow_stopped = tty->flow_stopped; v->cpt_flags = tty->flags; v->cpt_ctrl_status = tty->ctrl_status; v->cpt_canon_data = tty->canon_data; v->cpt_canon_head = tty->canon_head - tty->read_tail; v->cpt_canon_column = tty->canon_column; v->cpt_column = tty->column; v->cpt_erasing = tty->erasing; v->cpt_lnext = tty->lnext; v->cpt_icanon = tty->icanon; v->cpt_raw = tty->raw; v->cpt_real_raw = tty->real_raw; v->cpt_closing = tty->closing; v->cpt_minimum_to_wake = tty->minimum_to_wake; v->cpt_pgrp = 0; if (tty->pgrp) { v->cpt_pgrp = pid_vnr(tty->pgrp); if ((int)v->cpt_pgrp < 0) { dprintk_ctx("cannot map tty->pgrp %d -> %d\n", pid_vnr(tty->pgrp), (int)v->cpt_pgrp); v->cpt_pgrp = -1; } } v->cpt_session = 0; if (tty->session) { v->cpt_session = pid_vnr(tty->session); if ((int)v->cpt_session < 0) { eprintk_ctx("cannot map tty->session %d -> %d\n", pid_nr(tty->session), (int)v->cpt_session); cpt_release_buf(ctx); return -EINVAL; } } memcpy(v->cpt_name, tty->name, 64); v->cpt_ws_row = tty->winsize.ws_row; v->cpt_ws_col = tty->winsize.ws_col; v->cpt_ws_prow = tty->winsize.ws_ypixel; v->cpt_ws_pcol = tty->winsize.ws_xpixel; if (tty->termios == NULL) { eprintk_ctx("NULL termios"); cpt_release_buf(ctx); return -EINVAL; } v->cpt_c_line = tty->termios->c_line; v->cpt_c_iflag = tty->termios->c_iflag; v->cpt_c_oflag = tty->termios->c_oflag; v->cpt_c_cflag = tty->termios->c_cflag; v->cpt_c_lflag = tty->termios->c_lflag; memcpy(v->cpt_c_cc, tty->termios->c_cc, NCCS); if (NCCS < 32) memset(v->cpt_c_cc + NCCS, 255, 32 - NCCS); memcpy(v->cpt_read_flags, tty->read_flags, sizeof(v->cpt_read_flags)); ctx->write(v, sizeof(*v), ctx); cpt_release_buf(ctx); if (tty->read_buf && tty->read_cnt) { struct cpt_obj_bits *v = cpt_get_buf(ctx); loff_t saved_pos; cpt_push_object(&saved_pos, ctx); cpt_open_object(NULL, ctx); v->cpt_next = CPT_NULL; v->cpt_object = CPT_OBJ_BITS; v->cpt_hdrlen = sizeof(*v); v->cpt_content = CPT_CONTENT_DATA; v->cpt_size = tty->read_cnt; ctx->write(v, sizeof(*v), ctx); cpt_release_buf(ctx); if (tty->read_cnt) { int n = min(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail); ctx->write(tty->read_buf + tty->read_tail, n, ctx); if (tty->read_cnt > n) ctx->write(tty->read_buf, tty->read_cnt-n, ctx); ctx->align(ctx); } cpt_close_object(ctx); cpt_pop_object(&saved_pos, ctx); } cpt_close_object(ctx); return 0; }