/* SAMHAIN file system integrity testing                                   */
/* Copyright (C) 1999, 2000 Rainer Wichmann                                */
/*                                                                         */
/*  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., 675 Mass Ave, Cambridge, MA 02139, USA.              */

#include "config_xor.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#undef  FIL__
#define FIL__  _("sh.fifo.c")


#include "samhain.h"
#include "sh_mem.h"
#include "sh_unix.h"

#if defined(HAVE_MLOCK) && !defined(HAVE_BROKEN_MLOCK)
#include <sys/mman.h>
#endif

#define SH_FIFO_MAX 128

struct dlist {
  /*@null@*//*@dependent@*/ struct dlist * next;
  char         * data;
  /*@null@*//*@dependent@*/ struct dlist * prev;
};

typedef struct fifo_str {
  /*@null@*//*@dependent@*/ struct dlist * head_ptr;
  /*@null@*//*@dependent@*/ struct dlist * tail_ptr;
  int            fifo_cts;
} SH_FIFO;



/* push an item on the head of the list
 */
int push_list (SH_FIFO * fifo, char * indat)
{
  struct dlist * item;
  size_t         len;

  SL_ENTER(_("push_list"));

  if (indat == NULL || fifo == NULL)
    {
      SL_RETURN((-1), _("push_list"));
    }

  if (fifo->fifo_cts > SH_FIFO_MAX)
    {
      SL_RETURN((-1), _("push_list"));
    }

  len             = sl_strlen(indat);

  if (len == 0)
    {
      SL_RETURN((-1), _("push_list"));
    }
  item            = SH_ALLOC(sizeof(struct dlist));
  /*@i@*/ item->data      = SH_ALLOC(len+1);
  
  if (NULL != sl_strstr (indat, _("LOGKEY")))
    {
      MLOCK(item->data, (len+1));
      ;
    }

  strcpy (item->data, indat);                   /* known to fit  */
  item->data[len] = '\0';

  if (fifo->tail_ptr == NULL)
    {
      fifo->tail_ptr = item;
      item->prev     = NULL;
    }
  else
    {
      /*@i@*/ fifo->head_ptr->prev = item;
      item->prev           = NULL;
    }

  item->next      = fifo->head_ptr;
  fifo->head_ptr  = item;

  ++(fifo->fifo_cts);

  SL_RETURN((fifo->fifo_cts), _("push_list"));
}

/* push an item on the tail of the list
 */
int push_tail_list (SH_FIFO * fifo, char * indat)
{
  struct dlist * item;
  size_t         len;

  SL_ENTER(_("push_tail_list"));

  if (indat == NULL || fifo == NULL)
    {
      SL_RETURN((-1), _("push_tail_list"));
    }

  if (fifo->fifo_cts > SH_FIFO_MAX)
    {
      SL_RETURN((-1), _("push_tail_list"));
    }

  len = sl_strlen(indat);
  if (len == 0)
    {
      SL_RETURN((-1), _("push_list"));
    }

  item            = SH_ALLOC(sizeof(struct dlist));
  /*@i@*/item->data      = SH_ALLOC(len+1);

  if (NULL != sl_strstr (indat, _("LOGKEY")))
    {
      MLOCK(item->data, (len+1));
      ;
    }

  strcpy (item->data, indat);                          /* known to fit  */
  item->data[len] = '\0';

  if (fifo->head_ptr == NULL)
    {
      item->next     = NULL;
      fifo->head_ptr = item;
    }
  else
    {
      item->next           = NULL;
      fifo->tail_ptr->next = item;
    }

  item->prev     = fifo->tail_ptr;
  fifo->tail_ptr = item;

  ++(fifo->fifo_cts);

  SL_RETURN((0), _("push_tail_list"));
}

/* pop an item from the tail of the list
 */
/*@null@*/ char * pop_list (SH_FIFO * fifo)
{
  size_t         len;
  struct dlist * getit;
  char         * retval;

  SL_ENTER(_("pop_list"));

  if (fifo == NULL || fifo->tail_ptr == NULL)
    {
      SL_RETURN (NULL, _("pop_list"));
    }

  getit       = fifo->tail_ptr;

  if (getit->prev == NULL) /* last element */
    {
      fifo->tail_ptr = NULL;
      fifo->head_ptr = NULL;
    } 
  else
    {
      fifo->tail_ptr        = getit->prev;
      fifo->tail_ptr->next  = getit->next;
    } 
  
  len         = sl_strlen(getit->data);
  retval      = SH_ALLOC(len+1);
  strcpy (retval, getit->data);                        /* known to fit  */
  retval[len] = '\0';
 
  memset(getit->data, 0, len);

  if (NULL != sl_strstr (retval, _("LOGKEY")))
    {
      MUNLOCK(getit->data, (len+1));
      ;
    }

  SH_FREE(getit->data);
  SH_FREE(getit);

  --(fifo->fifo_cts);

  SL_RETURN (retval, _("pop_list"));
}




