/*
 * Copyright (c) 1998,1999,2000
 *	Traakan, Inc., Los Altos, CA
 *	All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice unmodified, this list of conditions, and the following
 *    disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * Project:  NDMJOB
 * Ident:    $Id: $
 *
 * Description:
 *
 *	This is the #include file for the Operating System
 *	(O/S) specific portion of the NDMJOBLIB library.
 *	By O/S we mean the programming environment including
 *	compilers, header files, as well the host O/S APIs.
 *	O/S specific is clear and concise, so that's how we refer
 *	to the hosting environment.
 *
 *	This file, ndmos.h, essentially	#include's the right
 *	ndmos_xxx.h for the hosting environment. The companion
 *	source C files, ndmos_xxx*.c, are similarly selected by
 *	ndmos.c.
 *
 *	  (hacked in Amanda to just #include ndmos_glib.h and then follow up
 *	  with the usual defaults)
 *
 *	The strategy for separating the O/S specific and O/S
 *	generic portions of NDMJOBLIB has four key points:
 *
 *	  1) Isolate O/S specific portions in separate
 *	     files which can be developed, contributed,
 * 	     and maintained independently of the overall
 *	     source base.
 *
 *	  2) NEVER NEVER #ifdef based on O/S or programming
 *	     environment in the O/S generic portions. These
 *	     make collective maintenance and integration
 *	     too difficult.
 *
 *	  3) Use O/S specific #define macros (NDMOS_...)
 *	     and C functions (ndmos_...) as wrappers around
 *	     the portions that vary between environments
 *	     and applications.
 *
 *	  4) Use generic, objective-oriented #ifdef's to isolate
 *	     and omit functionality which may not be wanted in
 *	     all applications.
 *
 *	There are templates in ndmos_xxx.h and ndmos_xxx.c
 *	to get started on a new O/S specific portion.
 *	Send contributions to the current keeper of NDMJOB.
 *	Contact ndmp-tech@ndmp.org for details.
 *
 *	>>>  DO NOT MODIFY THIS FILE OR ANY GENERIC  <<<
 *	>>>  PORTION OF NDMJOBLIB FOR THE SAKE OF A  <<<
 *	>>>  HOSTING ENVIRONMENT OR APPLICATION.     <<<
 *
 *	If you discover additional isolation requirements,
 *	raise the issue on ndmp-tech@ndmp.org. Propose new
 *	#define NDMOS_ macros to address them. Then, submit
 *	the proposal with required changes to the current
 *	keeper of NDMJOB. Changes to the generic portion which
 *	use #ifdef's based on anything other than NDMOS_
 *	macros will be summarily rejected.
 *
 *	There are four sections of this file:
 *	  1) Establish identities for various O/S platforms
 *	  2) Try to auto-recognize the environment
 *	  3) #include the right O/S specific ndmos_xxx.h
 *	  4) Establish default #define-itions for macros
 *	     left undefined
 */


#ifndef _NDMOS_H
#define _NDMOS_H

/* set up the appropriate macros for use in various version-printing
 * functions */
#define NDMOS_IDENT(A,B,C,D)   (((A)<<24)+((B)<<16)+((C)<<8)+(D))
#define NDMOS_ID_GLIB          NDMOS_IDENT('G','l','i','b')
#define NDMOS_ID NDMOS_ID_GLIB

/* unconditionally include ndmos_glib.h */
#include "ndmos_glib.h"

