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; }
static int restore_unix_rqueue(struct sock *sk, struct cpt_sock_image *si, loff_t pos, struct cpt_context *ctx) { loff_t endpos; pos = pos + si->cpt_hdrlen; endpos = pos + si->cpt_next; while (pos < endpos) { struct sk_buff *skb; struct sock *owner_sk; __u32 owner; skb = rst_skb(sk, &pos, &owner, NULL, ctx); if (IS_ERR(skb)) { if (PTR_ERR(skb) == -EINVAL) { int err; err = rst_sock_attr(&pos, sk, ctx); if (err) return err; } return PTR_ERR(skb); } owner_sk = unix_peer(sk); if (owner != -1) { cpt_object_t *pobj; pobj = lookup_cpt_obj_byindex(CPT_OBJ_SOCKET, owner, ctx); if (pobj == NULL) { eprintk_ctx("orphan af_unix skb?\n"); kfree_skb(skb); continue; } owner_sk = pobj->o_obj; } if (owner_sk == NULL) { dprintk_ctx("orphan af_unix skb 2?\n"); kfree_skb(skb); continue; } skb_set_owner_w(skb, owner_sk); if (UNIXCB(skb).fp) skb->destructor = unix_destruct_fds; skb_queue_tail(&sk->sk_receive_queue, skb); if (sk->sk_state == TCP_LISTEN) { struct socket *sock = skb->sk->sk_socket; if (sock == NULL) BUG(); if (sock->file) BUG(); skb->sk->sk_socket = NULL; skb->sk->sk_sleep = NULL; sock->sk = NULL; sock_release(sock); } } 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; }
static int rst_socket_tcp(struct cpt_sock_image *si, loff_t pos, struct sock *sk, struct cpt_context *ctx) { struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *skb; tp->pred_flags = si->cpt_pred_flags; tp->rcv_nxt = si->cpt_rcv_nxt; tp->snd_nxt = si->cpt_snd_nxt; tp->snd_una = si->cpt_snd_una; tp->snd_sml = si->cpt_snd_sml; tp->rcv_tstamp = tcp_jiffies_import(si->cpt_rcv_tstamp); tp->lsndtime = tcp_jiffies_import(si->cpt_lsndtime); tp->tcp_header_len = si->cpt_tcp_header_len; inet_csk(sk)->icsk_ack.pending = si->cpt_ack_pending; inet_csk(sk)->icsk_ack.quick = si->cpt_quick; inet_csk(sk)->icsk_ack.pingpong = si->cpt_pingpong; inet_csk(sk)->icsk_ack.blocked = si->cpt_blocked; inet_csk(sk)->icsk_ack.ato = si->cpt_ato; inet_csk(sk)->icsk_ack.timeout = jiffies_import(si->cpt_ack_timeout); inet_csk(sk)->icsk_ack.lrcvtime = tcp_jiffies_import(si->cpt_lrcvtime); inet_csk(sk)->icsk_ack.last_seg_size = si->cpt_last_seg_size; inet_csk(sk)->icsk_ack.rcv_mss = si->cpt_rcv_mss; tp->snd_wl1 = si->cpt_snd_wl1; tp->snd_wnd = si->cpt_snd_wnd; tp->max_window = si->cpt_max_window; inet_csk(sk)->icsk_pmtu_cookie = si->cpt_pmtu_cookie; tp->mss_cache = si->cpt_mss_cache; tp->rx_opt.mss_clamp = si->cpt_mss_clamp; inet_csk(sk)->icsk_ext_hdr_len = si->cpt_ext_header_len; inet_csk(sk)->icsk_ca_state = si->cpt_ca_state; inet_csk(sk)->icsk_retransmits = si->cpt_retransmits; tp->reordering = si->cpt_reordering; tp->frto_counter = si->cpt_frto_counter; tp->frto_highmark = si->cpt_frto_highmark; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) // // tp->adv_cong = si->cpt_adv_cong; #endif inet_csk(sk)->icsk_accept_queue.rskq_defer_accept = si->cpt_defer_accept; inet_csk(sk)->icsk_backoff = si->cpt_backoff; tp->srtt = si->cpt_srtt; tp->mdev = si->cpt_mdev; tp->mdev_max = si->cpt_mdev_max; tp->rttvar = si->cpt_rttvar; tp->rtt_seq = si->cpt_rtt_seq; inet_csk(sk)->icsk_rto = si->cpt_rto; tp->packets_out = si->cpt_packets_out; tp->retrans_out = si->cpt_retrans_out; tp->lost_out = si->cpt_lost_out; tp->sacked_out = si->cpt_sacked_out; tp->fackets_out = si->cpt_fackets_out; tp->snd_ssthresh = si->cpt_snd_ssthresh; tp->snd_cwnd = si->cpt_snd_cwnd; tp->snd_cwnd_cnt = si->cpt_snd_cwnd_cnt; tp->snd_cwnd_clamp = si->cpt_snd_cwnd_clamp; tp->snd_cwnd_used = si->cpt_snd_cwnd_used; tp->snd_cwnd_stamp = tcp_jiffies_import(si->cpt_snd_cwnd_stamp); inet_csk(sk)->icsk_timeout = tcp_jiffies_import(si->cpt_timeout); tp->rcv_wnd = si->cpt_rcv_wnd; tp->rcv_wup = si->cpt_rcv_wup; tp->write_seq = si->cpt_write_seq; tp->pushed_seq = si->cpt_pushed_seq; tp->copied_seq = si->cpt_copied_seq; tp->rx_opt.tstamp_ok = si->cpt_tstamp_ok; tp->rx_opt.wscale_ok = si->cpt_wscale_ok; tp->rx_opt.sack_ok = si->cpt_sack_ok; tp->rx_opt.saw_tstamp = si->cpt_saw_tstamp; tp->rx_opt.snd_wscale = si->cpt_snd_wscale; tp->rx_opt.rcv_wscale = si->cpt_rcv_wscale; tp->nonagle = si->cpt_nonagle; tp->keepalive_probes = si->cpt_keepalive_probes; tp->rx_opt.rcv_tsval = si->cpt_rcv_tsval; tp->rx_opt.rcv_tsecr = si->cpt_rcv_tsecr; tp->rx_opt.ts_recent = si->cpt_ts_recent; tp->rx_opt.ts_recent_stamp = si->cpt_ts_recent_stamp; tp->rx_opt.user_mss = si->cpt_user_mss; tp->rx_opt.dsack = si->cpt_dsack; tp->duplicate_sack[0].start_seq = si->cpt_sack_array[0]; tp->duplicate_sack[0].end_seq = si->cpt_sack_array[1]; tp->selective_acks[0].start_seq = si->cpt_sack_array[2]; tp->selective_acks[0].end_seq = si->cpt_sack_array[3]; tp->selective_acks[1].start_seq = si->cpt_sack_array[4]; tp->selective_acks[1].end_seq = si->cpt_sack_array[5]; tp->selective_acks[2].start_seq = si->cpt_sack_array[6]; tp->selective_acks[2].end_seq = si->cpt_sack_array[7]; tp->selective_acks[3].start_seq = si->cpt_sack_array[8]; tp->selective_acks[3].end_seq = si->cpt_sack_array[9]; tp->window_clamp = si->cpt_window_clamp; tp->rcv_ssthresh = si->cpt_rcv_ssthresh; inet_csk(sk)->icsk_probes_out = si->cpt_probes_out; tp->rx_opt.num_sacks = si->cpt_num_sacks; tp->advmss = si->cpt_advmss; inet_csk(sk)->icsk_syn_retries = si->cpt_syn_retries; tp->ecn_flags = si->cpt_ecn_flags; tp->prior_ssthresh = si->cpt_prior_ssthresh; tp->high_seq = si->cpt_high_seq; tp->retrans_stamp = si->cpt_retrans_stamp; tp->undo_marker = si->cpt_undo_marker; tp->undo_retrans = si->cpt_undo_retrans; tp->urg_seq = si->cpt_urg_seq; tp->urg_data = si->cpt_urg_data; inet_csk(sk)->icsk_pending = si->cpt_pending; tp->snd_up = si->cpt_snd_up; tp->keepalive_time = si->cpt_keepalive_time; tp->keepalive_intvl = si->cpt_keepalive_intvl; tp->linger2 = si->cpt_linger2; sk->sk_send_head = NULL; for (skb = skb_peek(&sk->sk_write_queue); skb && skb != (struct sk_buff*)&sk->sk_write_queue; skb = skb->next) { if (!after(tp->snd_nxt, TCP_SKB_CB(skb)->seq)) { sk->sk_send_head = skb; break; } } if (sk->sk_state != TCP_CLOSE && sk->sk_state != TCP_LISTEN) { struct inet_sock *inet = inet_sk(sk); if (inet->num == 0) { cpt_object_t *lobj = NULL; if ((int)si->cpt_parent != -1) lobj = lookup_cpt_obj_byindex(CPT_OBJ_SOCKET, si->cpt_parent, ctx); if (lobj && lobj->o_obj) { inet->num = ntohs(inet->sport); local_bh_disable(); __inet_inherit_port(lobj->o_obj, sk); local_bh_enable(); dprintk_ctx("port inherited from parent\n"); } else { struct sock *lsk = find_parent(inet->sport, ctx); if (lsk) { inet->num = ntohs(inet->sport); local_bh_disable(); __inet_inherit_port(lsk, sk); local_bh_enable(); dprintk_ctx("port inherited\n"); } else { eprintk_ctx("we are kinda lost...\n"); } } } sk->sk_prot->hash(sk); if (inet_csk(sk)->icsk_ack.pending&ICSK_ACK_TIMER) sk_reset_timer(sk, &inet_csk(sk)->icsk_delack_timer, inet_csk(sk)->icsk_ack.timeout); if (inet_csk(sk)->icsk_pending) sk_reset_timer(sk, &inet_csk(sk)->icsk_retransmit_timer, inet_csk(sk)->icsk_timeout); if (sock_flag(sk, SOCK_KEEPOPEN)) { unsigned long expires = jiffies_import(si->cpt_ka_timeout); if (time_after(jiffies, expires)) expires = jiffies + HZ; sk_reset_timer(sk, &sk->sk_timer, expires); } } if (sk->sk_family == AF_INET6) sk->sk_gso_type = SKB_GSO_TCPV6; else sk->sk_gso_type = SKB_GSO_TCPV4; return 0; }
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; } }
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; }