Logo Search packages:      
Sourcecode: latrine version File versions  Download package

latrine.c

/* vim: set noet ts=4:
 *
 * Copyright (c) 2002-2007 Martin A. Godisch <martin@godisch.de>.
 *
 * 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., 51 Franklin
 * St, Fifth Floor, Boston, MA 02110-1301, USA.
 */
#include <latrine.h>
#include <charset.h>
#include <data.h>
#include <fcntl.h>
#include <memory.h>
#include <options.h>
#include <screen.h>
#include <signal.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdarg.h>
#include <stdio.h>

#define MAXERRMSG 256

FILE *debug = NULL;

static char *lockfile = NULL;
static char *errbuf   = NULL;

void errmsg(const char *msg, ...)
{
      static size_t nmsg   = 0;
      char buffer[BUFSIZE] = ""; /* FIXME: check for overflow below */
      char *i = (char*)msg;
      va_list ap;
      size_t n;

      if (nmsg == -1)
            return;
      if (nmsg >= MAXERRMSG) {
            strncpy(buffer, _("too many error messages, stopping here"), BUFSIZE);
            nmsg = -1;
      } else {
            va_start(ap, msg);
            while ((i = index(msg, '%')) != NULL) {
                  strncat(buffer, msg, i - msg);
                  switch (*++i) {
                  case 'c':
                        sprintf(buffer + strlen(buffer), "%c", (char)va_arg(ap, int));
                        break;
                  case 'd':
                        sprintf(buffer + strlen(buffer), "%d", va_arg(ap, int));
                        break;
                  case 'm':
                        sprintf(buffer + strlen(buffer), "%m");
                        break;
                  case 's':
                        sprintf(buffer + strlen(buffer), "%s", va_arg(ap, char*));
                        break;
                  case 'X':
                        sprintf(buffer + strlen(buffer), "%04lX", va_arg(ap, unsigned long));
                        break;
                  case '%':
                        strcat(buffer, "%");
                        break;
                  default:
                        assert(0);
                  }
                  msg = ++i;
            }
            va_end(ap);
            strcat(buffer, msg);
            nmsg++;
      }
      if ((errbuf = realloc(errbuf, (n = errbuf == NULL ? 0 : strlen(errbuf)) + strlen(PACKAGE_NAME) + strlen(buffer) + 4)) != NULL)
            sprintf(errbuf + n, "%s: %s\n", PACKAGE_NAME, buffer);
}

static inline void set_title(int set)
{
      static char *term = NULL;

      if ((term = getenv("TERM")) == NULL)
            return;
      if (strncmp(term, "xterm", 5) == 0) {
            if (set) {
                  /* printf("%c[21t", '\033'); FIXME */
                  printf("%c]0;%s%c", '\033', PACKAGE_NAME, '\007');
            } else
                  printf("%c]0;%s%c", '\033', "xterm", '\007');
            return;
      }
}

static void bye(void)
{
      endwin();
      save_wordlist();
      if (debug)
            fclose(debug);
      set_title(0);
      if (lockfile != NULL && unlink(lockfile) != 0)
            errmsg("unlink: %s: %m", lockfile);
      if (errbuf != NULL)
            fprintf(stderr, "%s", errbuf);
}

static RETSIGTYPE handler(int signo)
{
      exit(0);
}

/* make a lockfile
 *
 * FIXME: make this user + dictionary dependent
 *
 * returns  0: success
 * returns -1: failure
 */
static int makelock(int force)
{
      FILE  *F  = NULL;
      pid_t pid = 0;
      int   fd  = 0, i = 0;
      char  *c  = NULL;
      char buffer[BUFSIZE];
      char proc[BUFSIZE];

      if ((fd = open(lockfile, O_WRONLY | O_CREAT | (force ? 0 : O_EXCL), 0666)) < 0) {
            if (errno == EEXIST) {
                  if ((F = fopen(lockfile, "r")) != NULL) {
                        i = fscanf(F, "%u", &pid);
                        fclose(F);
                        snprintf(proc, sizeof(proc), "/proc/%u/exe", pid);
                        if (i == 1 && ((i = readlink(proc, buffer, BUFSIZE - 1)) >= 0 || errno == ENOENT)) {
                              buffer[i] = 0;
                              if (i < 0 || ((c = rindex(buffer, '/')) != NULL && strcmp(c + 1, "latrine") != 0)) {
                                    errmsg(_("found stale lock file (pid %d)"), pid);
                                    return makelock(1);
                              }
                        }
                  }
                  errmsg(_("already running (pid %d)"), pid);
                  lockfile = NULL;
                  exit(1);
            }
            errmsg("open: %s: %m", lockfile);
            return -1;
      }
      if ((F = fdopen(fd, "w")) != NULL) {
            fprintf(F, "%u\n", getpid());
            fclose(F);
      } else
            close(fd);
      return 0;
}

int main(int argc, char *argv[])
{
      static int signals[] = {SIGALRM, SIGHUP, SIGINT, SIGPIPE, SIGTERM, SIGUSR1, SIGUSR2, 0};
      struct stat dummy;
      char *home = NULL;
      char *path = NULL;
      int  force = 0;
      int  n;

      assert(sizeof(char) == 1);
      atexit(bye);
      setlocale(LC_ALL, "");
      bindtextdomain("latrine", LOCALEDIR);
      textdomain("latrine");
      if ((home = getenv("HOME")) != NULL) {
            path = (char*)MALLOC((n = strlen(home)) + 9 + 7 + 1);
            sprintf(path, "%s/.latrine", home);
      } else {
            path = (char*)MALLOC(8 + 7 + 1);
            sprintf(path, ".latrine");
      }
      if (debug)
            fprintf(debug, "using config directory %s\n", path);
      if (stat(path, &dummy) != 0 && errno == ENOENT && mkdir(path, 0777) != 0) {
            errmsg("mkdir: %s: %m", path);
            exit(1);
      }
      strcat(path, "/config");
      do_conf(SYSCONFFILE);
      do_conf(path);
      do_opts(argc, argv, &force);
      lockfile = (char*)REALLOC(path, strlen(wordfile) + 6);
      sprintf(lockfile, "%s.lock", wordfile);
      for (n = 0; signals[n] != 0; n++)
            if (signal(signals[n], handler) == SIG_ERR)
                  errmsg("signal: %d: %m", signals[n]);
      makelock(force);
      set_title(1);
      init_screen(1);
      load_keymap(0, keymap[0]);
      load_keymap(1, keymap[1]);
      if (load_wordlist() == -1)
            exit(1);
      running();
      exit(0);
}

Generated by  Doxygen 1.6.0   Back to index