From: system@alchemy.chem.utoronto.ca (System Admin (Mike Peterson))
Subject: BSD to HP-UX porting tricks (LONG) (last updated: 24-Sep-1992)
Organization: University of Toronto Chemistry Department
Date: Thu, 1 Oct 1992 05:00:05 GMT

	HP TRICKS (home-grown and from news postings)
	=============================================

Things to watch out for:

TIOCNOTTY   - this is not available on HP-UX (use setsid()); trying
	      to open '/dev/tty' will also fail with status -1.
setpgrp     - this doesn't get rid of the controlling terminal
	      if you use -lBSD (use setsid()).
BSD signals - you almost certainly want them if your program came from
	      a BSD system (e.g. Sun); this breaks 'setpgrp' among other
	      things (see 'man bsdproc' and notes below).


getwd:
------

/* Replace 'SIZEOFARG-1' with the declared size of "arg", minus 1 */

#ifdef __hpux
#include <unistd.h>
#define getwd(arg)	getcwd(arg, (size_t) SIZEOFARG-1)
#else
char	*getwd();
#endif


getrusage:
----------

From: scot@pawnee.ugrad.ee.ufl.edu (Scott Miller)
Newsgroups: comp.sys.hp
Subject: Re: Where is getrusage()? (Summary)
Organization: UF EE Department

getrusage() is in the syscall includes

Here is the code fragment I used:

#ifdef hpux
#include <sys/syscall.h>
#define getrusage(a, b)  syscall(SYS_GETRUSAGE, a, b)
#endif /* hpux */


srandom, random:
----------------

