aboutsummaryrefslogblamecommitdiffstats
path: root/erts/emulator/test/driver_SUITE_data/sys_info_drv_impl.c
blob: 2d3203ae5def079aae750c3a2e99d9e644009a12 (plain) (tree)

























































































































































                                                                                
/* ``The contents of this file are subject to the Erlang Public License,
 * Version 1.1, (the "License"); you may not use this file except in
 * compliance with the License. You should have received a copy of the
 * Erlang Public License along with this software. If not, it can be
 * retrieved via the world wide web at http://www.erlang.org/.
 * 
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and limitations
 * under the License.
 * 
 * The Initial Developer of the Original Code is Ericsson Utvecklings AB.
 * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
 * AB. All Rights Reserved.''
 * 
 *     $Id$
 */

/*
 * Author: Rickard Green
 *
 * Description: Implementation of a driver that fakes different driver
 *              versions and tests driver_system_info(). This file should
 *		be included by an implementation that defines:
 *              * SYS_INFO_DRV_MAJOR_VSN
 *		* SYS_INFO_DRV_MINOR_VSN
 *		* SYS_INFO_DRV_NAME_STR
 *		* SYS_INFO_DRV_NAME
 *		* ERL_DRV_SYS_INFO_SIZE, or SYS_INFO_DRV_LAST_FIELD
 *		and implements:
 *		* static size_t sys_info_drv_max_res_len(ErlDrvSysInfo *)
 *		* static size_t sys_info_drv_sprintf_sys_info(ErlDrvSysInfo *,
 *							      char *)
 *
 */

#if !defined(ERL_DRV_SYS_INFO_SIZE) && defined(SYS_INFO_DRV_LAST_FIELD)

#define ERL_DRV_SYS_INFO_SIZE_FROM_LAST_FIELD(LAST_FIELD) \
  (((size_t) &((ErlDrvSysInfo *) 0)->LAST_FIELD) \
   + sizeof(((ErlDrvSysInfo *) 0)->LAST_FIELD))

#define ERL_DRV_SYS_INFO_SIZE \
  ERL_DRV_SYS_INFO_SIZE_FROM_LAST_FIELD(SYS_INFO_DRV_LAST_FIELD)

#endif

static ErlDrvData start(ErlDrvPort, char *);
static int control(ErlDrvData, unsigned int, char *, int, char **, int);

static ErlDrvEntry drv_entry = { 
    NULL /* init */,
    start,
    NULL /* stop */,
    NULL /* output */,
    NULL /* ready_input */,
    NULL /* ready_output */,
    SYS_INFO_DRV_NAME_STR,
    NULL /* finish */,
    NULL /* handle */,
    control,
    NULL /* timeout */,
    NULL /* outputv */,
    NULL /* ready_async */,
    NULL /* flush */,
    NULL /* call */,
    NULL /* event */,
    ERL_DRV_EXTENDED_MARKER,
    SYS_INFO_DRV_MAJOR_VSN,
    SYS_INFO_DRV_MINOR_VSN,
    ERL_DRV_FLAG_USE_PORT_LOCKING,
    NULL /* handle2 */,
    NULL /* process_exit */
};

DRIVER_INIT(SYS_INFO_DRV_NAME)
{
    return &drv_entry;
}

static ErlDrvData
start(ErlDrvPort port, char *command)
{
    return (ErlDrvData) port;
}

static int
control(ErlDrvData drv_data,
	unsigned int command,
	char *buf, int len,
	char **rbuf, int rlen)
{
    int res;
    char *str;
    size_t slen, slen2;
    ErlDrvPort port = (ErlDrvPort) drv_data;
    unsigned deadbeef[] = {0xdeadbeef,
			   0xdeadbeef,
			   0xdeadbeef,
			   0xdeadbeef,
			   0xdeadbeef,
			   0xdeadbeef,
			   0xdeadbeef,
			   0xdeadbeef,
			   0xdeadbeef,
			   0xdeadbeef};
    ErlDrvSysInfo *sip = driver_alloc(ERL_DRV_SYS_INFO_SIZE + sizeof(deadbeef));
    char *beyond_end_format = "error: driver_system_info() wrote beyond end "
	"of the ErlDrvSysInfo struct";
    char *buf_overflow_format = "error: Internal buffer overflow";

    if (!sip) {
	driver_failure_atom(port, "enomem");
	return 0;
    }

    memset((char *) sip, 0xed, ERL_DRV_SYS_INFO_SIZE);
    memcpy(((char *) sip) + ERL_DRV_SYS_INFO_SIZE,
	   (char *) &deadbeef[0],
	   sizeof(deadbeef));

    driver_system_info(sip, ERL_DRV_SYS_INFO_SIZE);

    slen = sys_info_drv_max_res_len(sip);
    slen2 = strlen(beyond_end_format) + 1;
    if (slen2 > slen)
	slen = slen2;
    slen2 = strlen(buf_overflow_format) + 1;
    if (slen2 > slen)
	slen = slen2;
    str = driver_alloc(slen);
    if (!str) {
	driver_free(sip);
	driver_failure_atom(port, "enomem");
	return 0;
    }
    *rbuf = str;

    /* Check that the emulator didn't write beyond ERL_DRV_SYS_INFO_SIZE */
    if (memcmp(((char *) sip) + ERL_DRV_SYS_INFO_SIZE,
	       (char *) &deadbeef[0],
	       sizeof(deadbeef)) != 0) {
	res = sprintf(str, beyond_end_format);
    }
    else {
	res = sys_info_drv_sprintf_sys_info(sip, str);
	if (res > slen)
	    res = sprintf(str, buf_overflow_format);
    }
    driver_free(sip);
    return res;
}