error_message.c revision ec84b746f553f150935f82dd8d487517fcad745b
15c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu/*
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * $Header$
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * $Source$
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * $Locker$
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) *
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Copyright 1987 by the Student Information Processing Board
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * of the Massachusetts Institute of Technology
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Permission to use, copy, modify, and distribute this software and
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * its documentation for any purpose is hereby granted, provided that
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * the names of M.I.T. and the M.I.T. S.I.P.B. not be used in
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * advertising or publicity pertaining to distribution of the software
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * without specific, written prior permission.  M.I.T. and the
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * M.I.T. S.I.P.B. make no representations about the suitability of
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * this software for any purpose.  It is provided "as is" without
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * express or implied warranty.
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdlib.h>
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <errno.h>
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef HAVE_SYS_PRCTL_H
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/prctl.h>
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define PR_GET_DUMPABLE 3
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if (!defined(HAVE_PRCTL) && defined(linux))
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <sys/syscall.h>
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "com_err.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "error_table.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "internal.h"
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static char buffer[25];
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct et_list * _et_list = (struct et_list *) NULL;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct et_list * _et_dynamic_list = (struct et_list *) NULL;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char * error_message (errcode_t code)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int offset;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    struct et_list *et;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    errcode_t table_num;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int started = 0;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    char *cp;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    offset = (int) (code & ((1<<ERRCODE_RANGE)-1));
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    table_num = code - offset;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!table_num) {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef HAS_SYS_ERRLIST
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (offset < sys_nerr)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    return(sys_errlist[offset]);
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	else
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    goto oops;
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	cp = strerror(offset);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (cp)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    return(cp);
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	else
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    goto oops;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (et = _et_list; et; et = et->next) {
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (et->table->base == table_num) {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    /* This is the right table */
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    if (et->table->n_msgs <= offset)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		goto oops;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    return(et->table->msgs[offset]);
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (et = _et_dynamic_list; et; et = et->next) {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (et->table->base == table_num) {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    /* This is the right table */
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    if (et->table->n_msgs <= offset)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		goto oops;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	    return(et->table->msgs[offset]);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)oops:
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    strcpy (buffer, "Unknown code ");
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (table_num) {
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)	strcat (buffer, error_table_name (table_num));
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	strcat (buffer, " ");
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (cp = buffer; *cp; cp++)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	;
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (offset >= 100) {
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	*cp++ = '0' + offset / 100;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	offset %= 100;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	started++;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (started || offset >= 10) {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	*cp++ = '0' + offset / 10;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	offset %= 10;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *cp++ = '0' + offset;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *cp = '\0';
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return(buffer);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This routine will only return a value if the we are not running as
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * a privileged process.
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static char *safe_getenv(const char *arg)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if ((getuid() != geteuid()) || (getgid() != getegid()))
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return NULL;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if HAVE_PRCTL
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (prctl(PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return NULL;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if (defined(linux) && defined(SYS_prctl))
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (syscall(SYS_prctl, PR_GET_DUMPABLE, 0, 0, 0, 0) == 0)
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return NULL;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef HAVE___SECURE_GETENV
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return __secure_getenv(arg);
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#else
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return getenv(arg);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define DEBUG_INIT	0x8000
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define DEBUG_ADDREMOVE 0x0001
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int debug_mask = 0;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static FILE *debug_f = 0;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void init_debug(void)
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles){
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	char *dstr;
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	char *fn;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (debug_mask & DEBUG_INIT)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	dstr = getenv("COMERR_DEBUG");
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (dstr)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		debug_mask = strtoul(dstr, 0, 0);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	fn = safe_getenv("COMERR_DEBUG_FILE");
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (fn)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		debug_f = fopen(fn, "a");
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (!debug_f)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		debug_f = fopen("/dev/tty", "a");
1514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)	if (!debug_f)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		debug_mask = 0;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	debug_mask |= DEBUG_INIT;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * New interface provided by krb5's com_err library
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)errcode_t add_error_table(const struct error_table * et)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct et_list *el;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (!(el = (struct et_list *) malloc(sizeof(struct et_list))))
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		return ENOMEM;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	el->table = et;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	el->next = _et_dynamic_list;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	_et_dynamic_list = el;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	init_debug();
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (debug_mask & DEBUG_ADDREMOVE)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		fprintf(debug_f, "add_error_table: %s (0x%p)\n",
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			error_table_name(et->base),
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			(const void *) et);
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return 0;
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * New interface provided by krb5's com_err library
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)errcode_t remove_error_table(const struct error_table * et)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct et_list *el = _et_dynamic_list;
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	struct et_list *el2 = 0;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	init_debug();
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	while (el) {
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		if (el->table->base == et->base) {
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			if (el2)	/* Not the beginning of the list */
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				el2->next = el->next;
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			else
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				_et_dynamic_list = el->next;
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			(void) free(el);
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			if (debug_mask & DEBUG_ADDREMOVE)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)				fprintf(debug_f,
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					"remove_error_table: %s (0x%p)\n",
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					error_table_name(et->base),
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)					(const void *) et);
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			return 0;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		}
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		el2 = el;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		el = el->next;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	}
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	if (debug_mask & DEBUG_ADDREMOVE)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)		fprintf(debug_f, "remove_error_table FAILED: %s (0x%p)\n",
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			error_table_name(et->base),
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)			(const void *) et);
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	return ENOENT;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Variant of the interface provided by Heimdal's com_err library
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)add_to_error_table(struct et_list *new_table)
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)	add_error_table(new_table->table);
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)