コード例 #1
0
ファイル: rst_tty.c プロジェクト: vps2fast/openvz-kernel
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;
}
コード例 #2
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;
}
コード例 #3
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;
}
コード例 #4
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;
}
コード例 #5
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;
}
コード例 #6
0
ファイル: rst_tty.c プロジェクト: vps2fast/openvz-kernel
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;
	}
}
コード例 #7
0
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;
}