/*
 * From here down, pre-processor symbols are #define'd to defaults
 * if not already #define'd in the O/S specific header file.
 *
 * Application Program Interfaces (APIs). The macros give the
 * O/S specific header a chance to use casts or different functions.
 *
 * NDMOS_API_BCOPY		-- memory copy
 * NDMOS_API_BZERO		-- zero-fill memory
 * NDMOS_API_MALLOC		-- memory allocator, no initialization
 * NDMOS_API_FREE		-- memory deallocator
 * NDMOS_API_STRTOLL		-- convert strings to long long
 * NDMOS_API_STRDUP		-- malloc() and strcpy()
 * NDMOS_API_STREND		-- return pointer to end of string
 *
 * Important constants that sometimes vary between O/S's.
 *
 * NDMOS_CONST_ALIGN		-- alignment for memory allocation
 * NDMOS_CONST_EWOULDBLOCK	-- errno when async I/O would stall
 * NDMOS_CONST_TAPE_REC_MAX	-- maximum tape record length
 * NDMOS_CONST_TAPE_REC_MIN	-- minimum tape record length
 * NDMOS_CONST_PATH_MAX		-- maximum path name length
 * NDMOS_CONST_NDMJOBLIB_REVISION -- String for in-house change level
 *				   Convention "0" if no changes
 *				   from released source. If changes,
 *				   the initials of local keeper with
 *				   sequence number or date code.
 * NDMOS_CONST_VENDOR_NAME	-- String for server_info_reply.vendor_name
 * NDMOS_CONST_PRODUCT_NAME	-- String for server_info_reply.product_name
 * NDMOS_CONST_PRODUCT_REVISION	-- String for product change level
 *				   By "product" we mean the program
 *				   enclosing this NDMJOBLIB library.
 * NDMOS_CONST_NDMOS_REVISION	-- String for ndmos_xxx change level
 *
 * Macros for certain small operations which can vary.
 *
 * NDMOS_MACRO_NEW		-- allocate a data structure, wrapper
 *				   around NDMOS_API_MALLOC() with casts
 * NDMOS_MACRO_NEWN		-- allocate a vector of data structs
 * NDMOS_MACRO_ZEROFILL		-- zero-fill data structure, wrapper
 *				   around NDMOS_API_BZERO()
 * NDMOS_MACRO_SRAND		-- wrapper around srand(3), for MD5
 * NDMOS_MACRO_RAND		-- wrapper around rand(3), for MD5
 * NDMOS_MACRO_OK_TAPE_REC_LEN	-- Uses NDMOS_CONST_TAPE_REC_MIN/MAX
 * NDMOS_MACRO_SET_SOCKADDR	-- Sets struct sockaddr_in with
 *				   respect to NDMOS_OPTION_HAVE_SIN_LEN
 *
 * The NDMOS_MACRO_xxx_ADDITIONS macros allow additional O/S
 * specific members to key structures in ndmagents.h
 *
 * NDMOS_MACRO_CONTROL_AGENT_ADDITIONS	-- struct ndm_control_agent
 * NDMOS_MACRO_DATA_AGENT_ADDITIONS	-- struct ndm_data_agent
 * NDMOS_MACRO_ROBOT_AGENT_ADDITIONS	-- struct ndm_robot_agent
 * NDMOS_MACRO_SESSION_ADDITIONS	-- struct ndm_session
 * NDMOS_MACRO_TAPE_AGENT_ADDITIONS	-- struct ndm_tape_agent
 *
 * All NDMOS_OPTION_... parameters are either #define'd or #undef'ed.
 * They are solely interpretted in #ifdef's and #ifndef's, and the
 * value of the definition means nothing. These _OPTIONS_'s can be set
 * on the command line (-D) in the Makefile, or in the O/S specific
 * header file.
 *
 * NDMOS_OPTION_NO_NDMP2	-- omit NDMPv2 support
 * NDMOS_OPTION_NO_NDMP3	-- omit NDMPv3 support
 * NDMOS_OPTION_NO_NDMP4	-- omit NDMPv4 support
 *
 * NDMOS_OPTION_NO_CONTROL_AGENT -- omit CONTROL agent features
 * NDMOS_OPTION_NO_DATA_AGENT	-- omit DATA agent features
 * NDMOS_OPTION_NO_ROBOT_AGENT	-- omit ROBOT agent features
 * NDMOS_OPTION_NO_TAPE_AGENT	-- omit TAPE agent features
 *	For some purposes, an all-in-one is overkill, or perhaps
 *	impractical. Everything is carefully constructed so
 *	that certain agents can be omitted without disturbing
 *	the rest. The two most obvious uses are to either
 *	keep or omit just the CONTROL agent.
 *
 * NDMOS_OPTION_ALLOW_SCSI_AND_TAPE_BOTH_OPEN
 *	The NDMP specification says that both TAPE and SCSI can not
 *	be open at the same time. Then the workflow docs suggest
 *	a separate process for the ROBOT agent to get around the
 *	restriction. #define'ing this breaks the spec and allows
 *	both to be open.
 *
 * NDMOS_OPTION_HAVE_SIN_LEN
 *	In preparation for IPv6, some O/Ss use a sin_len field to
 *	indicate the length of the address. This _OPTION_ affects
 *	the standard NDMOS_MACRO_SET_SOCKADDR.
 *
 * NDMOS_OPTION_TAPE_SIMULATOR
 *	Early in bring-up on a new system, it's a little easier to
 *	get started by using the tape simulator. It represents
 *	an idealized MTIO-type tape subsystem, and uses a disk
 *	file to represent the tape. As the real O/S specific tape
 *	subsystem interface is implemented (ndmos_tape_...()), the
 *	tape simulator serves as a reference for correct implementation.
 *
 * NDMOS_OPTION_ROBOT_SIMULATOR
 *	Similarly, for testing multi-tape operations, it's easier to
 *	get started by using the robot simulator. It represents a simple
 *	robot with ten slots and two drives.  It operates on a directory,
 *	and uses rename() to load and unload tapes.  It operates in concert
 *	with the tape simulator.  The robot name is a directory, and it
 *	creates drives named 'drive0', 'drive1', etc. in that directory
 *
 * NDMOS_OPTION_USE_SELECT_FOR_CHAN_POLL -- use common poll() code
 * NDMOS_OPTION_USE_POLL_FOR_CHAN_POLL   -- use common select() code
 *	These two _OPTION_'s choose common code to implement
 *	ndmos_chan_poll(). The select() and poll() functions are
 *	fairly common and consistent among various O/S's to detect
 *	ready I/O. Only one can be defined. If the common code
 *	doesn't work out, don't define either _OPTION_ and implement
 *	ndmos_chan_poll() in the O/S specific C source file.
 */

