Logo Search packages:      
Sourcecode: s390-tools version File versions  Download package

zg.c

/*
 * zgetdump - Tool for copying and converting System z dumps
 *
 * Helper functions
 *
 * Copyright IBM Corp. 2001, 2010
 * Author(s): Michael Holzheu <holzheu@linux.vnet.ibm.com>
 */

#include <stdlib.h>
#include <limits.h>
#include "zgetdump.h"

#define MAX_EXIT_FN     10
#define MAX_DEV_RETRIES 1000

/*
 * Progress information
 */
00020 struct prog {
      u64   addr_next;
      u64   mem_size;
};

/*
 * At exit information
 */
00028 struct atexit {
      zg_atexit_fn_t    fn_vec[MAX_EXIT_FN];
      unsigned int      cnt;
};

/*
 * Temp devnode information
 */
00036 struct devnode {
      char  **vec;
      int   cnt;
};

/*
 * File local static data
 */
static struct {
      struct atexit     atexit;
      struct prog prog;
      struct devnode    devnode;
} l;

/*
 * Call all registered exit handlers
 */
static void exit_fn(void)
{
      unsigned int i;

      for (i = 0; i < l.atexit.cnt; i++)
            l.atexit.fn_vec[i]();
}

/*
 * Register exit handler
 */
void zg_atexit(zg_atexit_fn_t fn)
{
      if (l.atexit.cnt >= MAX_EXIT_FN)
            ABORT("Too many atexit handlers (%d)", l.atexit.cnt + 1);
      l.atexit.fn_vec[l.atexit.cnt] = fn;
      if (l.atexit.cnt == 0)
            atexit(exit_fn);
      l.atexit.cnt++;
}

/*
 * Exit function (For having exit gdb break point)
 */
void zg_exit(int rc)
{
      exit(rc);
}

/*
 * Alloc memory and check for errors
 */
void *zg_alloc(unsigned int size)
{
      void *ptr = calloc(size, 1);
      if (!ptr)
            ERR_EXIT("Alloc: Out of memory (%i KiB)", TO_KIB(size));
      return ptr;
}

/*
 * Realloc memory and check for errors
 */
void *zg_realloc(void *ptr, unsigned int size)
{
      void *new_ptr = realloc(ptr, size);
      if (!new_ptr)
            ERR_EXIT("Realloc: Out of memory (%i KiB)", TO_KIB(size));
      return new_ptr;
}

/*
 * Create duplicate for string
 */
char *zg_strdup(const char *str)
{
      char *new_str = strdup(str);

      if (!new_str)
            ERR_EXIT("Strdup: Out of memory (%s)\n", str);
      return new_str;
}

/*
 * Free memory
 */
void zg_free(void *ptr)
{
      free(ptr);
}

/*
 * Return path name of open file
 */
const char *zg_path(struct zg_fh *zg_fh)
{
      return zg_fh->path;
}

/*
 * Return stat buffer of open file
 */
const struct stat *zg_stat(struct zg_fh *zg_fh)
{
      return &zg_fh->sb;
}

/*
 * Open file
 */
struct zg_fh *zg_open(const char *path, int flags, enum zg_check check)
{
      struct zg_fh *zg_fh = zg_alloc(sizeof(*zg_fh));

      zg_fh->fh = open(path, flags);
      if (zg_fh->fh == -1) {
            if (check == ZG_CHECK_NONE)
                  goto fail;
            ERR_EXIT_ERRNO("Could not open \"%s\"", path);
      }
      if (stat(path, &zg_fh->sb) == -1) {
            if (check == ZG_CHECK_NONE)
                  goto fail;
            ERR_EXIT_ERRNO("Could not access file \"%s\"", path);
      }
      zg_fh->path = zg_strdup(path);
      return zg_fh;

fail:
      zg_free(zg_fh);
      return NULL;
}

/*
 * Close file
 */
void zg_close(struct zg_fh *zg_fh)
{
      close(zg_fh->fh);
      free(zg_fh);
}

/*
 * Read file
 */
ssize_t zg_read(struct zg_fh *zg_fh, void *buf, size_t cnt, enum zg_check check)
{
      size_t copied = 0;
      ssize_t rc;

      do {
            rc = read(zg_fh->fh, buf + copied, cnt - copied);
            if (rc == -1) {
                  if (check == ZG_CHECK_NONE)
                        return rc;
                  ERR_EXIT_ERRNO("Could not read \"%s\"", zg_fh->path);
            }
            if (rc == 0) {
                  if (check != ZG_CHECK)
                        return copied;
                  ERR_EXIT("Unexpected end of file for \"%s\"",
                         zg_fh->path);
            }
            copied += rc;
      } while (copied != cnt);
      return copied;
}

/*
 * Return file size
 */
u64 zg_size(struct zg_fh *zg_fh)
{
      return zg_fh->sb.st_size;
}

/*
 * Return file position
 */
off_t zg_tell(struct zg_fh *zg_fh, enum zg_check check)
{
      off_t rc;

      rc = lseek(zg_fh->fh, 0, SEEK_CUR);
      if (rc == -1 && check != ZG_CHECK_NONE)
            ERR_EXIT_ERRNO("Could not get file position for \"%s\"",
                         zg_fh->path);
      return rc;
}

/*
 * Seek to "off" relative to END
 */
off_t zg_seek_end(struct zg_fh *zg_fh, off_t off, enum zg_check check)
{
      off_t rc;

      rc = lseek(zg_fh->fh, off, SEEK_END);
      if (rc == -1 && check != ZG_CHECK_NONE)
            ERR_EXIT_ERRNO("Could not seek \"%s\"", zg_fh->path);
      return rc;
}

