linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jiri Slaby <jslaby@suse.cz>
To: gregkh@linuxfoundation.org
Cc: alan@linux.intel.com, linux-kernel@vger.kernel.org,
	jirislaby@gmail.com, Martin Schwidefsky <schwidefsky@de.ibm.com>,
	Heiko Carstens <heiko.carstens@de.ibm.com>,
	linux390@de.ibm.com, linux-s390@vger.kernel.org
Subject: [PATCH 34/69] TTY: tty3270, add tty_port
Date: Mon,  2 Apr 2012 13:54:18 +0200	[thread overview]
Message-ID: <1333367693-3244-35-git-send-email-jslaby@suse.cz> (raw)
In-Reply-To: <1333367693-3244-1-git-send-email-jslaby@suse.cz>

And use tty from that. This means, we convert most of the users to
accept tty_port instead. This is not racy and ensures the tty to be
properly refcounted.

Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: linux390@de.ibm.com
Cc: linux-s390@vger.kernel.org
---
 drivers/s390/char/keyboard.c |   30 ++++++++++++++------------
 drivers/s390/char/keyboard.h |   14 +++++++++---
 drivers/s390/char/tty3270.c  |   48 ++++++++++++++++++------------------------
 3 files changed, 49 insertions(+), 43 deletions(-)

diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c
index 8065881..7ef9cfd 100644
--- a/drivers/s390/char/keyboard.c
+++ b/drivers/s390/char/keyboard.c
@@ -199,7 +199,7 @@ handle_diacr(struct kbd_data *kbd, unsigned int ch)
 	if (ch == ' ' || ch == d)
 		return d;
 
-	kbd_put_queue(kbd->tty, d);
+	kbd_put_queue(kbd->port, d);
 	return ch;
 }
 
@@ -221,7 +221,7 @@ k_self(struct kbd_data *kbd, unsigned char value)
 {
 	if (kbd->diacr)
 		value = handle_diacr(kbd, value);
-	kbd_put_queue(kbd->tty, value);
+	kbd_put_queue(kbd->port, value);
 }
 
 /*
@@ -239,7 +239,7 @@ static void
 k_fn(struct kbd_data *kbd, unsigned char value)
 {
 	if (kbd->func_table[value])
-		kbd_puts_queue(kbd->tty, kbd->func_table[value]);
+		kbd_puts_queue(kbd->port, kbd->func_table[value]);
 }
 
 static void
@@ -257,20 +257,20 @@ k_spec(struct kbd_data *kbd, unsigned char value)
  * but we need only 16 bits here
  */
 static void
-to_utf8(struct tty_struct *tty, ushort c) 
+to_utf8(struct tty_port *port, ushort c)
 {
 	if (c < 0x80)
 		/*  0******* */
-		kbd_put_queue(tty, c);
+		kbd_put_queue(port, c);
 	else if (c < 0x800) {
 		/* 110***** 10****** */
-		kbd_put_queue(tty, 0xc0 | (c >> 6));
-		kbd_put_queue(tty, 0x80 | (c & 0x3f));
+		kbd_put_queue(port, 0xc0 | (c >> 6));
+		kbd_put_queue(port, 0x80 | (c & 0x3f));
 	} else {
 		/* 1110**** 10****** 10****** */
-		kbd_put_queue(tty, 0xe0 | (c >> 12));
-		kbd_put_queue(tty, 0x80 | ((c >> 6) & 0x3f));
-		kbd_put_queue(tty, 0x80 | (c & 0x3f));
+		kbd_put_queue(port, 0xe0 | (c >> 12));
+		kbd_put_queue(port, 0x80 | ((c >> 6) & 0x3f));
+		kbd_put_queue(port, 0x80 | (c & 0x3f));
 	}
 }
 
@@ -283,7 +283,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode)
 	unsigned short keysym;
 	unsigned char type, value;
 
-	if (!kbd || !kbd->tty)
+	if (!kbd)
 		return;
 
 	if (keycode >= 384)