/*
 * Constants
 */
#ifndef NDMOS_CONST_ALIGN
#define NDMOS_CONST_ALIGN		sizeof(unsigned long long)
#endif /* !NDMOS_CONST_ALIGN */

#ifndef NDMOS_CONST_TAPE_REC_MIN
#define NDMOS_CONST_TAPE_REC_MIN	1
#endif /* !NDMOS_CONST_TAPE_REC_MIN */

#ifndef NDMOS_CONST_TAPE_REC_MAX
#define NDMOS_CONST_TAPE_REC_MAX	(256*1024)
#endif /* !NDMOS_CONST_TAPE_REC_MAX */

#ifndef NDMOS_CONST_PATH_MAX
#define NDMOS_CONST_PATH_MAX		(1024)
#endif /* !NDMOS_CONST_PATH_MAX */

#ifndef NDMOS_CONST_EWOULDBLOCK
#ifdef EWOULDBLOCK
#define NDMOS_CONST_EWOULDBLOCK		EWOULDBLOCK
#else /* EWOULDBLOCK */
#define NDMOS_CONST_EWOULDBLOCK		EAGAIN
#endif /* EWOULDBLOCK */
#endif /* !NDMOS_CONST_EWOULDBLOCK */

#ifndef NDMOS_CONST_NDMJOBLIB_REVISION
#define NDMOS_CONST_NDMJOBLIB_REVISION "1.4a"
#endif /* !NDMOS_CONST_NDMJOBLIB_REVISION */

#ifndef NDMOS_CONST_VENDOR_NAME
#define NDMOS_CONST_VENDOR_NAME "PublicDomain"
#endif /* !NDMOS_CONST_VENDOR_NAME */

#ifndef NDMOS_CONST_PRODUCT_NAME
#define NDMOS_CONST_PRODUCT_NAME "NDMJOB"
#endif /* !NDMOS_CONST_PRODUCT_NAME */

#ifndef NDMOS_CONST_PRODUCT_REVISION
#define NDMOS_CONST_PRODUCT_REVISION "1.4a"
#endif /* !NDMOS_CONST_PRODUCT_REVISION */

#ifndef NDMOS_CONST_NDMOS_REVISION
#define NDMOS_CONST_NDMOS_REVISION "0"
#endif /* !NDMOS_CONST_NDMOS_REVISION */




/*
 * Application Program Interfaces (APIs)
 */
#ifndef NDMOS_API_BZERO
#define NDMOS_API_BZERO(P,N)	(void)bzero((void*)(P),(N))
#endif /* !NDMOS_API_BZERO */

#ifndef NDMOS_API_BCOPY
#define NDMOS_API_BCOPY(S,D,N)	(void)bcopy((void*)(S),(void*)(D),(N))
#endif /* !NDMOS_API_BCOPY */

#ifndef NDMOS_API_MALLOC
#define NDMOS_API_MALLOC(N)	malloc(N)
#endif /* !NDMOS_API_MALLOC */

#ifndef NDMOS_API_FREE
#define NDMOS_API_FREE(P)	free((void*)(P))
#endif /* !NDMOS_API_FREE */

#ifndef NDMOS_API_STRTOLL
#define NDMOS_API_STRTOLL(P,PP,BASE) strtoll(P,PP,BASE)
#endif /* !NDMOS_API_STRTOLL */

#ifndef NDMOS_API_STRDUP
#define NDMOS_API_STRDUP(S)	strdup(S)
#endif /* !NDMOS_API_STRDUP */

#ifndef NDMOS_API_STREND
extern char *ndml_strend(char *s);	/* ndml_util.c */
#define NDMOS_API_STREND(S)	ndml_strend(S)
#endif /* !NDMOS_API_STREND */




/*
 * Macros
 */
#ifndef NDMOS_MACRO_NEW
#define NDMOS_MACRO_NEW(T)	((T *) NDMOS_API_MALLOC(sizeof (T)))
#endif /* !NDMOS_MACRO_NEW */

