home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / news / nn.tar / nn-6.5.1 / proto.c < prev    next >
C/C++ Source or Header  |  1995-04-29  |  5KB  |  257 lines

  1. /*
  2.  *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  3.  *
  4.  *    Master/slave communication and locking.
  5.  */
  6.  
  7. #include "config.h"
  8. #include <signal.h>
  9. #include <errno.h>
  10. #include <pwd.h>
  11. #include "proto.h"
  12.  
  13. /* proto.c */
  14.  
  15. static void write_lock __APROTO((char *lock, char *operation));
  16. static int read_lock __APROTO((char *lock));
  17.  
  18.  
  19. #ifndef ACCOUNTING
  20. #ifdef AUTHORIZE
  21. #define ACCOUNTING
  22. #endif
  23. #endif
  24.  
  25. import char *master_directory, *db_directory;
  26.  
  27. #define HOSTBUF 80
  28. export char proto_host[HOSTBUF];    /* host having the lock */
  29.  
  30. /*
  31.  *    When setting a lock, we must check a little later that
  32.  *    we really got the lock set, i.e. that another process
  33.  *    didn't set it at the same time!
  34.  */
  35.  
  36. #define LOCK_SAFETY    5    /* seconds */
  37.  
  38. /*
  39.  *    proto_lock(program, mode)
  40.  *
  41.  *    Returns:
  42.  *    -1    Not running.
  43.  *    0    Running, no permission (PL_WAKEUP_SOFT)
  44.  *    0    Lock set (PL_SET)
  45.  *    1    Lock not set (PL_SET)  (another is running)
  46.  *    1       Locked and running (PL_WAKEUP)
  47.  *    pid    Locked and running (PL_CHECK)
  48.  */
  49.  
  50. static void
  51. write_lock(lock, operation)
  52. char *lock, *operation;
  53. {
  54.     FILE *m_pid;
  55.     char host[HOSTBUF];
  56.  
  57.     m_pid = open_file(lock, OPEN_CREATE);
  58.     if (m_pid == NULL)
  59.     sys_error("Cannot %s lock file: %s", operation, lock);
  60.     nn_gethostname(host, HOSTBUF);
  61.     fprintf(m_pid, "%d\n%s\n", process_id, host);
  62.     fclose(m_pid);
  63. }
  64.  
  65. static int read_lock(lock)
  66. char *lock;
  67. {
  68.     FILE *m_pid;
  69.     char host[HOSTBUF];
  70.     char pid[10];
  71.     
  72.     pid[0] = NUL;
  73.     proto_host[0] = NUL;
  74.     
  75.     m_pid = open_file(lock, OPEN_READ);
  76.     if (m_pid == NULL) return -2;    /* no lock */
  77.     fgets(pid, 10, m_pid);
  78.     fgets(proto_host, HOSTBUF, m_pid);
  79.     fclose(m_pid);
  80.  
  81.     if (pid[0] == NUL) return 0;    /* corrupted lock */
  82.     
  83.     if (proto_host[0] != NUL) {
  84.     substchr(proto_host, NL, NUL);
  85.     nn_gethostname(host, HOSTBUF);
  86.     if (strncmp(proto_host, host, HOSTBUF) != 0)
  87.         return -1;            /* locked by another host */
  88.     proto_host[0] = NUL;
  89.     }
  90.     return atoi(pid);
  91. }
  92.  
  93. int
  94. proto_lock(prog, command)
  95. int prog;
  96. int command;
  97. {
  98.     int try, pid;
  99.     char *lock = NULL;
  100.  
  101.     switch (prog) {
  102.      case I_AM_MASTER:
  103.      case I_AM_EXPIRE:
  104.     lock = relative(master_directory, "MPID");
  105.     break;
  106.      case I_AM_SPEW:
  107.     lock = relative(master_directory, "WPID");
  108.     break;
  109. #ifdef ACCOUNTING
  110.      case I_AM_ACCT:
  111.     lock = relative(db_directory, "LCK..acct");
  112.     break;
  113. #endif
  114.      case I_AM_NN:
  115.     lock = relative(nn_directory, "LOCK");
  116.     break;
  117.      default:
  118.     sys_error("Invalid LOCK prog");
  119.     }
  120.  
  121.     if (command == PL_TRANSFER) {
  122.     write_lock(lock, "transfer");
  123.     return 1;
  124.     }
  125.  
  126.     if (command == PL_CLEAR)
  127.     goto rm_lock;
  128.  
  129.     try = 1;
  130.  again:
  131.  
  132.     switch (pid = read_lock(lock)) {
  133.      case -2:
  134.     goto no_lock;
  135.      case -1:            /* wrong host */
  136.     return 1;
  137.      case 0:
  138.      case 1:
  139.      case 2:            /* corrupted lock file */
  140.     if (who_am_i == I_AM_NN) goto rm_lock;
  141.     if (--try < 0) goto rm_lock;
  142.     sleep(LOCK_SAFETY);    /* maybe it is being written */
  143.     goto again;
  144.      default:
  145.     break;
  146.     }    
  147.  
  148.     if (kill(pid, command == PL_TERMINATE ? SIGHUP : SIGALRM) == 0) {
  149.     switch (command) {
  150.      case PL_SET_QUICK:
  151.         sleep(1);
  152.         goto again;
  153.  
  154.      case PL_SET_WAIT:
  155.      case PL_CLEAR_WAIT:
  156.         sleep(30);
  157.         goto again;
  158.  
  159.      case PL_CHECK:
  160.         return pid;
  161.  
  162.      default:
  163.         return 1;
  164.     }
  165.     }
  166.  
  167.     if (command == PL_CHECK)
  168.     return (errno == EPERM) ? pid : -1;
  169.     if (command == PL_WAKEUP_SOFT)
  170.     return (errno == EPERM) ? 0 : -1;
  171.  
  172.     /* lock file contains a non-existing process, or a process with */
  173.     /* wrong owner, ie. neither master or expire, so remove it */
  174.  
  175.  rm_lock:
  176.     unlink(lock);
  177.  
  178.  no_lock:
  179.     if (command != PL_SET && command != PL_SET_QUICK && command != PL_SET_WAIT)
  180.     return -1;
  181.  
  182.     write_lock(lock, "create");
  183.  
  184.     /* a user will not start nn twice at the exact same time! */
  185.     if (who_am_i == I_AM_NN || command == PL_SET_QUICK) return 0;
  186.  
  187.     sleep(LOCK_SAFETY);
  188.  
  189.     if (read_lock(lock) != process_id)
  190.     return 1;    /* somebody stole the lock file */
  191.     return 0;     /* lock is set */
  192. }
  193.  
  194. FILE *open_gate_file(mode)
  195. int mode;
  196. {
  197.     char *gate, *err;
  198.     FILE *gf;
  199.  
  200.     gate = relative(master_directory, "GATE");
  201.     gf = open_file(gate, mode);
  202.     err = NULL;
  203.  
  204.     switch (mode) {
  205.      case OPEN_READ:
  206.     if (gf != NULL) {
  207.         if (unlink(gate) == 0) break;
  208.         err = "unlink";
  209.         break;
  210.     }
  211.     if (errno != ENOENT) err = "read";
  212.     break;
  213.     
  214.      default:
  215.     if (gf != NULL) chmod(gate, 0644); /* override restrictive umask */
  216.     /* caller must complain if cannot open! */
  217.     break;
  218.     }
  219.  
  220.     if (err != NULL) {
  221.     sys_warning("Cannot %s %s (err=%d).  Check modes!!", err, gate, errno);
  222.     if (gf != NULL) fclose(gf);
  223.     return NULL;
  224.     }
  225.     return gf;
  226. }
  227.  
  228. void
  229. send_master(command, gh, opt, arg)
  230. char command;
  231. group_header *gh;
  232. char opt;
  233. long arg;
  234. {
  235.     FILE *gate;
  236.  
  237.     gate = open_gate_file(OPEN_APPEND);
  238.  
  239.     if (gate == NULL) {
  240.     printf("Cannot send to master (check GATE file)\n");
  241.     return;
  242.     }
  243.  
  244.     fprintf(gate, "%c;%ld;%c;%ld;%s %s;\n",
  245.         command, gh == NULL ? -1L : gh->group_num, opt, arg,
  246.         user_name(), date_time((time_t)0));
  247.  
  248.     fclose(gate);
  249.  
  250.     log_entry('A', "SEND %c %s %c %ld",
  251.           command, gh == NULL ? "(all)" : gh->group_name, opt, arg);
  252.  
  253.     if (who_am_i == I_AM_ADMIN)
  254.     proto_lock(I_AM_MASTER, PL_WAKEUP_SOFT);
  255. }
  256.  
  257.