/*
 * Seek to "off" in file
 */
off_t zg_seek(struct zg_fh *zg_fh, off_t off, enum zg_check check)
{
      off_t rc;

      rc = lseek(zg_fh->fh, off, SEEK_SET);
      if (rc == -1 && check != ZG_CHECK_NONE)
            ERR_EXIT_ERRNO("Could not seek \"%s\"", zg_fh->path);
      if (rc != off && check == ZG_CHECK)
            ERR_EXIT("Could not seek \"%s\"", zg_fh->path);
      return rc;
}

/*
 * Seek from current position
 */
off_t zg_seek_cur(struct zg_fh *zg_fh, off_t off, enum zg_check check)
{
      off_t rc;

      rc = lseek(zg_fh->fh, off, SEEK_CUR);
      if (rc == -1 && check != ZG_CHECK_NONE)
            ERR_EXIT_ERRNO("Could not seek \"%s\"", zg_fh->path);
      return rc;
}

/*
 * Do ioctl and exit in case of an error
 */
int zg_ioctl(struct zg_fh *zg_fh, int rq, void *data, const char *op,
           enum zg_check check)
{
      int rc;

      rc = ioctl(zg_fh->fh, rq, data);
      if (rc == -1 && check != ZG_CHECK_NONE)
            ERR_EXIT_ERRNO("Operation \"%s\" failed on \"%s\"", op,
                         zg_fh->path);
      return rc;
}

/*
 * Return file type
 */
enum zg_type zg_type(struct zg_fh *zg_fh)
{
      struct mtop mtop;
      struct stat *sb = &zg_fh->sb;

      if (S_ISREG(sb->st_mode))
            return ZG_TYPE_FILE;
      if (S_ISBLK(sb->st_mode)) {
            if (minor(sb->st_rdev) % 4 == 0)
                  return ZG_TYPE_DASD;
            else
                  return ZG_TYPE_DASD_PART;
      }
      if (S_ISCHR(sb->st_mode)) {
            mtop.mt_count = 1;
            mtop.mt_op = MTTELL;
            if (zg_ioctl(zg_fh, MTIOCTOP, &mtop, "MTIOCTOP",
                       ZG_CHECK_NONE) != -1)
                  return ZG_TYPE_TAPE;
      }
      return ZG_TYPE_UNKNOWN;
}

/*
 * Initialize progress messages
 */
void zg_progress_init(const char *msg, u64 mem_size)
{
      STDERR("%s:\n", msg);
      l.prog.addr_next = 0;
      l.prog.mem_size = mem_size;
}

/*
 * Print progress
 */
void zg_progress(u64 addr)
{
      if (addr < l.prog.addr_next)
            return;

      STDERR("  %08Lu / %08Lu MB\n", TO_MIB(addr), TO_MIB(l.prog.mem_size));
      l.prog.addr_next += l.prog.mem_size / 6;
      l.prog.addr_next = MIN(l.prog.addr_next, l.prog.mem_size);
}

/*
 * Try to create device node in "dir"
 */
static char *devnode_create_dir(const char *dir, dev_t dev)
{
      char file_path[PATH_MAX];
      int i, fh, rc;

      for (i = 0; i < MAX_DEV_RETRIES; i++) {
            snprintf(file_path, PATH_MAX, "%s/zgetdump.%04d", dir, i);
            rc = mknod(file_path, S_IFBLK | S_IRWXU, dev);
            if (rc == -1) {
                  if (errno == EEXIST)
                        continue;
                  else
                        break;
            }

            /* Need this test to cover 'nodev'-mounted filesystems */
            fh = open(file_path, O_RDWR);
            if (fh == -1) {
                  remove(file_path);
                  break;
            }
            close(fh);
            return zg_strdup(file_path);
      }
      return NULL;
}

/*
 * Delete temporary device node
 */
static void devnode_remove(char *dev_node)
{
      if (remove(dev_node))
            ERR("Warning: Could not remove temporary file %s: %s",
                dev_node, strerror(errno));
      zg_free(dev_node);
}

/*
 * Remove all temporary device nodes
 */
static void devnode_remove_all(void)
{
      int i;

      for (i = 0; i < l.devnode.cnt; i++)
            devnode_remove(l.devnode.vec[i]);
      if (l.devnode.vec) {
            zg_free(l.devnode.vec);
            l.devnode.vec = NULL;
      }
      l.devnode.cnt = 0;
}

/*
 * Make temporary device node for input dev identified by its dev_t
 */
char *zg_devnode_create(dev_t dev)
{
      char *dir_vec[] = {getenv("TMPDIR"), "/tmp", getenv("HOME"), ".", "/"};
      char *file_path;
      unsigned int i;

      for (i = 0; i < ARRAY_ELEMENT_CNT(dir_vec); i++) {
            if (dir_vec[i] == NULL)
                  continue;
            file_path = devnode_create_dir(dir_vec[i], dev);
            if (file_path)
                  goto found;
      }
      ERR_EXIT_ERRNO("Unable to create temporary dev node");
      return NULL;
found:
      l.devnode.cnt++;
      l.devnode.vec = zg_realloc(l.devnode.vec, l.devnode.cnt *
                           sizeof(void *));
      l.devnode.vec[l.devnode.cnt - 1] = file_path;
      if (l.devnode.cnt == 1)
            zg_atexit(devnode_remove_all);
      return file_path;
}

Generated by  Doxygen 1.6.0   Back to index