/*****************************************************************************/
/* The development of this program is partly supported by IPA                */
/* (Information-Technology Promotion Agency, Japan).                         */
/*****************************************************************************/

/*****************************************************************************/
/*  util.c - utility function                                                */
/*  Copyright: Copyright (c) Hitachi, Ltd. 2004-2007                         */
/*             Authors: Yumiko Sugita (yumiko.sugita.yf@hitachi.com),        */
/*                      Satoshi Fujiwara (sa-fuji@sdl.hitachi.co.jp)         */
/*                                                                           */
/*  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.                                      */
/*                                                                           */
/*  This program is distributed in the hope that it will be useful,          */
/*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
/*  GNU General Public License for more details.                             */
/*                                                                           */
/*  You should have received a copy of the GNU General Public License        */
/*  along with this program; if not, write to the Free Software              */
/*  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA      */
/*****************************************************************************/

#include <sys/stat.h>
#include <sys/mount.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <dirent.h>
#include <mntent.h>



void uDumpN(char* buf, size_t n) {
	int	i, j, offset;
	char	s[16];
	char	c;

	for (i = 0; i < n; i++) {
		c = buf[i];
		offset = i % 16;
		printf("%02x", (unsigned char)c);
		s[offset] = isprint(c) ? c : ' ';
		if (offset == 15)
			printf("   \"%.*s\"\n", 16, s);
		else if (i == (n - 1)) {
			for (j = 0; j < 3 * (15 - offset); j++)
				printf(" ");
			printf("   \"%.*s\"\n", offset + 1, s);
		} else
			printf(" ");
	}
}

int uOpen(const char *pathname, int flags) {
	int	f;

	f = open(pathname, flags);
	if (f < 0)
		fprintf(stderr, "%s open failed. (%s)\n", pathname,
			strerror(errno));
	return f;
}

int uSeek(int f, off_t pos) {
	off_t	rc;

	rc = lseek(f, pos, SEEK_SET);
	if (rc < 0) {
		fprintf(stderr, "lseek failed. (%s)\n", strerror(errno));
		return -1;
	}
	return 0;
}

int uRead(int f, void* buf, size_t n) {
	int	rc;

	while ((rc = read(f, buf, n)) < 0 && errno == EINTR);
	if (rc < 0) {
		fprintf(stderr, "read failed. (%s)\n", strerror(errno));
		/*
		switch (errno) {
		case EINTR:
			fprintf(stderr, "  EINTR\n");
			break;
		case EAGAIN:
			fprintf(stderr, "  EAGAIN\n");
			break;
		case EIO:
			fprintf(stderr, "  EIO\n");
			break;
		case EISDIR:
			fprintf(stderr, "  EISDIR\n");
			break;
		case EBADF:
			fprintf(stderr, "  EBADF\n");
			break;
		case EINVAL:
			fprintf(stderr, "  EINVAL\n");
			break;
		case EFAULT:
			fprintf(stderr, "  EFAULT\n");
			break;
		default:
			fprintf(stderr, "  other\n");
			break;
		}
		*/
	}
	return rc;
}

int uWrite(int f, void* buf, size_t n) {
	int	rc;

	while ((rc = write(f, buf, n)) < 0 && errno == EINTR);
	if (rc < 0)
		fprintf(stderr, "write failed. (%s)\n", strerror(errno));
	return rc;
}

int uSeekRead(int f, off_t pos, void* buf, size_t n) {
	int	rc;

	rc = uSeek(f, pos);
	if (rc < 0)
		return rc;
	rc = uRead(f, buf, n);
	if (rc < 0)
		return rc;
#ifdef DEBUG2
	fprintf(stderr, "--- %lld (%016llx) ---\n", pos, pos);
	uDumpN(buf, n);
	fprintf(stderr, "---\n");
	fflush(stderr);
#endif
	return rc;
}

void *uCalloc(size_t nmemb, size_t n) {
	void	*p;

	p = calloc(nmemb, n);
	if (p == NULL)
		fprintf(stderr, "calloc failed. (%s)\n", strerror(errno));
	return p;
}

void *uMalloc(size_t n) {
	void	*p;

	p = malloc(n);
	if (p == NULL)
		fprintf(stderr, "malloc failed. (%s)\n", strerror(errno));
	return p;
}

void *uRealloc(void *ptr, size_t n) {
	void	*p;

	p = realloc(ptr, n);
	if (p == NULL)
		fprintf(stderr, "realloc failed. (%s)\n", strerror(errno));
	return p;
}

int uLstat(const char *pathname, struct stat *buf) {
	int	rc;

	rc = lstat(pathname, buf);
	if (rc < 0)
		fprintf(stderr, "lstat failed. (%s)\n", strerror(errno));
	return rc;
}

int uChdir(char *path) {
	int	rc;

	rc = chdir(path);
	if (rc < 0)
		fprintf(stderr, "\"%s\" chdir failed.(%s)\n",
			path, strerror(errno));
	return rc;
}

DIR *uOpendir(const char *pathname) {
	DIR	*d;

	d = opendir(pathname);
	if (!d)
		fprintf(stderr, "opendir failed. (%s)\n", strerror(errno));
	return d;
}

struct dirent* uReaddir(DIR *d) {
	struct dirent	*child;

	child = readdir(d);
	if (!child && errno == EBADF)
		fprintf(stderr, "readdir failed. (%s)\n", strerror(errno));
	return child;
}

int uClosedir(DIR *d) {
	int	rc;

	rc = closedir(d);
	if (rc < 0)
		fprintf(stderr, "closedir failed. (%s)\n", strerror(errno));
	return rc;
}

char *uGetCwd(char *buf, size_t *size) {
	char		*p;
	size_t		step = 256;

	while ((p = getcwd(buf, *size)) == NULL) {
		*size += step;
		buf = uRealloc(buf, *size);
		if (!buf)
			return NULL;
	}
	return p;
}

FILE *uSetmntent(const char *filename, const char *type) {
	FILE		*f;

	f = setmntent(filename, type);
	if (f == NULL)
		fprintf(stderr, "setmntent failed.(%s)\n", strerror(errno));
	return f;
}

static int isValidMntFlags(struct mntent* m) {
	if (strcmp(m->mnt_opts, "rw") != 0) {
		fprintf(stderr, "unknown mount option.(%s)\n", m->mnt_opts);
		return 0;
	}
	return 1;
}

int uSyncDisk(char* dev) {
	FILE		*f;
	struct mntent	*m;
	int		rc;

	if ((f = uSetmntent(MOUNTED, "r")) == NULL)
		return -1;
	while ((m = getmntent(f)) != NULL) {
		if (strcmp(dev, m->mnt_fsname) == 0) {
			break;
		}
	}
	endmntent(f);
	if (!m)
		/* this device is not mounted. */
		return 0;
	/*
	fprintf(stderr, "FIND: %s\n", m->mnt_fsname);
	*/

	if (!isValidMntFlags(m))
		return -1;
	rc = umount(m->mnt_dir);
	if (rc < 0) {
		fprintf(stderr, "umount failed.(%s)\n", strerror(errno));
		return -1;
	}
	rc = mount(m->mnt_fsname, m->mnt_dir, m->mnt_type, 0, NULL);
	if (rc < 0) {
		fprintf(stderr, "mount failed.(%s)\n", strerror(errno));
		return -1;
	}
	return 0;
}
