/*
  (c) 1998 netEstate (http://www.netestate.de/, info@netestate.de),
Michael Brunnbauer & Markus Hendel, Gesellschaft fuer Netzwerkkommunikation bR
Am Bluetenanger 8, 80995 Muenchen, Germany

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
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-1307  USA
*/

#include "locklib.h"

int do_lock(char* lockfile,int flags=0)
{
  char buf[MAX_LINE_SIZE];
  string tmpfile;
  int handle,returncode;
  unsigned int pid,oldpid;
  struct stat filestat;

  pid=getpid();
  handle=open(lockfile,O_RDONLY);
  if (handle!=-1)
    {
      if (read(handle,buf,MAX_LINE_SIZE)<=0)
	{
	  log(LOG_WARN,__FILE__,__LINE__,ERROR_SYNTAX_ERROR,
              "cannot read lockfile %s",lockfile);
	  close(handle);
	  return -1;
	};
      close(handle);

      if (sscanf(buf,"%u",&oldpid)!=1)
	{
	  log(LOG_WARN,__FILE__,__LINE__,ERROR_SYNTAX_ERROR,
	      "lockfile %s is not an ASCII lock",lockfile);
	  return -1;
	};

      /* ours ? */
      if (oldpid==pid)
	{
	  log(LOG_WARN,__FILE__,__LINE__,ERROR_SYNTAX_ERROR,
	      "lockfile %s is ours (??)",lockfile);
	  return 1;
	};
      /* stale lock ? */
      if ((kill(oldpid,0)==-1) && errno == ESRCH)
	{
	  log(LOG_WARN,__FILE__,__LINE__,ERROR_SYNTAX_ERROR,
	      "stale lockfile %s",lockfile);
	  if (unlink(lockfile)==-1)
	    {
	      log(flags & LOCK_NOFATAL ? LOG_WARN : LOG_FATAL,
		  __FILE__,__LINE__,ERROR_UNSPECIFIED,
		  "cannot remove stale lockfile %s",lockfile);
	      return -1;
	    };
	};
    };

  if (gethostname(buf,MAX_LINE_SIZE)==-1)
    {
      log(flags & LOCK_NOFATAL ? LOG_WARN : LOG_FATAL,
	  __FILE__,__LINE__,ERROR_UNSPECIFIED,
	  "do_lock(): error with gethostname()");
      return -1;
    };
  tmpfile=(string) lockfile+"."+(string) buf;
  snprintf(buf,MAX_LINE_SIZE,"%u",pid);
  tmpfile+=buf;

  handle=open(tmpfile,O_RDWR|O_CREAT,S_IRUSR|S_IWUSR);
  if (handle==-1)
    {
      log(flags & LOCK_NOFATAL ? LOG_WARN : LOG_FATAL,
	  __FILE__,__LINE__,ERROR_UNSPECIFIED,
	  "do_lock(): cannot create file %s",(char*) tmpfile);
      return -1;
    };
  snprintf(buf,MAX_LINE_SIZE,"     %u\n",pid);
  if (write(handle,buf,strlen(buf))!=(ssize_t) strlen(buf))
    {
      log(flags & LOCK_NOFATAL ? LOG_WARN : LOG_FATAL,
          __FILE__,__LINE__,ERROR_UNSPECIFIED,
          "do_lock(): cannot write to file %s",(char*) tmpfile);
      return -1;
    };
  if (close(handle)==-1)
    {
      log(flags & LOCK_NOFATAL ? LOG_WARN : LOG_FATAL,
	  __FILE__,__LINE__,ERROR_UNSPECIFIED,
	  "do_lock(): cannot close file %s",(char*) tmpfile);
      return -1;
    };

  link(tmpfile,lockfile);

  if (stat(tmpfile,&filestat)==-1)
    {
      log(flags & LOCK_NOFATAL ? LOG_WARN : LOG_FATAL,
	  __FILE__,__LINE__,ERROR_UNSPECIFIED,
	  "do_lock(): cannot stat file %s",(char*) tmpfile);
      return -1;
    };

  if (filestat.st_nlink==2)
    {
      /* lock OK */
      returncode=1;
    }
  else
    {
      /* lock failed */
      returncode=0;
    };

  if (unlink(tmpfile)==-1)
    {
      log(flags & LOCK_NOFATAL ? LOG_WARN : LOG_FATAL,
	  __FILE__,__LINE__,ERROR_UNSPECIFIED,
	  "do_lock(): cannot remove file %s",(char*) tmpfile);
      return -1;
    }

  return returncode;
}

int do_unlock(char* lockfile,int flags=0)
{
  if (unlink(lockfile)==-1)
    {
      log(flags & LOCK_NOFATAL ? LOG_WARN : LOG_FATAL,
	  __FILE__,__LINE__,ERROR_UNSPECIFIED,
          "do_unlock(): cannot remove file %s",(char*) lockfile);
      return -1;
    };
  return 1;
}


