/*==============================================================================

FICHIER     : [systools.c]

DATE        : 2005/12/0005 21:58:43

CREATEUR    : [Linux!jef]

COMMENTAIRE :
		Released under GPL license, see gnu.org
================================================================================

==============================================================================*/
#define __USE_LARGEFILE64
#define _LARGEFILE64_SOURCE
#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#if defined(__sun)
#	include <sys/statvfs.h>
#	include <sys/ioctl.h>
#else
#	include <sys/statfs.h>
#endif
#include <fcntl.h>
#include <unistd.h>
#if defined(__sun)
#	include <stropts.h>
#endif
#include <string.h>
#include <errno.h>
#include <sys/wait.h>
#if defined(__sun)
#	include <sys/cdio.h>
#	define NON_BLOCKING
#else
#	include <linux/cdrom.h>
#	include <linux/loop.h>
#endif
#include <ctype.h>


#include <limits.h>


char ** environ;
#define	SH_PATH	"/bin/sh"
#define	SH_NAME	"sh"

/* Structure describing a popen child.  */
struct child
{
	int fd;
	int pid;
} Child;

#define PATHCHR		':'
#define SEPCHAR		'/'

/*------------------------------------------------------------------------------
	MKFIFO-
Linux!jef 2005/12/05 21:59:11
------------------------------------------------------------------------------*/

int MkFifo( fifoName )
char * fifoName;
{
	return( mknod( fifoName, S_IFIFO | 0666, 0 ) ? -1 : 0 );
}
/*------------------------------------------------------------------------------
	DELFIFO-
Linux!jef 2005/12/05 22:00:27
------------------------------------------------------------------------------*/

int DelFifo( fifoName )
char * fifoName;
{
	unlink( fifoName );
	return( 0 );
}

/*------------------------------------------------------------------------------
	FILESTAT64-
Linux!jef 2005/12/16 21:19:35
------------------------------------------------------------------------------*/

long long FileSize64( char * fileName )
{
	struct stat64 bstat;
	int res;

	res = stat64( fileName, &bstat );
	if( res < 0 )	return( 0LL );
// fprintf(stderr,"sizeof(bstat.st_size)=%d := %lld\n", sizeof(bstat.st_size), bstat.st_size );
	return( (long long)bstat.st_size );
}

/*------------------------------------------------------------------------------
	LLSIZE2GIGA-
Linux!jef 2005/12/16 22:22:31
------------------------------------------------------------------------------*/

char * LLSize2Giga( long long size )
{
	static char string[200];
	double g;

// fprintf(stderr,"Size: %lld\n", size );

	g = (double)size / ( 1024.0 * 1024.0 * 1024.0 );
	if( g >= 1.0 ) {
		sprintf( string,(char*)("%.2f gigas"), g );
	}
	else {
		g = (double)size / ( 1024.0 * 1024.0 );
		if( g >= 1.0 ) {
			sprintf( string,(char*)("%.2f megas"), g );
		}
		else {
			g = (double)size / ( 1024.0 );
			sprintf( string,(char*)("%.2f kilos"), g );
		}
	}
	return( string );
}

/*------------------------------------------------------------------------------
	FLOOK-
JEF!jef 95/02/02 15:17:26
------------------------------------------------------------------------------*/
int flook( fname )
char *fname;
{
	char *path;	/* environmental PATH variable */
	char *sp;	/* pointer into path spec */
	char fspec[512];	/* full path spec to search */


	if( *fname == '/' ) {
		if( access( fname, 1 ) == 0 )	return( 1 );
// fprintf(stderr,"%s: is regular file !\n", fname );
		return( 0 );
	}
	/* get the PATH variable */
	path = getenv("PATH");
	if( path ) {
		while (*path) {

			/* build next possible file spec */
			sp = fspec;
			while (*path && (*path != PATHCHR))
				*sp++ = *path++;

			/* add a terminating dir separator if we need it */
			if (sp[-1] != SEPCHAR)
				*sp++ = SEPCHAR;

			*sp = 0;
			strcat(fspec, fname);
// fprintf(stderr,"Trying: (%s)\n",fspec);
			/* and try it out */
			if( access( fspec, 1 ) == 0 )
				return(1);
			if (*path == PATHCHR)
				++path;
		}
	}
	return(0);	/* no such luck */
}
/*------------------------------------------------------------------------------
	FSFREE-
Linux!jef 2005/12/19 20:57:02
------------------------------------------------------------------------------*/

long long FsFree( char * fsName )
{
#if defined(__sun)
        struct statvfs b;
	int res;
	long long freeSize;

        res = statvfs( fsName, &b);
	if( res < 0 )	return( 0LL );
	freeSize = ((long long)b.f_bavail * (long long)b.f_bsize);

	return( freeSize );
#else
	struct statfs b;
	int res;
	long long freeSize;

	res = statfs( fsName, &b );
	if( res < 0 )	return( 0LL );
	freeSize = ((long long)b.f_bavail * (long long)b.f_bsize);
// fprintf(stderr,"avail: %ld bsize: %ld = %lld\n", b.f_bavail,  b.f_bsize, freeSize );
	return( freeSize );
#endif
}
/*------------------------------------------------------------------------------
	DIREXIST-
Linux!jef 2006/01/31 20:46:19
------------------------------------------------------------------------------*/

