/***************************************************************************
                          misc_sys.c  -  description
                             -------------------
    begin                : Fri Jan 17 2003
    copyright            : (C) 2003 by Tim-Philipp Müller
    email                : t.i.m@orange.net
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include <glib.h>  /* for G_OS_* */

#include "global.h"
#include "misc_sys.h"

#if defined(__linux__)
# include <sys/types.h>
# include <sys/sysinfo.h>
#endif

#if defined(__FreeBSD__)
# include <sys/types.h>
#endif

#if defined(__MacOSX__)
# include <sys/types.h>     /* TODO: is this right? check this when SF compile farm MacOSX server works again */
#endif

#if defined(G_OS_UNIX)
# include <sys/stat.h>
# include <sys/time.h>      /* for setrlimit/getrlimit */
# include <sys/resource.h>  /* for setrlimit/getrlimit */
# include <unistd.h>
#endif

#include <stdio.h>

/******************************************************************************
 *
 *   misc_sys_get_uptime_in_secs
 *
 *   gets the number of seconds the system has been up so far.
 *
 *   returns secs or 0 on error
 */

#if defined(__linux__)

time_t
misc_sys_get_uptime_in_secs (void)
{
	struct sysinfo s;

	if ( sysinfo(&s) == -1 )
		return 0;

	return (time_t) s.uptime;
}

#elif defined(__FreeBSD__)

#include <sys/time.h>

/* Daniel: Whups, FreeBSD *does* have a way of getting seconds since boot
 *
 * Tim: seems to give us an 'undefined reference' error on some/all freebsd
 *      boxes.
 */

time_t
misc_sys_get_uptime_in_secs (void)
{
/*
	struct timeval   t;

	getmicrouptime(&t);
	return (time_t) t.tv_sec;
*/
	return 0;
}

#else

time_t
misc_sys_get_uptime_in_secs (void)
{
	return 0;
}

#endif



/******************************************************************************
 *
 *   misc_sys_set_rlimit_to_max_open_fd_possible
 *
 *   Tries to set the value for the max. number of open
 *    file descriptors as high as possible
 *    (before we spawn the core for example)
 *
 ******************************************************************************/

#ifndef RLIMIT_OFILE
# define RLIMIT_OFILE RLIMIT_NOFILE
#endif

void
misc_sys_set_rlimit_to_max_open_fd_possible (void)
{
#if defined(G_OS_UNIX)
	struct rlimit  rlim;

	if (getrlimit(RLIMIT_OFILE, &rlim) == 0)
	{
		if (rlim.rlim_max == RLIM_INFINITY)
		{
			rlim.rlim_cur = 4096;
		}
		else
		{
			rlim.rlim_cur = rlim.rlim_max;
		}

		(void) setrlimit(RLIMIT_OFILE, &rlim);
	}
#endif

	return;
}


/******************************************************************************
 *
 *   misc_sys_get_max_open_files
 *
 *   Tries to find out the value for the max. number of open
 *    file descriptors that this user is allowed (assumption:
 *    this operates on a per-user or per-process basis)
 *
 *   returns TRUE if a value was retrieved and *max_open is set.
 *
 ******************************************************************************/

#if defined(G_OS_UNIX)

gboolean
misc_sys_get_max_open_files (glong *max_open)
{
	/* Note: _SC_STREAM_MAX returns a useless minimum maximum */
	g_return_val_if_fail ( max_open != NULL, FALSE );

	*max_open = (glong) sysconf(_SC_OPEN_MAX);

	return ( *max_open > 0 );
}

#else

gboolean
misc_sys_get_max_open_files (glong *max_open)
{
	return FALSE;
}

#endif


/******************************************************************************
 *
 *   misc_sys_get_pid_open_files
 *
 *   Tries to find out how many files the process specified by the given
 *    PID has open, counting the number of entries in /proc/<pid>/fd
 *
 *   returns TRUE if a value was found and *num_open is set.
 *
 ******************************************************************************/


#if defined(__linux__)

gboolean
misc_sys_get_pid_open_files (gulong pid, glong *num_open)
{
	GDir  *dir;
	gchar *fn;

	g_return_val_if_fail ( num_open != NULL, FALSE );

	fn = g_strdup_printf ("/proc/%lu/fd", pid);
	g_return_val_if_fail ( fn != NULL, FALSE );

	dir = g_dir_open(fn, 0, NULL);
	g_free(fn);

	if (!dir)
		return FALSE;

	*num_open = 0L;

	while (g_dir_read_name(dir))
		++(*num_open);

	g_dir_close(dir);

	return TRUE;
}


#else

gboolean
misc_sys_get_pid_open_files (gulong pid, glong *num_open)
{
	return FALSE;
}

#endif


/******************************************************************************
 *
 *   misc_sys_stat_file_size
 *
 *   Does a stat() on the filename and returns the filesize in bytes
 *    or -1 on error
 *
 ******************************************************************************/

#ifdef G_OS_UNIX

glong
misc_sys_stat_file_size(const gchar *filename)
{
	struct stat   logstat;

	if (stat (filename, &logstat) != 0)
		return -1;

	return (glong)logstat.st_size;
}

#else /* !G_OS_UNIX */

glong
misc_sys_stat_file_size(const gchar *filename)
{
	FILE  *handle;
	glong  ret = -1;

	handle = fopen(filename, "rb");

	if (handle)
	{
		if (fseek(handle, 0, SEEK_END) == 0)
		{
			ret = ftell(handle);
		}
		fclose(handle);
	}

	return ret;
}

#endif /* !G_OS_UNIX */



