/* lock.c -- Lock file handling routines (UUCP style)
    Copyright 1998 - 2012 SCS GmbH & Co. KG, Hanau, Germany
    written by Peter Mack (peter.mack@scs-ptc.com)
    
    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-1307  USA
*/

#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>

#include "lock.h"

int lock_device (char *device)
{
	char lckf[128];
	int lfh;
	pid_t lckpid;
	char *devicename;
	char lckpidstr[20];
	int nb;
	struct stat buf;

	devicename = strrchr (device, '/');
	snprintf (lckf, 128, "%s/%s%s", LF_PATH, LF_PREFIX, (devicename ? (devicename + 1) : device));

	/* 
	 * Check if there's already a LCK..* file
	 */
	if (stat (lckf, &buf) == 0) {
		/* 
		 * we must now expend effort to learn if it's stale or not.
		 */
		if ((lfh = open (lckf, O_RDONLY)) != -1) {
			nb = read (lfh, &lckpidstr, min (20, buf.st_size));
			if (nb > 0) {
				lckpidstr[nb] = 0;
				sscanf (lckpidstr, "%d", &lckpid);
				if (kill (lckpid, 0) == 0) {
					fprintf (stderr, "Device %s is locked by process %d\n", device, lckpid);
					return -1;
				}

				/* 
				 * The lock file is stale. Remove it.
				 */
				if (unlink (lckf)) {
					fprintf (stderr, "Unable to unlink stale lock file \"%s\"\n", lckf);
					return -1;
				}
			} else {
				fprintf (stderr, "Cannot read from lock file \"%s\"\n", lckf);
				return -1;
			}
		} else {
			fprintf (stderr, "Cannot open existing lock file\"%s\"\n", lckf);
			return -1;
		}
	}

	if ((lfh = open (lckf, O_WRONLY | O_CREAT | O_EXCL, S_IWRITE | S_IREAD | S_IRGRP | S_IROTH)) < 0) {
		fprintf (stderr, "Cannot create lockfile. Sorry.\n");
		return -1;
	}
	snprintf (lckpidstr, 20, "%10d\n", getpid ());
	write (lfh, lckpidstr, strlen (lckpidstr));
	close (lfh);

	return 0;

}

int unlock_device (char *device)
{
	char lckf[128];
	char *devicename;

	devicename = strrchr (device, '/');
	snprintf (lckf, 128, "%s/%s%s", LF_PATH, LF_PREFIX, (devicename ? (devicename + 1) : device));

	if (unlink (lckf)) {
		fprintf (stderr, "Unable to unlink lock file \"%s\"\n", lckf);
		return -1;
	}

	return 0;
}