From: mjo@snclib.snc.edu (Mike O'Connor)
Newsgroups: comp.sys.hp
Subject: Re: random and srandom on HP9000/720 with HPUX-8.07

#define srandom srand
#define random rand


getdtablesize:
--------------

/*
 * getdtablesize ()
 *
 * Returns the maximum number of file descriptors allowed.
 */

#include <unistd.h>

	int
getdtablesize ()
{
	return(sysconf(_SC_OPEN_MAX));
}


usleep:
-------

/*
 *  NAME:
 *      usleep     -- This is the precision timer for Test Set
 *                    Automation. It uses the select(2) system
 *                    call to delay for the desired number of
 *                    micro-seconds. This call returns ZERO
 *                    (which is usually ignored) on successful
 *                    completion, -1 otherwise. 
 *
 *  ALGORITHM:
 *      1) We range check the passed in microseconds and log a
 *         warning message if appropriate. We then return without
 *         delay, flagging an error. 
 *      2) Load the Seconds and micro-seconds portion of the
 *         interval timer structure.
 *      3) Call select(2) with no file descriptors set, just the
 *         timer, this results in either delaying the proper
 *         ammount of time or being interupted early by a signal.
 *
 *  HISTORY:
 *      Added when the need for a subsecond timer was evident.
 *
 *  AUTHOR:
 *      Michael J. Dyer                   Telephone:   AT&T 414.647.4044
 *      General Electric Medical Systems        GE DialComm  8 *767.4044
 *      P.O. Box 414  Mail Stop 12-27         Sect'y   AT&T 414.647.4584
 *      Milwaukee, Wisconsin  USA 53201                      8 *767.4584
 *      internet:  mike@sherlock.med.ge.com     GEMS WIZARD e-mail: DYER
 */

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#include <sys/param.h>
#include <sys/types.h>

int     usleep( unsigned long int microSeconds )
{
        unsigned int            Seconds, uSec;
        int                     nfds, readfds, writefds, exceptfds;
        struct  timeval         Timer;

        nfds = readfds = writefds = exceptfds = 0;

        if( (microSeconds == (unsigned long) 0) 
                || microSeconds > (unsigned long) 4000000 )
        {
                errno = ERANGE;         /* value out of range */
                perror( "usleep time out of range ( 0 -> 4000000 ) " );
                return -1;
        }

        Seconds = microSeconds / (unsigned long) 1000000;
        uSec    = microSeconds % (unsigned long) 1000000;

        Timer.tv_sec            = Seconds;
        Timer.tv_usec           = uSec;

        if( select( nfds, &readfds, &writefds, &exceptfds, &Timer ) < 0 )
        {
                perror( "usleep (select) failed" );
                return -1;
        }

        return 0;
}


flock:
------

/*
 * flock (fd, operation)
 *
 * This routine performs some file locking like the BSD 'flock'
 * on the object described by the int file descriptor 'fd',
 * which must already be open.
 *
 * The operations that are available are:
 *
 * LOCK_SH  -  get a shared lock.
 * LOCK_EX  -  get an exclusive lock.
 * LOCK_NB  -  don't block (must be ORed with LOCK_SH or LOCK_EX).
 * LOCK_UN  -  release a lock.
 *
 * Return value: 0 if lock successful, -1 if failed.
 *
 * Note that whether the locks are enforced or advisory is
 * controlled by the presence or absence of the SETGID bit on
 * the executable.
 *
 * Note that there is no difference between shared and exclusive
 * locks, since the 'lockf' system call in SYSV doesn't make any
 * distinction.
 *
 * The file "<sys/file.h>" contains the definitions of the available
 * operations, which must be added manually (see below for the values).
 */

#include <unistd.h>
#include <sys/file.h>
#include <errno.h>

extern int errno;

	int
flock (int fd, int operation)
{
	int i;

	switch (operation) {

	/* LOCK_SH - get a shared lock */
	case LOCK_SH:
	/* LOCK_EX - get an exclusive lock */
	case LOCK_EX:
		i = lockf (fd, F_LOCK, 0);
		break;

	/* LOCK_SH|LOCK_NB - get a non-blocking shared lock */
	case LOCK_SH|LOCK_NB:
	/* LOCK_EX|LOCK_NB - get a non-blocking exclusive lock */
	case LOCK_EX|LOCK_NB:
		i = lockf (fd, F_TLOCK, 0);
		if (i == -1)
			if ((errno == EAGAIN) || (errno == EACCES))
				errno = EWOULDBLOCK;
		break;

	/* LOCK_UN - unlock */
	case LOCK_UN:
		i = lockf (fd, F_ULOCK, 0);
		break;

	/* Default - can't decipher operation */
	default:
		i = -1;
		errno = EINVAL;
		break;
	}

	return (i);
}

/*
 * An alternative version was posted by James Gritton
 * (gritton@byu.edu) in comp.sys.hp.
 * As far as I can tell, it works the same as the above
 * except for the "errno" values returned (and it defaults
 * an invalid operation to "unlock").
 * The definitions of LOCK_xx should be put into <sys/file.h> and/or
 * <fcntl.h>.
 * Note: this was typed in, so it may not work as given.
 */

/*
 *#include <fcntl.h>
 *#define LOCK_SH 1
 *#define LOCK_EX 2
 *#define LOCK_NB 4
 *#define LOCK_UN 8
 *
 *	int
 *flock (int fd, int operation)
 *{
 *	struct flock fl;
 *
 *	switch (operation & ~LOCK_NB) {
 *	case LOCK_SH:
 *		fl.l_type = F_RDLCK;
 *		break;
 *	case LOCK_EX:
 *		fl.l_type = F_WRLCK;
 *		break;
 *	default:
 *		fl.l_type = F_UNLCK;
 *		break;
 *	}
 *
 *	fl.l_whence = SEEK_SET;
 *	fl.l_start = fl.l_len = 0L;
 *
 *	return fcntl (fd, (operation & LOCK_NB) ? F_SETLK : F_SETLKW, &fl);
 *}
 */


getclktck:
----------

/*
 * getclktck ()
 *
 * Returns the value of CLK_TCK (timer resolution).
 */

#include <unistd.h>

	int
getclktck ()
{
	return(sysconf(_SC_CLK_TCK));
}


getloadavg (works on a wide variety of systems):
------------------------------------------------

/*
 * getloadavg (ave, n)
 *
 * This routine returns 'n' double precision floats containing
 * the load averages in 'ave'; at most 3 values will be returned.
 *
 * Return value: 0 if successful, -1 if failed (and all load
 * averages are returned as 0).
 */

#include <sys/types.h>
#include <stdio.h>
#include <nlist.h>
#include <errno.h>

extern int errno;

#define STRSIZ	512			/* Sprintf buffer size */
static char errstr[STRSIZ];		/* Global sprintf buffer */

int ugetloads(float *a);
static void mperror(char *s);
static char *syserr();

#define merror(a1)		fprintf(stderr,"%s",a1)
#define merror1(fmt,a1)		{ sprintf(errstr,fmt,a1); merror(errstr); }

struct	nlist nl[] = {
#ifdef stardent
# define unixpath "/unix"
	{ "avenrun" },
#else
#ifdef __hpux
# define unixpath "/hp-ux"
#ifdef __hppa       /* series 700 & 800 */
	{ "avenrun" },
#else               /* series 300 & 400 */
	{ "_avenrun" },
#endif
#else
# define unixpath "/vmunix"
	{ "_avenrun" },
#endif
#endif
	{ 0 },
};

#ifndef RISCos
	int
getloadavg (double *a, int na)
{
	int i, nreturn;
	static int kmem = -1;
#if defined(vax) || defined(__hpux)
	double avenrun[3];
#else
	long avenrun[3];
#endif
#ifdef NOKMEM
	float aves[3];
#endif /* NOKMEM */

	nreturn = na;
	if ( nreturn < 0 )
		nreturn = 0;
	if ( nreturn > 3 )
		nreturn = 3;

#ifdef NOKMEM
/* Use 'uptime' output for BSD-like systems with no /dev/kmem */

	i = ugetloads(aves);
	if( i == -1 ){
		merror("ugetloads failed\n");
		goto failed;
	}
	for (i = 0; i < nreturn; i++)
		a[i] = aves[i];

#else /*NOKMEM*/

	if(kmem == -1) {
#ifdef sgi
# include <sys/sysmp.h>
	nl[0].n_value = sysmp(MP_KERNADDR, MPKA_AVENRUN) & 0x7fffffff;
#else
		nlist(unixpath, nl);
		if (nl[0].n_type==0) {
			merror1("%s: No namelist\n", unixpath);
			goto failed;
		}
#ifdef stardent
		nl[0].n_value &= 0x7fffffff;
#endif
#endif
		if((kmem = open("/dev/kmem", 0)) == -1) {
			mperror("Can't open(/dev/kmem)");
			goto failed;
		}
	}
	if( lseek(kmem, (off_t)nl[0].n_value, 0) == -1 ){
		mperror("Can't lseek in kmem");
		goto failed;
	}
	if( read(kmem, (char *)avenrun, sizeof(avenrun)) != sizeof(avenrun) ){
		mperror("Can't read kmem");
		goto failed;
	}
	for (i = 0; i < nreturn; i++)
#if defined(sun) || defined(sequent)
		a[i] = avenrun[i] / FSCALE;
#else 
#ifdef sgi
		a[i] = avenrun[i] / 1024;
#else
#if defined(BSD4_2) || defined(__hpux)
		a[i] = avenrun[i];
#else 
#ifdef stardent
		a[i] = (double)avenrun[i] / (1<<16);
#else
		a[i] = avenrun[i] / 1024;
#endif /*stardent*/
#endif /*BSD4_2*/
#endif /*sgi*/
#endif /*sun*/
#endif /*NOKMEM*/
	return(0); 
failed:;
	for (i = 0; i < nreturn; i++)
		a[i] = 0;
	return(-1);
}
#else /*RISCos*/
#include <sys/fixpoint.h>
	static
getloadavg (double *a, int na)
{
	int i, nreturn;
	static int kmem = -1;
	fix avenrun[3];

	nreturn = na;
	if ( nreturn < 0 )
		nreturn = 0;
	if ( nreturn > 3 )
		nreturn = 3;

	if(kmem == -1) {
		nlist("/unix", nl);
		if (nl[0].n_type==0) {
			merror("/unix: No namelist\n");
			goto failed;
		}
		if((kmem = open("/dev/kmem", 0)) == -1) {
			mperror("Can't open(/dev/kmem)");
			goto failed;
		}
	}
	if( lseek(kmem, (off_t)nl[0].n_value, 0) == -1 ){
		mperror("Can't lseek in kmem");
		goto failed;
	}
	if( read(kmem, (char *)avenrun, sizeof(avenrun)) != sizeof(avenrun) ){
		mperror("Can't read kmem");
		goto failed;
	}
	for (i = 0; i < nreturn; i++)
	        a[i] = (int) FIX_TO_INT(avenrun[i]) + .5;
	return(0);
failed:;
	for (i = 0; i < nreturn; i++)
		a[i] = 0;
	return(-1);
}
#endif /* RISCOS */

/* ugetloads(ls)
 * float ld[3];
 *
 * Puts the 1, 5, and 15 minute load averages in the float
 * array passed to it.  This program calls upon uptime(1)
 * which could have different ways of printing ie. with bsd4.2
 * "   9:34pm  up 11 hrs,  3 users,  load average: 0.25, 0.22, 0.24  "
 *                                notice the commas -- ^ --- ^.
 * while bsd4.1 does not print commas.  The BSD41 define will 
 * take care of this if that is your system, it defaults to
 * the 4.2 version.
 *
 * Author:
 *  John Bien
 *  {ihnp4 | ucbvax | decvax}!trwrb!jsb
 *
 * This routine taken from comp.sources.unix: Volume 4, Issue 78
 */

FILE *popen();

ugetloads(ld)
float ld[3];
{
    FILE *stream;
    int i;

    if((stream = popen("uptime","r")) == NULL)
	return(-1);

#ifdef BSD41
    i = fscanf(stream,"%*[^l] load average: %f %f %f", &ld[0],&ld[1],&ld[2]);
#else
    i = fscanf(stream,"%*[^l] load average: %f, %f, %f", &ld[0],&ld[1],&ld[2]);
#endif /* BSD41 */
    pclose(stream);
    return i == 3 ? 0 : -1;
}

/* Routine to print messages to stderr, appending the system error message */

	static void
mperror(char *s)
{
	char *p;
	char str[STRSIZ];	/* must have own internal buffer */

	if( (p=index(s,'\n')) != NULL )
		*p = '\0';
	sprintf(str,"%s: %s\n", s, syserr());
	if( p )
		*p = '\n';
	merror(str);
}

/* Routine to get the last system error message */

extern int sys_nerr;
extern char *sys_errlist[];

	static char *
syserr()
{
	static char buf[80];

	if (errno >= 0 && errno < sys_nerr)
		return(sys_errlist[errno]);
	sprintf(buf,"Unknown error %d", errno);
	return(buf);
}


Dissociate from controlling terminal:
-------------------------------------

From: jhd@irfu.se (Jan D.)
Organization: Swedish Institute of Space Physics, Uppsala, Sweden

The code above should look like this on HP-UX (POSIX ?):

	#include <unistd.h>	/* For _SC_OPEN_MAX */

	long	tblsiz = sysconf(_SC_OPEN_MAX);

 	if (fork())
 	    exit(0);

	setsid();	/* Disassociate from controlling terminal */
 	for (c = 0; c < tblsiz; c++)
 	    (void) close(c);
 	(void) open("/", O_RDONLY);
 	(void) dup2(0, 1);
 	(void) dup2(0, 2);


Here's the deal regarding '-lBSD':

setpgrp() (in libc) is equivalent to setsid().
setpgrp(pid, pgrp) (in -lBSD) is equivalent to POSIX setpgid(pid, pgrp).
setpgrp2(pid, pgrp) is also equivalent to POSIX setpgid(pid, pgrp).

If you don't link with -lBSD you can replace setsid() in with setpgrp()
if you wan't. They both will get rid of the controlling terminal.

setpgrp(pid, pgrp) (-lBSD style), setpgid(pid, pgrp)
and setpgrp2(pid, pgrp) will NOT remove the controlling terminal.

Thus: The only way (I know of) in HP-UX to remove the controlling terminal
is with setsid() or setpgrp() in libc. The only way in POSIX to get
rid of the controlling terminal is with setsid().


setlinebuf:
-----------

/*
 * setlinebuf (FILE *fp)
 *
 * Routine to set line buffering on "fp".
 */

#include <stdio.h>

	int
setlinebuf (FILE *fp)
{
	(void) setvbuf (fp, NULL, _IOLBF, 0);
	return(0);
}