int DirExist( char * dirName )
{
	struct stat bStat;
	int res;

	res = stat( dirName, &bStat );
// fprintf(stderr,"%s: res=%d\n", dirName, res );
	if( res )	return( 0 );
	if( S_ISDIR( bStat.st_mode ) )	return( 1 );
	return( -1 );
}
/*------------------------------------------------------------------------------
	FILEEXIST-
Linux!jef 2006/01/31 21:02:35
------------------------------------------------------------------------------*/

int FileExist( char * fileName )
{
	struct stat64 bStat;
	int res;

	res = stat64( fileName, &bStat );
// fprintf(stderr,"%s(%s) = %d errno: %d\n", __FUNCTION__,fileName, res, errno );
	if( res )	return( 0 );
	if( S_ISREG( bStat.st_mode ) )	return( 1 );
	if( S_ISBLK( bStat.st_mode ) )	return( 2 );
	return( -1 );
}


/*------------------------------------------------------------------------------
	MY_POPEN-
JEF!jef 95/09/26 14:29:09
	Open a new stream that is a one-way pipe to a
	child process running the given shell command. 
------------------------------------------------------------------------------*/
FILE * my_popen( command, mode)
char * command;
char * mode;
{
	int pid;
	int pipedes[2];
	FILE * stream;

	if (command == NULL || mode == NULL || (*mode != 'r' && *mode != 'w'))
	{
		errno = EINVAL;
		return NULL;
	}

  /* Create the pipe.  */
	if( pipe(pipedes) < 0)
		return NULL;

  /* Fork off the child.  */
	pid = fork();
	if( pid == -1)
	{
/* The fork failed.  */
		close(pipedes[0]);
		close(pipedes[1]);
		return( NULL );
	}
	else {
		if( !pid )
		{
			char *new_argv[4];
			int res;

			signal( SIGHUP, SIG_DFL );
			signal( SIGTERM, SIG_DFL );
			signal( SIGINT, SIG_DFL );
			signal( SIGQUIT, SIG_DFL );
			if( *mode == 'w' ) {
				res = dup2( pipedes[0] , 0 );
			}
			else {
				res = dup2( pipedes[1] , 1 );
/* Ajout Stderr */
				res |= dup2( pipedes[1] , 2 );
			}
			if( res < 0 )	_exit( 127 );

      /* Close the pipe descriptors.  */
			close(pipedes[0]);
			close(pipedes[1]);

      /* Exec the shell.  */
			new_argv[0] = SH_NAME;
			new_argv[1] = "-c";
			new_argv[2] = command;
			new_argv[3] = NULL;
			(void) execve(	SH_PATH,
					(char **) new_argv,
					(char **)environ);
			/* Die if it failed.  */
			_exit(127);
		}
	}
  /* We are the parent side.  */

  /* Close the irrelevant side of the pipe and open the relevant side as a
     new stream.  Mark our side of the pipe to close on exec, so new children
     won't see it.  */
	if( *mode == 'r')
	{
		close(pipedes[1]);
		fcntl( pipedes[0], F_SETFD, FD_CLOEXEC);
		stream = fdopen(pipedes[0], mode);
	}
	else {
		close(pipedes[0]);
		fcntl( pipedes[1], F_SETFD, FD_CLOEXEC);
		stream = fdopen(1, mode);
	}

	if( !stream )
		goto error;

	memset( &Child , 0 , sizeof( Child ));
	Child.fd = fileno(stream);
	Child.pid = pid;
	setvbuf( stream , NULL,_IOFBF,0 );
	return( stream );

error:;
	{
		int save = errno;

		kill(pid, SIGKILL);
		if( !stream )
			close(pipedes[*mode == 'r' ? 1 : 0]);
		else
			fclose(stream);
		{
			int dead;
			do
				dead = wait ((int *) NULL);
			while (dead > 0 && dead != pid);
		}
		errno = save;
		return NULL;
	}
}

/* Close a stream opened by popen and return its status.
   Returns -1 if the stream was not opened by popen.  */
int my_pclose( stream )
FILE *stream;
{
	int pid, dead;
	int status;
	pid = Child.pid;

// fprintf(stderr,"killing: %d\n", pid );

	status = kill( pid, SIGHUP );
	if( fclose(stream) )
		return( -1 );
	do
		dead = wait (&status);
	while (dead > 0 && dead != pid);
	if (dead != pid)
		status = -1;
	return( status );
}
/*------------------------------------------------------------------------------
	DUREE2STRING-
Linux!jef 2006/11/06 22:32:50
------------------------------------------------------------------------------*/

