/*
 *  krt_symbols_nlist.c,v 1.10 1993/12/15 03:48:21 jch Exp
 */

/* Gated Release 3.5 */
/* Copyright (c) 1990,1991,1992,1993,1994 by Cornell University. All rights */
/* reserved. Refer to Particulars and other Copyright notices at the end of this */
/* file. */


#define	INCLUDE_FILE
#define	INCLUDE_NLIST
#define	INCLUDE_KVM
#include "include.h"
#ifdef	PROTO_INET
#include "inet.h"
#endif	/* PROTO_INET */
#include "krt.h"
#include "krt_var.h"


#ifdef	PROTO_INET
static struct nlist *krt_ipforwarding;
static struct nlist *krt_udpcksum;
#endif	/* PROTO_INET */

static struct nlist *krt_version;

static struct {
    const char *nl_name;
    struct nlist **nl_ptr;
} nl_names[] = {
#ifdef	KRT_RTREAD_KMEM
    {"_rthost", &krt_rthash[KRT_RTHOST]},
    {"_rtnet", &krt_rthash[KRT_RTNET]},
    {"_rthashsize", &krt_rthashsize},
#endif	/* KRT_RTREAD_KMEM */
#ifdef	KRT_RTREAD_RADIX
    {"_radix_node_head", &krt_radix_head},
#endif	/* KRT_RTREAD_RADIX */
#ifdef	KRT_LLADDR_KMEM
    {"_ifnet", &krt_ifnet},
#endif	/* KRT_LLADDR_KMEM */
#ifdef	PROTO_INET
    {KSYM_IPFORWARDING, &krt_ipforwarding},
    {KSYM_UDPCKSUM, &krt_udpcksum},
#endif	/* PROTO_INET */
#ifndef	VRS_SYM
#define	VRS_SYM	"_version"
#endif	/* VRS_SYM */
    {VRS_SYM, &krt_version},
    {NULL, NULL}
};

#define	NL_SIZE	(sizeof (nl_names)/sizeof (nl_names[0]))

#ifdef	_AUX_SOURCE
#define	n_name	n_nptr
#endif	/* _AUX_SOURCE */

int
krt_symbols __PF1(tp, task *)
{
    int i;
    static struct nlist nl[NL_SIZE];

    if (!kd) {
	return EBADF;
    }
    
    for (i = NL_SIZE; i--;) {
	register struct nlist *nlp = &nl[i];

	/* Use bcopy to avoid warning about const char * */
	bcopy((caddr_t) &nl_names[i].nl_name, (caddr_t) &nlp->n_name, sizeof(char *));
#ifdef	NLIST_NOUNDER
	if (nlp->n_name) {
	    nlp->n_name++;
	}
#endif	/* NLIST_NOUNDER */
	if (nl_names[i].nl_ptr) {
	    *nl_names[i].nl_ptr = nlp;
	}
    }

#ifdef	_IBMR2
    knlist(nl, NL_SIZE, sizeof (struct nlist));
#else	/* _IBMR2 */
    if (KVM_NLIST(kd, nl) < 0) {
	trace_log_tp(tp,
		     0,
		     LOG_ERR,
		     ("krt_symbols: %s",
		      KVM_GETERR(kd, "kvm_nlist error")));

	return EINVAL;
    }
#endif	/* _IBMR2 */
#ifdef	_AUX_SOURCE
    /*  There is a bug in the Apple A/UX 2.01 nlist function.  It will	*/
    /*  return a value of zero for any symbol that is in the bss region.*/
    /*  It does work correctly for symbols which are in the data region.*/
    /*  This function opens a pipe to the nm(1) command, which works	*/
    /*  correctly, although more slowly, for symbols in the bss region.	*/
    /*  Herb Weiner <herbw@wiskit.rain.com>				*/
    for (i = NL_SIZE; i--;) {
	register struct nlist *nlp = &nl[i];
	
	if (nlp->n_type && !nlp->n_value) {
	    char command [256];
	    char buffer [256];
	    char *bufp;
	    FILE *symbol_pipe;
 
	    sprintf (command, "/bin/nm -d %s | /bin/grep %s",
		     UNIX_NAME,
		     nlp->nl_name);
	    NON_INTR(symbol_pipe, pope (command, "r"));
 
	    fgets (buffer, sizeof (buffer), symbol_pipe);
	    bufp = strchr (buffer, '|');
	    if (bufp) {
		sscanf (bufp, "|%ld|", &nlp->nl_value);
	    }
    
	    pclose (symbol_pipe);
	}
    }
#endif	/* _AUX_SOURCE */

    if (TRACE_TP(tp, TR_KRT_SYMBOLS)) {
	for (i = NL_SIZE; i--;) {
	    register struct nlist *nlp = &nl[i];

	    if (nlp->n_name) {
		trace_only_tp(tp,
			      0,
			      ("krt_symbols: %s = %x",
			       nlp->n_name,
			       nlp->n_value));
	    }
	}
    }
    
    if (krt_version->n_value) {
	char *p;

	krt_version_kernel = (char *) task_block_alloc(task_block_pagesize);
	if (KVM_READ(kd,
		     krt_version->n_value,
		     krt_version_kernel,
		     task_pagesize - 1) < 0) {
	    trace_log_tp(tp,
			 0,
			 LOG_ERR,
			 ("krt_symbols: reading kernel version: %s",
			  KVM_GETERR(kd, "kvm_read error")));
	    return EINVAL;
	}
	if ((p = (char *) index(krt_version_kernel, '\n'))) {
	    *p = (char) 0;
	}
	p = task_mem_strdup(tp, krt_version_kernel);
	task_block_free(task_block_pagesize, krt_version_kernel);
	krt_version_kernel = p;
	trace_only_tp(tp,
		      TRC_NL_BEFORE,
		      ("krt_symbols: %s = %s",
		       krt_version->n_name,
		       krt_version_kernel));
    }

#ifdef	PROTO_INET
    if (krt_ipforwarding->n_value) {
	int value;
	
	if (KVM_READ(kd,
		     krt_ipforwarding->n_value,
		     &value,
		     sizeof(value)) < 0) {
	    trace_log_tp(tp,
			 0,
			 LOG_INFO,
			 ("krt_symbols: reading IP forwarding enable flag: %s",
			  KVM_GETERR(kd, "kvm_read error")));
	} else {
	    inet_ipforwarding = value > 0;
	    trace_tp(tp,
		     TR_KRT_SYMBOLS,
		     0,
		     ("krt_symbols: IP forwarding %u using %u",
		      value,
		      inet_ipforwarding));
	}
    }
    if (krt_udpcksum->n_value) {
	int value;
	
	if (KVM_READ(kd,
		     krt_udpcksum->n_value,
		     &value,
		     sizeof(value)) < 0) {
	    trace_log_tp(tp,
			 0,
			 LOG_INFO,
			 ("krt_symbols: reading UDP checksum enable flag: %s",
			  KVM_GETERR(kd, "kvm_read error")));
	} else {
	    inet_udpcksum = value != 0;
	    trace_tp(tp,
		     TR_KRT_SYMBOLS,
		     0,
		     ("krt_symbols: UDP checksums %u using %u",
		      value,
		      inet_udpcksum));
	}
    }
#endif	/* PROTO_INET */

    return 0;
}


