home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume22 / nn6.4 / part04 / global.c
Encoding:
C/C++ Source or Header  |  1990-06-07  |  12.0 KB  |  660 lines

  1. /*
  2.  *    (c) Copyright 1990, Kim Fabricius Storm.  All rights reserved.
  3.  *
  4.  *    Global declarations and auxiliary functions.
  5.  */
  6.  
  7. #include <signal.h>
  8. #include <errno.h>
  9. #include <pwd.h>
  10. #include "config.h"
  11. #include "patchlevel.h"
  12.  
  13. export char *home_directory;
  14. export char *nn_directory;        /* ~/.nn */
  15. export char *news_directory;        /* /usr/spool/news */
  16. export char *news_lib_directory;     /* /usr/lib/news */
  17. export char *lib_directory;        /* /usr/local/lib/nn */
  18. export char *master_directory;        /* = lib */
  19. export char *help_directory;        /* = lib/help */
  20. export char *bin_directory = BIN_DIRECTORY;
  21.  
  22. export char *db_directory;    /* /usr/spool/nn or NEWS_DIR/.nn */
  23. export char *db_data_directory;    /* ..../DATA     or undefined    */
  24.  
  25. export char *news_active;    /* NLIB/active or DB/ACTIVE */
  26.  
  27. export char *pager;
  28.  
  29. export char *log_file;            /* = lib/Log */
  30. export char *log_entry_filter = NULL;
  31.  
  32. export char *temp_file;
  33.  
  34. #ifndef TMP_DIRECTORY
  35. #define TMP_DIRECTORY "/usr/tmp"
  36. #endif
  37. export char *tmp_directory = TMP_DIRECTORY;
  38.  
  39. export char version_id[32];
  40.  
  41. export unsigned short user_id, group_id;
  42. export int process_id;
  43. export int who_am_i;
  44. export int dont_write_console = 0;
  45.  
  46. #ifdef HAVE_MULTIGROUP
  47. #ifndef NGROUPS
  48. #include <sys/param.h>
  49. #endif
  50. #ifndef GIDSET_TYPE
  51. #define GIDSET_TYPE int
  52. #endif
  53. static int ngroups;
  54. static GIDSET_TYPE gidset[NGROUPS];
  55.  
  56. static in_grplist(gid)
  57. GIDSET_TYPE gid;
  58. {
  59.     int n;
  60.  
  61.     for (n = 0; n < ngroups; ++n)
  62.     if (gidset[n] == gid) return 1;
  63.  
  64.     return 0;
  65. }
  66.  
  67. #define group_access(gpid)    in_grplist((GIDSET_TYPE)(gpid))
  68. #else
  69. #define group_access(gid)    ((gid) == group_id)
  70. #endif
  71.  
  72. /* signal handler interface */
  73.  
  74. export int s_hangup        = 0;    /* hangup signal */
  75. export int s_keyboard        = 0;    /* keyboard interrupt */
  76. export int s_pipe        = 0;    /* broken pipe */
  77. export int s_redraw        = 0;    /* redraw signal (if job control) */
  78.  
  79. sig_type catch_hangup(n)
  80. {
  81.     signal(n, SIG_IGN);
  82.  
  83.     s_hangup++;
  84. }
  85.  
  86. static sig_type catch_keyboard(n)
  87. {
  88.     s_keyboard++;
  89.  
  90. #ifdef RESET_SIGNAL_WHEN_CAUGHT
  91.     signal(n, catch_keyboard);
  92. #endif
  93. }
  94.  
  95. static sig_type catch_pipe(n)
  96. {
  97.     s_pipe++;
  98.  
  99. #ifdef RESET_SIGNAL_WHEN_CAUGHT
  100.     signal(n, catch_pipe);
  101. #endif
  102. }
  103.  
  104. #ifdef HAVE_JOBCONTROL
  105. static sig_type catch_suspend(n)
  106. {
  107.     s_redraw++;
  108.  
  109. #ifdef RESET_SIGNAL_WHEN_CAUGHT
  110.     signal(n, catch_suspend);
  111. #endif
  112.  
  113.     suspend_nn();
  114. }
  115. #endif
  116.  
  117.  
  118. init_global()
  119. {
  120.     unsigned short getuid(), getgid();
  121.     int getpid();
  122.     int suspend_nn();
  123.  
  124.     if (who_am_i != I_AM_NN) {
  125.     signal(SIGINT,  SIG_IGN);
  126.     signal(SIGQUIT, SIG_IGN);
  127.     }
  128.     signal(SIGTERM, catch_hangup);
  129.     signal(SIGHUP,  catch_hangup);
  130.     signal(SIGPIPE, catch_pipe);
  131.     signal(SIGALRM, SIG_IGN);
  132.  
  133. #ifdef SIGPWR
  134.     signal(SIGPWR, catch_hangup);
  135. #endif
  136.  
  137.     sprintf(version_id, "%s.%d #%d", RELEASE, PATCHLEVEL,
  138. #include "update.h"
  139.         );
  140.  
  141.     user_id = getuid();
  142.  
  143. #ifdef HAVE_MULTIGROUP
  144.     ngroups = getgroups(NGROUPS, gidset);    /* Get users's group set */
  145.     group_id = gidset[0];    /* not used, but just in case... */
  146. #else
  147.     group_id = getgid();
  148. #endif
  149.  
  150.     process_id = getpid();
  151.  
  152. #ifdef NEWS_DIRECTORY
  153.     news_directory = NEWS_DIRECTORY;
  154. #else
  155.     news_directory = "/usr/spool/news";
  156. #endif
  157.  
  158. #ifdef DB_DIRECTORY
  159.     db_directory = DB_DIRECTORY;
  160. #else
  161.     db_directory = mk_file_name(news_directory, ".nn");
  162. #endif
  163.  
  164. #ifdef ACCOUNTING
  165.     if (who_am_i == I_AM_ACCT)
  166.     return 0;
  167. #endif
  168.  
  169. #ifdef DB_DATA_DIRECTORY
  170.     db_data_directory = DB_DATA_DIRECTORY;
  171. #else
  172. #ifdef DB_DIRECTORY
  173.     db_data_directory = mk_file_name(db_directory, "DATA");
  174. #else
  175.     db_data_directory = NULL;
  176. #endif
  177. #endif
  178.  
  179. #ifdef NEWS_LIB_DIRECTORY
  180.     news_lib_directory = NEWS_LIB_DIRECTORY;
  181. #else
  182.     news_lib_directory = "/usr/lib/news";
  183. #endif
  184.  
  185.     /* this may later be changed by nntp_check */
  186.     news_active = mk_file_name(news_lib_directory, "active");
  187.  
  188. #ifdef CLIENT_DIRECTORY
  189.     lib_directory = CLIENT_DIRECTORY;
  190. #else
  191.     lib_directory = LIB_DIRECTORY;
  192. #endif
  193.  
  194. #ifdef MASTER_DIRECTORY
  195.     master_directory = MASTER_DIRECTORY;
  196. #else
  197.     master_directory = lib_directory;
  198. #endif
  199.  
  200. #ifdef HELP_DIRECTORY
  201.     help_directory = HELP_DIRECTORY;
  202. #else
  203.     help_directory = mk_file_name(lib_directory, "help");
  204. #endif
  205.  
  206. #ifdef LOG_FILE
  207.     log_file = LOG_FILE;
  208. #else
  209.     log_file = mk_file_name(lib_directory, "Log");
  210. #endif
  211.  
  212.     if (who_am_i == I_AM_MASTER || who_am_i == I_AM_SPEW)
  213.     return 0;
  214.  
  215.     signal(SIGINT,  catch_keyboard);
  216.     signal(SIGQUIT, catch_keyboard);
  217. #ifdef HAVE_JOBCONTROL
  218.     signal(SIGTSTP, catch_suspend);
  219. #endif
  220.  
  221.     if ((home_directory = getenv("HOME")) == NULL)
  222.     user_error("No HOME environment variable");
  223.  
  224.     if ((pager = getenv("PAGER")) == NULL)
  225.     pager = DEFAULT_PAGER;
  226.  
  227.     nn_directory = mk_file_name(home_directory, ".nn");
  228.  
  229.     if (who_am_i != I_AM_ADMIN && !file_exist(nn_directory, "drwx")) {
  230.     if (who_am_i != I_AM_NN) return -1;
  231.     if (mkdir(nn_directory, 0755) < 0)
  232.         user_error("Cannot create %s directory", nn_directory);
  233.     return 1;
  234.     }
  235.  
  236.     return 0;
  237. }
  238.  
  239. new_temp_file()
  240. {
  241.     static char buf[FILENAME];
  242.     static char *temp_dir = NULL;
  243.  
  244.     if (temp_dir == NULL)
  245.     if ((temp_dir = getenv("TMPDIR")) == NULL)
  246.         temp_dir = tmp_directory; /* just to make test above false */
  247.     else
  248.         tmp_directory = temp_dir;
  249.  
  250.     sprintf(buf, "%s/nn.XXXXXX", tmp_directory);
  251.     mktemp(buf);
  252.     temp_file = buf;
  253. }
  254.  
  255.  
  256. FILE *open_file(name, mode)
  257. char *name;
  258. int mode;
  259. {
  260.     FILE *f;
  261.     int fd;
  262.     extern int errno;
  263.  
  264.     if ((mode & DONT_CREATE) && !file_exist(name, (char *)NULL))
  265.     return NULL;
  266.  
  267.     switch (mode & 0x0f) {
  268.  
  269.      case OPEN_READ:
  270.  
  271.     f = fopen(name, "r");
  272.     break;
  273.  
  274.      case OPEN_UPDATE:
  275.  
  276. /*    f = fopen(name, "r+");     -- not reliable on many systems (sigh) */
  277.  
  278.     if ((fd = open(name, O_WRONLY)) >= 0) {
  279.         if ((f = fdopen(fd, "w")) != NULL) return f;
  280.         close(fd);
  281.     }
  282.  
  283.     /* fall thru */
  284.  
  285.      case OPEN_CREATE:
  286.  
  287.     f = fopen(name, "w");
  288.     break;
  289.  
  290.      case OPEN_APPEND:
  291.  
  292.     f = fopen(name, "a");
  293.     break;
  294.  
  295.      case OPEN_CREATE_RW:
  296.  
  297.     f = fopen(name, "w+");    /* not safe on all systems -- beware */
  298.     break;
  299.  
  300.      default:
  301.  
  302.     sys_error("Illegal mode: open_file(%s, 0x%x)", name, mode);
  303.     }
  304.  
  305.     if (f) {
  306.     if (mode & OPEN_UNLINK) unlink(name);
  307.     return f;
  308.     }
  309.  
  310.     if ((mode & MUST_EXIST) == 0) return NULL;
  311.  
  312.     sys_error("Cannot open file %s, mode=0x%x, errno=%d", name, mode, errno);
  313.  
  314.     return NULL;
  315. }
  316.  
  317.  
  318.  
  319.  
  320. /*
  321.  *     relative -- concat directory name and file name
  322.  */
  323.  
  324. char *relative(dir, name)
  325. char *dir, *name;
  326. {
  327.     static char concat_path[FILENAME];
  328.  
  329.     sprintf(concat_path, "%s/%s", dir, name);
  330.     return concat_path;
  331. }
  332.  
  333.  
  334. char *mk_file_name(dir, name)
  335. char *dir, *name;
  336. {
  337.     char *buf;
  338.  
  339.     buf = newstr(strlen(dir) + strlen(name) + 2);
  340.     sprintf(buf, "%s/%s", dir, name);
  341.  
  342.     return buf;
  343. }
  344.  
  345.  
  346. char *home_relative(dir)
  347. char *dir;
  348. {
  349.     if (dir) {
  350.     if (*dir == '/')
  351.         return copy_str(dir);
  352.     else {
  353.         if (*dir == '~' && *++dir == '/') dir++;
  354.         return mk_file_name(home_directory, dir);
  355.     }
  356.     }
  357.     return NULL;
  358. }
  359.  
  360.  
  361. char *copy_str(str)
  362. char *str;
  363. {
  364.     char *new;
  365.  
  366.     new = newstr(strlen(str) + 1);
  367.     if (new) strcpy(new, str);
  368.  
  369.     return new;
  370. }
  371.  
  372. time_t m_time(f)
  373. FILE *f;
  374. {
  375.     struct stat st;
  376.  
  377.     if (fstat(fileno(f), &st) < 0) return 0;
  378.     return st.st_mtime;
  379. }
  380.  
  381.  
  382. time_t file_exist(name, mode)
  383. char *name;
  384. char *mode;
  385. {
  386.     struct stat statb;
  387.     extern int errno;
  388.  
  389.     if (stat(name, &statb)) return 0;
  390.  
  391.     if (mode == NULL) return statb.st_mtime;
  392.  
  393.     while (*mode) {
  394.     switch (*mode++) {
  395.     case 'd':
  396.         if ((statb.st_mode & S_IFMT) == S_IFDIR) continue;
  397.         errno = ENOTDIR;
  398.         return 0;
  399.     case 'f':
  400.         if ((statb.st_mode & S_IFMT) == S_IFREG) continue;
  401.         if ((statb.st_mode & S_IFMT) == 0000000) continue;
  402.         if ((statb.st_mode & S_IFMT) == S_IFDIR) {
  403.         errno = EISDIR;
  404.         return 0;
  405.         }
  406.         break;
  407.     case 'r':
  408.         if ((statb.st_mode & 0400) && statb.st_uid == user_id) continue;
  409.         if ((statb.st_mode & 0040) && group_access(statb.st_gid)) continue;
  410.             if ((statb.st_mode & 0004)) continue;
  411.         break;
  412.     case 'w':
  413.         if ((statb.st_mode & 0200) && statb.st_uid == user_id) continue;
  414.         if ((statb.st_mode & 0020) && group_access(statb.st_gid)) continue;
  415.             if ((statb.st_mode & 0002)) continue;
  416.         break;
  417.     case 'x':
  418.         if ((statb.st_mode & 0100) && statb.st_uid == user_id) continue;
  419.         if ((statb.st_mode & 0010) && group_access(statb.st_gid)) continue;
  420.             if ((statb.st_mode & 0001)) continue;
  421.         break;
  422.     }
  423.     errno = EACCES;
  424.     return 0;
  425.     }
  426.  
  427.     /* all modes are ok */
  428.     return statb.st_mtime;
  429. }
  430.  
  431.  
  432. #ifdef HAVE_SYSLOG
  433. #include <syslog.h>
  434. #endif /* HAVE_SYSLOG */
  435.  
  436.  
  437. static enter_log(type, va_tail)
  438. char type;
  439. va_tdcl
  440. {
  441.     FILE *log;
  442.     char *msg, buf[512];
  443.  
  444.     if (log_entry_filter != NULL)
  445.     for (msg = log_entry_filter; *msg; msg++)
  446.         if (*msg == type) return 1;
  447.  
  448.     msg  = va_arg1(char *);
  449.     vsprintf(buf, msg, va_args2toN);
  450.  
  451.     /* cannot use relative: one of the args may be generated by it */
  452.  
  453.     log = open_file(log_file, OPEN_APPEND);
  454.     if (log == NULL) return 0;
  455.  
  456.     fprintf(log, "%c: %s (%s): %s\n", type,
  457.         date_time((time_t)0), user_name(), buf);
  458.  
  459.     fclose(log);
  460.     return 1;
  461. }
  462.  
  463. /*VARARGS*/
  464. sys_error(va_alist)
  465. va_dcl
  466. {
  467.     char buf[512];
  468.     char *fmt;
  469.     FILE *f;
  470.     use_vararg;
  471.  
  472.     start_vararg;
  473.     enter_log('E', va_args1toN);
  474.     end_vararg;
  475.  
  476.     start_vararg;
  477.     fmt = va_arg1(char *);
  478.     vsprintf(buf, fmt, va_args2toN);
  479.     end_vararg;
  480.  
  481.     if (who_am_i == I_AM_MASTER) {
  482.     if (dont_write_console) nn_exit(7);
  483. #ifndef HAVE_SYSLOG
  484.     f = open_file("/dev/console", OPEN_CREATE);
  485.     if (f == NULL) nn_exit(8);
  486.     fprintf(f, "\n\rNNMASTER FATAL ERROR\n\r%s\n\n\r", buf);
  487.     fclose(f);
  488. #else /* HAVE_SYSLOG */
  489.     openlog("nnmaster", LOG_CONS, LOG_DAEMON);
  490.     syslog(LOG_ALERT, "%s", buf);
  491.     closelog();
  492. #endif /* HAVE_SYSLOG */
  493.     nn_exit(7);
  494.     }
  495.     user_error("%s", buf);
  496. }
  497.  
  498. /*VARARGS*/
  499. log_entry(va_alist)
  500. va_dcl
  501. {
  502.     int type, rval;
  503.     use_vararg;
  504.  
  505.     start_vararg;
  506.     type = va_arg1(int);
  507.     rval = enter_log(type, va_args2toN);
  508.     end_vararg;
  509.  
  510.     return rval;
  511. }
  512.  
  513. char *user_name()
  514. {
  515.     static char *user = NULL;
  516.     struct passwd *pw, *getpwuid();
  517.  
  518.     if (who_am_i == I_AM_MASTER) return "M";
  519.     if (who_am_i == I_AM_EXPIRE) return "X";
  520.  
  521.     if (user == NULL) {
  522.     pw = getpwuid((int)user_id);
  523.     if (pw == NULL) user = "?";
  524.     user = copy_str(pw->pw_name);
  525.     }
  526.  
  527.     return user;
  528. }
  529.  
  530. time_t cur_time()
  531. {
  532.     time_t t;
  533.  
  534.     time(&t);
  535.     return t;
  536. }
  537.  
  538. char *date_time(t)
  539. time_t t;
  540. {
  541.     char *str;
  542.  
  543.     if (t == (time_t)0) t = cur_time();
  544.     str = ctime(&t);
  545.  
  546.     str[16] = 0;
  547.     return str+4;
  548. }
  549.  
  550. char *plural(n)
  551. long n;
  552. {
  553.     return n != 1 ? "s" : "";
  554. }
  555.  
  556. /*
  557.  *    memory management
  558.  */
  559.  
  560. /* #define MEM_DEBUG        /* trace memory usage */
  561.  
  562. static mem_error(t, bytes)
  563. int t;
  564. int32 bytes;
  565. {
  566.     char buf[200];
  567.  
  568.     if (t == 1) {
  569.     sprintf(buf, "Alloc failed: unsigned too short to represent %ld bytes",
  570.         (long)bytes);
  571.     } else {
  572.     sprintf(buf, "Out of memory - cannot allocate %ld bytes",
  573.         (long)bytes);
  574.     }
  575.  
  576.     sys_error(buf);
  577. }
  578.  
  579. char *mem_obj(size, nelt)
  580. unsigned size;
  581. int32 nelt;
  582. {
  583.     unsigned n;
  584.     char *obj, *calloc();
  585.  
  586.     n = nelt;
  587.     if (n != nelt) mem_error(1, nelt);
  588.  
  589.     obj = calloc(n, size);
  590. #ifdef MEM_DEBUG
  591.     printf("CALLOC(%u,%u) => %lx\n", n, size, (long)obj);
  592. #endif
  593.     if (obj == NULL) mem_error(2, (int32)(size * nelt));
  594.     return obj;
  595. }
  596.  
  597. char *mem_str(nelt)
  598. int32 nelt;
  599. {
  600.     unsigned n;
  601.     char *obj, *malloc();
  602.  
  603.     n = nelt;
  604.     if (n != nelt) mem_error(1, nelt);
  605.  
  606.     obj = malloc(n);
  607. #ifdef MEM_DEBUG
  608.     printf("MALLOC(%u) => %lx\n", n, (long)obj);
  609. #endif
  610.     if (obj == NULL) mem_error(2, nelt);
  611.     return obj;
  612. }
  613.  
  614. char *mem_resize(obj, size, nelt)
  615. char *obj;
  616. unsigned size;
  617. int32 nelt;
  618. {
  619.     unsigned n;
  620.     char *realloc(), *obj1;
  621.  
  622.     if (obj == NULL)
  623.     return mem_obj(size, nelt);
  624.  
  625.     nelt *= size;
  626.  
  627.     n = nelt;
  628.     if (n != nelt) mem_error(1, nelt);
  629.  
  630.     obj1 = realloc(obj, n);
  631. #ifdef MEM_DEBUG
  632.     printf("REALLOC(%lx, %u) => %lx\n", (long)obj, n, (long)obj1);
  633. #endif
  634.     if (obj1 == NULL) mem_error(2, (int32)size);
  635.     return obj1;
  636. }
  637.  
  638. mem_free(obj)
  639. char *obj;
  640. {
  641. #ifdef MEM_DEBUG
  642.     printf("FREE(%lx)\n", (long)obj);
  643. #endif
  644.     if (obj != NULL) free(obj);
  645. }
  646.  
  647. #ifndef HAVE_MKDIR
  648.  
  649. mkdir(path, mode)
  650. char *path;
  651. int mode;
  652. {
  653.     char command[FILENAME*2 + 20];
  654.  
  655.     sprintf(command, "{ mkdir %s && chmod %o %s ; } > /dev/null 2>&1",
  656.         path, mode, path);
  657.     return system(command) != 0 ? -1 : 0;
  658. }
  659. #endif
  660.