#ifndef NDMOS_MACRO_NEWN
#define NDMOS_MACRO_NEWN(T,N)	((T *) NDMOS_API_MALLOC(sizeof (T) * (N)))
#endif /* !NDMOS_MACRO_NEWN */

#ifndef NDMOS_MACRO_FREE
#define NDMOS_MACRO_FREE(T) free(T)
#endif

#ifndef NDMOS_MACRO_ZEROFILL
#define NDMOS_MACRO_ZEROFILL(P)	NDMOS_API_BZERO(P,sizeof *(P))
#endif /* !NDMOS_MACRO_ZEROFILL */

#ifndef NDMOS_MACRO_SRAND
#define NDMOS_MACRO_SRAND() srand(time(0))
#endif /* !NDMOS_MACRO_SRAND */

#ifndef NDMOS_MACRO_RAND
#define NDMOS_MACRO_RAND() rand()
#endif /* !NDMOS_MACRO_RAND */

#ifndef NDMOS_MACRO_OK_TAPE_REC_LEN
#define NDMOS_MACRO_OK_TAPE_REC_LEN(LEN) \
	(NDMOS_CONST_TAPE_REC_MIN <= (LEN) \
	 && (LEN) <= NDMOS_CONST_TAPE_REC_MAX)
#endif /* !NDMOS_MACRO_OK_TAPE_REC_LEN */

#ifndef NDMOS_MACRO_SET_SOCKADDR
#ifdef NDMOS_OPTION_HAVE_SIN_LEN
#define NDMOS_MACRO_SET_SOCKADDR(SA,INADDR,PORT) \
	( NDMOS_MACRO_ZEROFILL (SA), \
	  ((struct sockaddr_in *)(SA))->sin_len = sizeof *(SA), \
	  ((struct sockaddr_in *)(SA))->sin_family = AF_INET, \
	  ((struct sockaddr_in *)(SA))->sin_addr.s_addr = htonl(INADDR), \
	  ((struct sockaddr_in *)(SA))->sin_port = htons(PORT))
#else /* NDMOS_OPTION_HAVE_SIN_LEN */
#define NDMOS_MACRO_SET_SOCKADDR(SA,INADDR,PORT) \
	( NDMOS_MACRO_ZEROFILL (SA), \
	  ((struct sockaddr_in *)(SA))->sin_family = AF_INET, \
	  ((struct sockaddr_in *)(SA))->sin_addr.s_addr = htonl(INADDR), \
	  ((struct sockaddr_in *)(SA))->sin_port = htons(PORT))
#endif /* NDMOS_OPTION_HAVE_SIN_LEN */
#endif /* !NDMOS_MACRO_SET_SOCKADDR */




/*
 * Composite effects
 */

#ifdef NDMOS_OPTION_NO_DATA_AGENT
#ifdef NDMOS_OPTION_NO_TAPE_AGENT
#ifdef NDMOS_OPTION_NO_ROBOT_AGENT
#define NDMOS_EFFECT_NO_SERVER_AGENTS
#endif /* !NDMOS_OPTION_NO_ROBOT_AGENT */
#endif /* !NDMOS_OPTION_NO_TAPE_AGENT */
#endif /* !NDMOS_OPTION_NO_DATA_AGENT */

#ifdef NDMOS_OPTION_NO_NDMP3
#ifdef NDMOS_OPTION_NO_NDMP4
#define NDMOS_EFFECT_NO_NDMP3_NOR_NDMP4
#endif /* !NDMOS_OPTION_NO_NDMP3 */
#endif /* !NDMOS_OPTION_NO_NDMP4 */

/* check for a conflict: robot sim requires tape sim */
#ifdef NDMOS_OPTION_ROBOT_SIMULATOR
#ifndef NDMOS_OPTION_TAPE_SIMULATOR
#error robot simulator requires the tape simulator
#endif /* NDMOS_OPTION_TAPE_SIMULATOR */
#ifdef NDMOS_COMMON_SCSI_INTERFACE
#error robot simulator and ndmos scsi interface are incompatible
#endif
#endif /* NDMOS_OPTION_ROBOT_SIMULATOR */

/*
 * simulator fields
 */

#ifdef NDMOS_OPTION_TAPE_SIMULATOR
#define NDMOS_MACRO_TAPE_AGENT_ADDITIONS \
	int			tape_fd; \
	char			drive_name[PATH_MAX]; \
	int			weof_on_close; \
	int			sent_leom;
#endif /* NDMOS_OPTION_TAPE_SIMULATOR */

#ifdef NDMOS_OPTION_ROBOT_SIMULATOR
#define NDMOS_MACRO_ROBOT_AGENT_ADDITIONS \
	    char sim_dir[PATH_MAX];
#endif /* NDMOS_OPTION_ROBOT_SIMULATOR */

#endif /* _NDMOS_H */
