/*
 * ipwstatus for IPWireless USB Modem
 *
 * Authors:
 *   Stephen Blackheath <stephen@blacksapphire.com>,
 *   Ben Martel (benm@symmetric.co.nz>
 *
 *   Copyright (C) 2004 by Symmetric Systems Ltd (NZ)
 *
 * Released under the GNU General Public Licence
 */

/*
 * This method of locking tty devices complies with the FSSTND, the
 * Linux Filesystem Hierarchy Standard, and will therefore interoperate
 * with pppd and minicom and others.
 */

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <signal.h>

static char lockfile[255];

/*
 * lock the specified tty device.
 *
 * returns 0 if successful, -1 if failed.
 * On failure, errno is EAGAIN if the device really is locked by another process.
 */
int tty_lock(char* dev)
{
  char buf[20];
  int fd, pid, n;
  char lockfile_tmp[sizeof(lockfile)];

  char *p;

  lockfile[0] = 0;

  while ((p = strchr(dev, '/')) != NULL)
    dev = p + 1;
  sprintf(lockfile_tmp, "/var/lock/LCK..%s", dev);

  while ((fd = open(lockfile_tmp, O_EXCL | O_CREAT | O_RDWR, 0644)) < 0) {
    if (errno != EEXIST)
      return -1;

      /* If the lock file already exists... */
    fd = open(lockfile_tmp, O_RDONLY, 0);
    if (fd < 0)
      return -1;
    n = read(fd, buf, 11);
    close(fd);

      /* Then fetch the pid from it */
    if (n < 0)
      n = 0;
    buf[n] = 0;
    pid = atoi(buf);

      /* If it's me, then all is well. */
    if (pid == getpid())
      return 0;

      /* If the locking process doesn't exist, ... */
    if (pid == 0 || (kill(pid, 0) == -1 && errno == ESRCH)) {
        /* then attempt to write over the lock file. */
      fd = open(lockfile_tmp, O_CREAT | O_TRUNC | O_WRONLY, 0644);
        /* If this fails, then we continue as if we locked it, but issue a warning. */
      if (fd < 0) {
        fprintf(stderr, "Warning! Can't write over stale lock file %s\n", lockfile_tmp);
        return 0;
      }
      break;
    }
    else {
        /* If the locking process does exist, then we fail to lock */
      errno = EAGAIN;
      return -1;
    }
    break;
  }

  pid = getpid();
  sprintf(buf, "%10d\n", pid);
  write (fd, buf, 11);
  close(fd);
  strcpy(lockfile, lockfile_tmp);
  return 0;
}

void tty_unlock()
{
  if (lockfile[0]) {
    unlink(lockfile);
    lockfile[0] = 0;
  }
}