@@ -323,7 +323,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode)
 #endif
 		(*k_handler[type])(kbd, value);
 	} else
-		to_utf8(kbd->tty, keysym);
+		to_utf8(kbd->port, keysym);
 }
 
 /*
@@ -457,6 +457,7 @@ do_kdgkb_ioctl(struct kbd_data *kbd, struct kbsentry __user *u_kbs,
 
 int kbd_ioctl(struct kbd_data *kbd, unsigned int cmd, unsigned long arg)
 {
+	struct tty_struct *tty;
 	void __user *argp;
 	unsigned int ct;
 	int perm;
@@ -467,7 +468,10 @@ int kbd_ioctl(struct kbd_data *kbd, unsigned int cmd, unsigned long arg)
 	 * To have permissions to do most of the vt ioctls, we either have
 	 * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG.
 	 */
-	perm = current->signal->tty == kbd->tty || capable(CAP_SYS_TTY_CONFIG);
+	tty = tty_port_tty_get(kbd->port);
+	/* FIXME this test is pretty racy */
+	perm = current->signal->tty == tty || capable(CAP_SYS_TTY_CONFIG);
+	tty_kref_put(tty);
 	switch (cmd) {
 	case KDGKBTYPE:
 		return put_user(KB_101, (char __user *)argp);
diff --git a/drivers/s390/char/keyboard.h b/drivers/s390/char/keyboard.h
index 7e736aa..f682f4e 100644
--- a/drivers/s390/char/keyboard.h
+++ b/drivers/s390/char/keyboard.h
@@ -21,7 +21,7 @@ typedef void (fn_handler_fn)(struct kbd_data *);
  */
 
 struct kbd_data {
-	struct tty_struct *tty;
+	struct tty_port *port;
 	unsigned short **key_maps;
 	char **func_table;
 	fn_handler_fn **fn_handler;
@@ -42,16 +42,24 @@ int kbd_ioctl(struct kbd_data *, unsigned int, unsigned long);
  * Helper Functions.
  */
 static inline void
-kbd_put_queue(struct tty_struct *tty, int ch)
+kbd_put_queue(struct tty_port *port, int ch)
 {
+	struct tty_struct *tty = tty_port_tty_get(port);
+	if (!tty)
+		return;
 	tty_insert_flip_char(tty, ch, 0);
 	tty_schedule_flip(tty);
+	tty_kref_put(tty);
 }
 
 static inline void
-kbd_puts_queue(struct tty_struct *tty, char *cp)
+kbd_puts_queue(struct tty_port *port, char *cp)
 {
+	struct tty_struct *tty = tty_port_tty_get(port);
+	if (!tty)
+		return;
 	while (*cp)
 		tty_insert_flip_char(tty, *cp++, 0);
 	tty_schedule_flip(tty);
+	tty_kref_put(tty);
 }
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index 1f4aff7..10ec690 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -61,7 +61,7 @@ struct tty3270_line {
  */
 struct tty3270 {
 	struct raw3270_view view;
-	struct tty_struct *tty;		/* Pointer to tty structure */
+	struct tty_port port;
 	void **freemem_pages;		/* Array of pages used for freemem. */
 	struct list_head freemem;	/* List of free memory for strings. */
 
@@ -449,10 +449,9 @@ tty3270_rcl_add(struct tty3270 *tp, char *input, int len)
 static void
 tty3270_rcl_backward(struct kbd_data *kbd)
 {
-	struct tty3270 *tp;
+	struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
 	struct string *s;
 
-	tp = kbd->tty->driver_data;
 	spin_lock_bh(&tp->view.lock);
 	if (tp->inattr == TF_INPUT) {
 		if (tp->rcl_walk && tp->rcl_walk->prev != &tp->rcl_lines)
@@ -477,9 +476,8 @@ tty3270_rcl_backward(struct kbd_data *kbd)
 static void
 tty3270_exit_tty(struct kbd_data *kbd)
 {
-	struct tty3270 *tp;
+	struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
 
-	tp = kbd->tty->driver_data;
 	raw3270_deactivate_view(&tp->view);
 }
 
@@ -489,10 +487,9 @@ tty3270_exit_tty(struct kbd_data *kbd)
 static void
 tty3270_scroll_forward(struct kbd_data *kbd)
 {
-	struct tty3270 *tp;
+	struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
 	int nr_up;
 
-	tp = kbd->tty->driver_data;
 	spin_lock_bh(&tp->view.lock);
 	nr_up = tp->nr_up - tp->view.rows + 2;
 	if (nr_up < 0)
@@ -512,10 +509,9 @@ tty3270_scroll_forward(struct kbd_data *kbd)
 static void
 tty3270_scroll_backward(struct kbd_data *kbd)
 {
-	struct tty3270 *tp;
+	struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
 	int nr_up;
 
-	tp = kbd->tty->driver_data;
 	spin_lock_bh(&tp->view.lock);
 	nr_up = tp->nr_up + tp->view.rows - 2;
 	if (nr_up + tp->view.rows - 2 > tp->nr_lines)
@@ -575,13 +571,10 @@ tty3270_read_tasklet(struct raw3270_request *rrq)
 	raw3270_request_add_data(tp->kreset, &kreset_data, 1);
 	raw3270_start(&tp->view, tp->kreset);
 
-	/* Emit input string. */
-	if (tp->tty) {
-		while (len-- > 0)
-			kbd_keycode(tp->kbd, *input++);
-		/* Emit keycode for AID byte. */
-		kbd_keycode(tp->kbd, 256 + tp->input->string[0]);
-	}
+	while (len-- > 0)
+		kbd_keycode(tp->kbd, *input++);
+	/* Emit keycode for AID byte. */
+	kbd_keycode(tp->kbd, 256 + tp->input->string[0]);
 
 	raw3270_request_reset(rrq);
 	xchg(&tp->read, rrq);
@@ -691,6 +684,7 @@ tty3270_alloc_view(void)
 	INIT_LIST_HEAD(&tp->update);
 	INIT_LIST_HEAD(&tp->rcl_lines);
 	tp->rcl_max = 20;
+	tty_port_init(&tp->port);
 	setup_timer(&tp->timer, (void (*)(unsigned long)) tty3270_update,
 		    (unsigned long) tp);
 	tasklet_init(&tp->readlet,
@@ -802,14 +796,14 @@ static void
 tty3270_release(struct raw3270_view *view)
 {
 	struct tty3270 *tp = container_of(view, struct tty3270, view);
-	struct tty_struct *tty;
+	struct tty_struct *tty = tty_port_tty_get(&tp->port);
 
-	tty = tp->tty;
 	if (tty) {
 		tty->driver_data = NULL;
-		tp->tty = tp->kbd->tty = NULL;
+		tty_port_tty_set(&tp->port, NULL);
 		tty_hangup(tty);
 		raw3270_put_view(&tp->view);
+		tty_kref_put(tty);
 	}
 }
 
@@ -869,8 +863,8 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
 		tty->winsize.ws_row = tp->view.rows - 2;
 		tty->winsize.ws_col = tp->view.cols;
 		tty->low_latency = 0;
-		tp->tty = tty;
-		tp->kbd->tty = tty;
+		/* why to reassign? */
+		tty_port_tty_set(&tp->port, tty);
 		tp->inattr = TF_INPUT;
 		return 0;
 	}
@@ -900,7 +894,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
 		return rc;
 	}
 
-	tp->tty = tty;
+	tty_port_tty_set(&tp->port, tty);
 	tty->low_latency = 0;
 	tty->driver_data = tp;
 	tty->winsize.ws_row = tp->view.rows - 2;
@@ -914,7 +908,7 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
 	for (i = 0; i < tp->view.rows - 2; i++)
 		tty3270_blank_line(tp);
 
-	tp->kbd->tty = tty;
+	tp->kbd->port = &tp->port;
 	tp->kbd->fn_handler[KVAL(K_INCRCONSOLE)] = tty3270_exit_tty;
 	tp->kbd->fn_handler[KVAL(K_SCROLLBACK)] = tty3270_scroll_backward;
 	tp->kbd->fn_handler[KVAL(K_SCROLLFORW)] = tty3270_scroll_forward;
@@ -938,7 +932,7 @@ tty3270_close(struct tty_struct *tty, struct file * filp)
 		return;
 	if (tp) {
 		tty->driver_data = NULL;
-		tp->tty = tp->kbd->tty = NULL;
+		tty_port_tty_set(&tp->port, NULL);
 		raw3270_put_view(&tp->view);
 	}
 }
@@ -1387,7 +1381,7 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch)
 			tty3270_lf(tp);
 			break;
 		case 'Z':		/* Respond ID. */
-			kbd_puts_queue(tp->tty, "\033[?6c");
+			kbd_puts_queue(&tp->port, "\033[?6c");
 			break;
 		case '7':		/* Save cursor position. */
 			tp->saved_cx = tp->cx;
@@ -1433,11 +1427,11 @@ tty3270_escape_sequence(struct tty3270 *tp, char ch)
 	tp->esc_state = ESnormal;
 	if (ch == 'n' && !tp->esc_ques) {
 		if (tp->esc_par[0] == 5)		/* Status report. */
-			kbd_puts_queue(tp->tty, "\033[0n");
+			kbd_puts_queue(&tp->port, "\033[0n");
 		else if (tp->esc_par[0] == 6) {	/* Cursor report. */
 			char buf[40];
 			sprintf(buf, "\033[%d;%dR", tp->cy + 1, tp->cx + 1);
-			kbd_puts_queue(tp->tty, buf);
+			kbd_puts_queue(&tp->port, buf);
 		}
 		return;
 	}
-- 
1.7.9.2



  parent reply	other threads:[~2012-04-02 11:56 UTC|newest]

Thread overview: 81+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-04-02 11:53 [PATCH 00/69] TTY buffer in tty_port -- prep no. 2 Jiri Slaby
2012-04-02 11:53 ` [PATCH 01/69] TTY: crisv10, remove unused tmp_buf Jiri Slaby
2012-04-03 11:47   ` Jesper Nilsson
2012-04-02 11:53 ` [PATCH 02/69] TTY: crisv10, initialize tty_port Jiri Slaby
2012-04-03 11:47   ` Jesper Nilsson
2012-04-02 11:53 ` [PATCH 03/69] TTY: deprecate linux/generic_serial.h Jiri Slaby
2012-04-02 11:53 ` [PATCH 04/69] ISDN: i4l, remove cvs crap Jiri Slaby
2012-04-02 11:53 ` [PATCH 05/69] TTY: isdn, remove callout Jiri Slaby
2012-04-02 11:53 ` [PATCH 06/69] TTY: isdn, remove ISDN_ASYNC_* flags Jiri Slaby
2012-04-02 11:53 ` [PATCH 07/69] TTY: isdn, do not play with module refcounts Jiri Slaby
2012-04-02 11:53 ` [PATCH 08/69] TTY: isdn, make some functions readable Jiri Slaby
2012-04-02 11:53 ` [PATCH 09/69] TTY: isdn, remove unused members from modem_info Jiri Slaby
2012-04-02 11:53 ` [PATCH 10/69] TTY: isdn, add tty_port Jiri Slaby
2012-04-02 11:53 ` [PATCH 11/69] TTY: isdn, use open/close_wait from tty_port Jiri Slaby
2012-04-02 11:53 ` [PATCH 12/69] TTY: isdn, use counts " Jiri Slaby
2012-04-02 11:53 ` [PATCH 13/69] TTY: isdn, use tty " Jiri Slaby
2012-04-02 11:53 ` [PATCH 14/69] TTY: isdn, use xmit_buf " Jiri Slaby
2012-04-02 11:53 ` [PATCH 15/69] TTY: isdn, define local tty_port Jiri Slaby
2012-04-02 11:54 ` [PATCH 16/69] TTY: isdn, use tty_port_close_end helper Jiri Slaby
2012-04-02 11:54 ` [PATCH 17/69] TTY: isdn, define tty_port_operations Jiri Slaby
2012-04-02 11:54 ` [PATCH 18/69] TTY: isdn, use tty_port_block_til_ready helper Jiri Slaby
2012-04-02 11:54 ` [PATCH 19/69] TTY: hso, do not set TTY MAGIC Jiri Slaby
2012-04-02 11:54 ` [PATCH 20/69] TTY: hso, free tty_driver Jiri Slaby
2012-04-02 11:54 ` [PATCH 21/69] TTY: hso, add tty_port Jiri Slaby
2012-04-02 11:54 ` [PATCH 22/69] TTY: hso, remove tty NULL checks fro tty->ops Jiri Slaby
2012-04-02 11:54 ` [PATCH 23/69] TTY: hso, use tty from tty_port Jiri Slaby
2012-04-02 11:54 ` [PATCH 24/69] TTY: con3215, centralize allocation Jiri Slaby
2012-04-03  5:56   ` Heiko Carstens
2012-04-02 11:54 ` [PATCH 25/69] TTY: con3215, remove tasklet for tty_wakeup Jiri Slaby
2012-04-03  5:42   ` Heiko Carstens
2012-04-03  7:59     ` Jiri Slaby
2012-04-09 18:27       ` Greg KH
2012-04-09 18:30         ` Jiri Slaby
2012-04-09 19:07           ` Greg KH
2012-04-02 11:54 ` [PATCH 26/69] TTY: con3215, add tty_port Jiri Slaby
2012-04-02 11:54 ` [PATCH 27/69] TTY: con3215, use tty from tty_port Jiri Slaby
2012-04-02 11:54 ` [PATCH 28/69] TTY: sclp_tty, add tty_port Jiri Slaby
2012-04-02 11:54 ` [PATCH 29/69] TTY: sclp_vt220, " Jiri Slaby
2012-04-02 11:54 ` [PATCH 30/69] TTY: sclp_vt220, remove unused allocation Jiri Slaby
2012-04-02 11:54 ` [PATCH 31/69] TTY: tty3270, move initialization to allocation Jiri Slaby
2012-04-02 11:54 ` [PATCH 32/69] TTY: tty3270, get rid of ugly aliasing Jiri Slaby
2012-04-02 11:54 ` [PATCH 33/69] TTY: tty3270, push tty down to tty3270_do_write Jiri Slaby
2012-04-02 11:54 ` Jiri Slaby [this message]
2012-04-02 11:54 ` [PATCH 35/69] TTY: bfin_jtag_comm, add tty_port Jiri Slaby
2012-04-02 11:54 ` [PATCH 36/69] TTY: bfin_jtag_comm, use tty from tty_port Jiri Slaby
2012-04-02 11:54 ` [PATCH 37/69] TTY: HVC, add tty_port Jiri Slaby
2012-04-02 11:54 ` [PATCH 38/69] TTY: HVC, use tty from tty_port Jiri Slaby
2012-04-02 11:54 ` [PATCH 39/69] TTY: HVC, use count " Jiri Slaby
2012-04-02 11:54 ` [PATCH 40/69] TTY: hvcs, add tty_port Jiri Slaby
2012-04-02 11:54 ` [PATCH 41/69] TTY: hvcs, use kref from tty_port Jiri Slaby
2012-04-02 11:54 ` [PATCH 42/69] TTY: hvcs, use tty " Jiri Slaby
2012-04-02 11:54 ` [PATCH 43/69] TTY: hvsi, CLOCAL is not in tty->flags Jiri Slaby
2012-04-02 11:54 ` [PATCH 44/69] TTY: hvsi, add tty_port Jiri Slaby
2012-04-02 11:54 ` [PATCH 45/69] TTY: hvsi, sanitize uses of tty Jiri Slaby
2012-04-02 11:54 ` [PATCH 46/69] TTY: hvsi, use tty from tty_port Jiri Slaby
2012-04-02 11:54 ` [PATCH 47/69] TTY: ipwireless, use synchronous hangup Jiri Slaby
2012-04-02 12:42   ` David Sterba
2012-04-02 11:54 ` [PATCH 48/69] TTY: ipwireless, move prints to appropriate places Jiri Slaby
2012-04-02 11:54 ` [PATCH 49/69] TTY: ipwireless, add tty_port Jiri Slaby
2012-04-02 11:54 ` [PATCH 50/69] TTY: ipwireless, use tty from tty_port Jiri Slaby
2012-04-02 11:54 ` [PATCH 51/69] TTY: 68328serial, remove serial_state and friends Jiri Slaby
2012-04-03 12:48   ` Geert Uytterhoeven
2012-04-02 11:54 ` [PATCH 52/69] TTY: 68328serial, remove unused stuff from m68k_serial Jiri Slaby
2012-04-02 11:54 ` [PATCH 53/69] TTY: 68328serial, remove garbage Jiri Slaby
2012-04-02 11:54 ` [PATCH 54/69] TTY: 68328serial, use ulong flags for interrupts status Jiri Slaby
2012-04-02 11:54 ` [PATCH 55/69] TTY: 68328serial, remove 68328serial.h Jiri Slaby
2012-04-02 11:54 ` [PATCH 56/69] TTY: 68328serial, add tty_port Jiri Slaby
2012-04-02 11:54 ` [PATCH 57/69] TTY: 68328serial, use open/close_wait from tty_port Jiri Slaby
2012-04-02 11:54 ` [PATCH 58/69] TTY: 68328serial, use close_delay/closing_wait " Jiri Slaby
2012-04-02 11:54 ` [PATCH 59/69] TTY: 68328serial, use flags " Jiri Slaby
2012-04-02 11:54 ` [PATCH 60/69] TTY: 68328serial, propagate tty Jiri Slaby
2012-04-02 11:54 ` [PATCH 61/69] TTY: 68328serial, use tty from tty_port Jiri Slaby
2012-04-02 11:54 ` [PATCH 62/69] TTY: 68328serial, use tty_port_block_til_ready Jiri Slaby
2012-04-04 12:25   ` Greg Ungerer
2012-04-02 11:54 ` [PATCH 63/69] TTY: usb/u_serial, add tty_port Jiri Slaby
2012-04-02 11:54 ` [PATCH 64/69] TTY: usb/u_serial, use tty from tty_port Jiri Slaby
2012-04-02 11:54 ` [PATCH 65/69] TTY: usb/u_serial use close_wait " Jiri Slaby
2012-04-02 11:54 ` [PATCH 66/69] TTY: rfcomm/tty, add tty_port Jiri Slaby
2012-04-02 11:54 ` [PATCH 67/69] TTY: rfcomm/tty, use tty_port refcounting Jiri Slaby
2012-04-02 11:54 ` [PATCH 68/69] TTY: rfcomm/tty, remove work for tty_wakeup Jiri Slaby
2012-04-02 11:54 ` [PATCH 69/69] TTY: rfcomm/tty, use count from tty_port Jiri Slaby

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1333367693-3244-35-git-send-email-jslaby@suse.cz \
    --to=jslaby@suse.cz \
    --cc=alan@linux.intel.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=heiko.carstens@de.ibm.com \
    --cc=jirislaby@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-s390@vger.kernel.org \
    --cc=linux390@de.ibm.com \
    --cc=schwidefsky@de.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).