char * Duree2String( int duree )
{
	static char result[100];
	int h,m,s;

	h = duree / 3600;
	duree -= h * 3600;
	m = duree / 60;
	duree -= m * 60;
	s = duree;

	sprintf( result, "%02dh%02dm%02ds", h, m, s );
	return( result );
}
/*------------------------------------------------------------------------------
	ADDSTRING2LIST-
Linux!jef 2007/01/19 22:06:45
------------------------------------------------------------------------------*/

char * AddString2List( char * list, char * string )
{
	char * newList;

	if( strstr( list, string ) ) {
		return( strdup( list ));
	}
	newList = alloca( strlen( list ) + strlen( string ) + 1 + 1 );
	strcpy( newList, list );
	if( *newList ) {
		strcat( newList, "," );
	}
	strcat( newList, string );
	return( strdup( newList ) );
}
/*------------------------------------------------------------------------------
	REMOVESTRINGFROMLIST-
Linux!jef 2007/01/19 22:08:50
------------------------------------------------------------------------------*/

char * RemoveStringFromList( char * list, char * string )
{
	char * newList;
	char * temp;
	char * tok;

	if( !strstr( list, string ) ) {
		return( strdup( list ));
	}
	newList = alloca( strlen( list ) + 1 );
	*newList = 0;
	temp = alloca( strlen( list ) + 1 );
	strcpy( temp, list );
	tok = strtok( temp, "," );
	while( tok ) {
		if( strcmp( tok, string ) ) {
			if( *newList )	strcat( newList, "," );
			strcat( newList, tok );
		}
		tok = strtok( NULL, "," );
	}
	return( strdup( newList ) );
}
/*------------------------------------------------------------------------------
	MAKEDIRIFNEEDED-
Linux!jef 2007/01/23 23:05:51
------------------------------------------------------------------------------*/

int MakeDirIfNeeded( char * path )
{
	struct stat64 bStat;
	int res;

	res = stat64( path, &bStat );
// fprintf(stderr,"%s(%s) = %d errno: %d\n", __FUNCTION__,fileName, res, errno );
	if( !res && S_ISDIR( bStat.st_mode ) )	return( 0 );
	return( mkdir( path, 0777 ) );
}


/*------------------------------------------------------------------------------
	ISDVDLOADED-
Linux!jef 2007/01/09 22:13:37
------------------------------------------------------------------------------*/

int IsDvdLoaded( char * device )
{
	int fd;
	int ret;
	struct stat64 b;
#if !defined(__sun)
	struct loop_info lInfo;
#endif

// fprintf(stderr,"%s(%s)\n", __FUNCTION__, device );
	if( stat64( device, &b) ) {
// perror( device );
		return( -1 );
	}
	if( S_ISREG( b.st_mode ) )	return( 1 );
	fd = open( device, O_RDONLY | O_NONBLOCK);
	if( fd < 0 ) {
// perror( "open" );
		return( -1 );
	}
#if defined (__sun)
        struct cdrom_tochdr cdth;
        ret = ioctl( fd, CDROMREADTOCHDR, &cdth);
        if( cdth.cdth_trk1 > 0 ) {
#else
	ret = ioctl( fd,  CDROM_DRIVE_STATUS, CDSL_CURRENT);
	if( ret == CDS_DISC_OK ) {
#endif
		close( fd );
		return( 1 );
	}
#if !defined(__sun)
/* Try to know if it is a loop device */
	ret = ioctl( fd, LOOP_GET_STATUS, &lInfo );
	close( fd );
	if( !ret )	return( 1 );
#else
	close( fd );
#endif
	return( 0 );
}
/*------------------------------------------------------------------------------
	STRINGDUREE2SEC-
Linux!jef 2007/01/30 22:07:02
------------------------------------------------------------------------------*/

int StringDuree2Sec( char * string )
{
	int sec = 0;
	int acc = 0;

	while( *string ) {
		if( isdigit( *string ) ) {
			acc *= 10;
			acc += *string - '0';
		}
		else {
			if( tolower( *string ) == 'h' ) { sec += acc * 3600; acc = 0; }
			if( tolower( *string ) == 'm' ) { sec += acc * 60; acc = 0; }
			if( tolower( *string ) == 's' ) { sec += acc     ; acc = 0; }
		}
		string++;
	}
	return( sec );
}
/*------------------------------------------------------------------------------
	ISLOOPDEVICEREADY-
Linux!jef 2007/02/12 20:55:27
------------------------------------------------------------------------------*/

int IsLoopDeviceReady( char * loopDevice )
{
#if !defined(__sun)
	struct loop_info lInfo;
	int fd;
	int ret;

	fd = open( loopDevice, O_RDONLY | O_NONBLOCK);
	if( fd < 0 )	return( 0 );
	ret = ioctl( fd, LOOP_GET_STATUS, &lInfo );
// fprintf(stderr,"(%s)=%d lInfo.lo_name(%s)\n", loopDevice, ret,lInfo.lo_name );
	close( fd );
	if( !ret )	return( 1 );
#endif
	return( 0 );
}

