Annotation of fam/fam/main.c++, Revision 1.1
1.1 ! trev 1: // Copyright (C) 1999 Silicon Graphics, Inc. All Rights Reserved.
! 2: // This program is free software; you can redistribute it and/or modify it
! 3: // under the terms of version 2 of the GNU General Public License as
! 4: // published by the Free Software Foundation.
! 5: //
! 6: // This program is distributed in the hope that it would be useful, but
! 7: // WITHOUT ANY WARRANTY; without even the implied warranty of
! 8: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Further, any
! 9: // license provided herein, whether implied or otherwise, is limited to
! 10: // this program in accordance with the express provisions of the GNU
! 11: // General Public License. Patent licenses, if any, provided herein do not
! 12: // apply to combinations of this program with other product or programs, or
! 13: // any other product whatsoever. This program is distributed without any
! 14: // warranty that the program is delivered free of the rightful claim of any
! 15: // third person by way of infringement or the like. See the GNU General
! 16: // Public License for more details.
! 17: //
! 18: // You should have received a copy of the GNU General Public License along
! 19: // with this program; if not, write the Free Software Foundation, Inc., 59
! 20: // Temple Place - Suite 330, Boston MA 02111-1307, USA.
! 21:
! 22: #include "config.h"
! 23: #include <stdio.h>
! 24: #include <stdlib.h>
! 25: #include <string.h>
! 26: #include <signal.h>
! 27: #include <sys/stat.h>
! 28: #if HAVE_SYSSGI
! 29: #include <sys/syssgi.h>
! 30: #endif
! 31: #include <unistd.h>
! 32: #include <ctype.h>
! 33: #include <limits.h>
! 34:
! 35: #include "Activity.h"
! 36: #include "Listener.h"
! 37: #include "Log.h"
! 38: #include "Pollster.h"
! 39: #include "Scheduler.h"
! 40: #include "Cred.h"
! 41: #include "Interest.h"
! 42:
! 43: const char *program_name;
! 44:
! 45: // These are options which are read from the configuration file & the
! 46: // command line.
! 47: struct config_opts
! 48: {
! 49: config_opts();
! 50: const char *config_file; // do not free this
! 51: char *untrusted_user;
! 52: int pollster_interval; // in seconds
! 53: int activity_timeout; // in seconds
! 54: bool disable_pollster;
! 55: bool local_only;
! 56: bool xtab_verification;
! 57: bool disable_audit;
! 58: bool disable_mac;
! 59: bool insecure_compat;
! 60: bool debugging;
! 61: };
! 62: #define CFG_INSECURE_COMPAT "insecure_compatibility"
! 63: #define CFG_LOCAL_ONLY "local_only"
! 64: #define CFG_XTAB_VERIFICATION "xtab_verification"
! 65: #define CFG_UNTRUSTED_USER "untrusted_user"
! 66: #define CFG_IDLE_TIMEOUT "idle_timeout"
! 67: #define CFG_NFS_POLLING_INTERVAL "nfs_polling_interval"
! 68: static void parse_config(config_opts &opts);
! 69: static void parse_config_line(config_opts &opts, int line,
! 70: const char *k, const char *v);
! 71: static bool is_true(const char *str);
! 72:
! 73: static const char *basename2(const char *p)
! 74: {
! 75: const char *tail = p;
! 76: while (*p)
! 77: if (*p++ == '/' && *p && *p != '/')
! 78: tail = p;
! 79: return tail;
! 80: }
! 81:
! 82: void usage()
! 83: { fprintf(stderr,
! 84: "fam, version %s\n"
! 85: "Use: %s [ -f | -d | -v ] [ -l | -t seconds ] [ -T seconds ] \\\n"
! 86: "\t\t\t\t[ -p prog.vers ] [ -L ] [ -c config_file ] [-C]\n",
! 87: VERSION, program_name);
! 88: fprintf(stderr, "\t-f\t\tstay in foreground\n");
! 89: fprintf(stderr, "\t-d\t\tdebug\n");
! 90: fprintf(stderr, "\t-v\t\tverbose\n");
! 91: fprintf(stderr, "\t-l\t\tno polling\n");
! 92: fprintf(stderr, "\t-t seconds\tset polling interval (default 6 s)\n");
! 93: fprintf(stderr, "\t-T seconds\tset inactive timeout (default 5 s)\n");
! 94: fprintf(stderr, "\t-p prog.vers\tset RPC program number and version\n");
! 95: fprintf(stderr, "\t-L\t\tlocal only (ignore remote requests)\n");
! 96: fprintf(stderr, "\t-c config_file\tpath to alternate configuration file\n");
! 97: fprintf(stderr, "\t\t\t (default is %s)\n", CONFIG_ETC_CONFIG_PATH);
! 98: fprintf(stderr, "\t-C\t\tinsecure compatibility\n");
! 99: fprintf(stderr, "\n");
! 100: exit(1);
! 101: }
! 102:
! 103: int main(int argc, char *argv[])
! 104: {
! 105: #if HAVE_SGI_NOHANG
! 106: // This keeps down nfs mounts from hanging fam. System calls on
! 107: // down nfs mounts fail with errno == ETIMEDOUT. We don't do this
! 108: // if we're running diskless because we don't want fam to crash
! 109: // because a page fault timed out.
! 110: char buf[20];
! 111: if (sgikopt("diskless", buf, sizeof buf) == 0
! 112: && strcmp(buf, "0") == 0) {
! 113: syssgi(SGI_NOHANG, 1);
! 114: }
! 115: #endif
! 116:
! 117: config_opts opts;
! 118:
! 119: // If fd 0 is a socket, we figure we were started by inetd.
! 120: struct stat st;
! 121: fstat(0, &st);
! 122: bool started_by_inetd = S_ISSOCK(st.st_mode);
! 123:
! 124: unsigned long program = Listener::FAMPROG, version = Listener::FAMVERS;
! 125:
! 126: program_name = basename2(argv[0]);
! 127: Log::name(program_name);
! 128:
! 129: if (!started_by_inetd)
! 130: Log::foreground();
! 131:
! 132: // Run through the command-line args once, looking for debugging flags
! 133: // and config-file flags. (We want to check those before we parse the
! 134: // config file, and we want to parse the config file before reading other
! 135: // command-line args which might override its contents.)
! 136: int i;
! 137: for (i = 1; i < argc; i++)
! 138: {
! 139: if (argv[i][0] != '-' || !argv[i][1] || argv[i][2]) continue;
! 140: switch (argv[i][1])
! 141: {
! 142: case 'c':
! 143: if(++i >= argc) usage();
! 144: opts.config_file = argv[i];
! 145: break;
! 146: case 'f':
! 147: opts.debugging = true;
! 148: break;
! 149: case 'd':
! 150: Log::debug();
! 151: opts.debugging = true;
! 152: break;
! 153: case 'v':
! 154: Log::info();
! 155: opts.debugging = true;
! 156: break;
! 157: }
! 158: }
! 159:
! 160: if (getuid() != 0)
! 161: { Log::error("must be superuser");
! 162: exit(1);
! 163: }
! 164:
! 165: parse_config(opts);
! 166:
! 167: // Now run through the command-line arguments again.
! 168: for (i = 1; i < argc; i++)
! 169: { if (argv[i][0] != '-' || !argv[i][1] || argv[i][2])
! 170: usage();
! 171: switch (argv[i][1])
! 172: {
! 173: char *p, *q;
! 174: unsigned secs;
! 175:
! 176: case 'f':
! 177: case 'd':
! 178: case 'v':
! 179: // handled above.
! 180: break;
! 181:
! 182: case 'l':
! 183: opts.disable_pollster = true;
! 184: break;
! 185:
! 186: case 'p':
! 187: if (++i >= argc)
! 188: usage();
! 189: p = strchr(argv[i], '.');
! 190: if (p)
! 191: { *p++ = '\0';
! 192: version = strtoul(p, &q, 10);
! 193: if (p == q) usage();
! 194: }
! 195: program = strtoul(argv[i], &q, 10);
! 196: if (argv[i] == q) usage();
! 197: break;
! 198:
! 199: case 't':
! 200: if (i + 1 >= argc)
! 201: usage();
! 202: secs = strtoul(argv[++i], &p, 10);
! 203: if (*p)
! 204: usage();
! 205: if (secs == 0)
! 206: Log::error("illegal poll interval 0");
! 207: else
! 208: opts.pollster_interval = secs;
! 209: break;
! 210:
! 211: case 'T':
! 212: if (i + 1 >= argc)
! 213: usage();
! 214: secs = strtoul(argv[++i], &p, 10);
! 215: if (*p)
! 216: usage();
! 217: opts.activity_timeout = secs;
! 218: break;
! 219:
! 220: case 'L':
! 221: opts.local_only = true;
! 222: break;
! 223:
! 224: case 'C':
! 225: opts.insecure_compat = true;
! 226: opts.xtab_verification = false;
! 227: Log::info("Running with -C (" CFG_INSECURE_COMPAT
! 228: ") command-line option");
! 229: break;
! 230:
! 231: case 'c':
! 232: // handled above.
! 233: ++i;
! 234: break;
! 235:
! 236: default:
! 237: usage();
! 238: }
! 239: }
! 240:
! 241: // Apply the various options.
! 242: if (opts.local_only && started_by_inetd) {
! 243: Log::error("Warning! Started by inetd, so -L (" CFG_LOCAL_ONLY
! 244: ") option is being ignored!");
! 245: opts.local_only = false;
! 246: }
! 247: if (opts.disable_audit) Log::disable_audit();
! 248: if (opts.disable_mac) Cred::disable_mac();
! 249: if (opts.insecure_compat) Cred::enable_insecure_compat();
! 250: if (opts.untrusted_user) Cred::set_untrusted_user(opts.untrusted_user);
! 251: else {
! 252: Log::error("Fatal misconfiguration! No " CFG_UNTRUSTED_USER
! 253: " found in %s!", opts.config_file);
! 254: exit(1);
! 255: }
! 256: Pollster::interval(opts.pollster_interval);
! 257: Activity::timeout(opts.activity_timeout);
! 258: if (opts.disable_pollster) Pollster::disable();
! 259: if (!opts.local_only) {
! 260: Interest::enable_xtab_verification(opts.xtab_verification);
! 261: }
! 262: Log::audit(true, "fam starting SAT with process name \"%s\"",
! 263: program_name);
! 264:
! 265: if (!started_by_inetd)
! 266: {
! 267: #if HAVE__DAEMONIZE
! 268: if (!opts.debugging)
! 269: { _daemonize(0, -1, -1, -1);
! 270: Log::background();
! 271: }
! 272: #else
! 273: # if HAVE_DAEMON
! 274: if (!opts.debugging)
! 275: { daemon(0, 0);
! 276: Log::background();
! 277: }
! 278: # endif
! 279: #endif
! 280: }
! 281: (void) signal(SIGPIPE, SIG_IGN);
! 282:
! 283: #if HAVE_SGI_NOHANG
! 284: // Ignore SIGCHLD because we run nfsunhang to unhang down nfs
! 285: // mounts, and we don't care about the exit status of nfsunhang
! 286: // (since we poll anyway) and we don't want to create zombies.
! 287: (void) signal(SIGCHLD, SIG_IGN);
! 288: #endif
! 289: new Listener(started_by_inetd, opts.local_only, program, version);
! 290: Scheduler::loop();
! 291: return 0;
! 292: }
! 293:
! 294:
! 295: static void
! 296: parse_config(config_opts &opts)
! 297: {
! 298: FILE *cfg = fopen(opts.config_file, "r");
! 299: if(cfg == NULL)
! 300: {
! 301: Log::error("Couldn't open config file \"%s\"!", opts.config_file);
! 302: usage();
! 303: return;
! 304: }
! 305: char buf[PATH_MAX + 64];
! 306: char *bp;
! 307: int lineno = 0;
! 308: while(fgets(buf, sizeof(buf), cfg))
! 309: {
! 310: ++lineno;
! 311: bp = buf;
! 312: while(isspace(*bp)) ++bp;
! 313: if ((*bp == '\0') || (*bp == '#') || (*bp == '!')) continue;
! 314: if (bp[strlen(bp) - 1] != '\n')
! 315: {
! 316: Log::error("config file %s line %d is too long, and is "
! 317: "being ignored!", opts.config_file, lineno);
! 318: --lineno;
! 319: continue;
! 320: }
! 321: bp[strlen(bp) - 1] = '\0'; // whap newline
! 322:
! 323: // split line at "=", strip whitespace from ends of both pieces
! 324: char *vp = strchr(bp, '=');
! 325: if(vp == NULL)
! 326: {
! 327: Log::error("config file %s line %d seems dain bramaged (no \"=\"), "
! 328: "and is being ignored.", opts.config_file, lineno);
! 329: continue;
! 330: }
! 331: *vp++ = '\0';
! 332: while (isspace(*vp)) ++vp;
! 333: char *end = bp + strlen(bp) - 1;
! 334: while (isspace(*end) && (end >= bp)) *end-- = '\0';
! 335: end = vp + strlen(vp) - 1;
! 336: while (isspace(*end) && (end >= vp)) *end-- = '\0';
! 337:
! 338: Log::debug("read %s line %d: \"%s\" = \"%s\"",
! 339: opts.config_file, lineno, bp, vp);
! 340: parse_config_line(opts, lineno, bp, vp);
! 341: }
! 342: fclose(cfg);
! 343: }
! 344:
! 345:
! 346:
! 347: static void
! 348: parse_config_line(config_opts &opts, int lineno, const char *key, const char *val)
! 349: {
! 350: char *p;
! 351: unsigned secs;
! 352:
! 353: if(!strcmp(key, CFG_UNTRUSTED_USER))
! 354: {
! 355: if (!opts.untrusted_user) opts.untrusted_user = strdup(val);
! 356: else Log::error("config file %s line %d: ignoring duplicate %s",
! 357: opts.config_file, lineno, key);
! 358: }
! 359: else if(!strcmp(key, CFG_LOCAL_ONLY))
! 360: {
! 361: opts.local_only = is_true(val);
! 362: }
! 363: else if(!strcmp(key, CFG_IDLE_TIMEOUT))
! 364: {
! 365: secs = strtoul(val, &p, 10);
! 366: if (*p)
! 367: {
! 368: Log::error("config file %s line %d: ignoring invalid value for %s",
! 369: opts.config_file, lineno, key);
! 370: }
! 371: else
! 372: {
! 373: opts.activity_timeout = secs;
! 374: }
! 375: }
! 376: else if(!strcmp(key, CFG_NFS_POLLING_INTERVAL))
! 377: {
! 378: secs = strtoul(val, &p, 10);
! 379: if (*p || secs == 0)
! 380: {
! 381: Log::error("config file %s line %d: ignoring invalid value for %s",
! 382: opts.config_file, lineno, key);
! 383: }
! 384: else
! 385: {
! 386: opts.pollster_interval = secs;
! 387: }
! 388: }
! 389: else if(!strcmp(key, CFG_XTAB_VERIFICATION))
! 390: {
! 391: opts.xtab_verification = is_true(val);
! 392: if(opts.xtab_verification && opts.insecure_compat)
! 393: {
! 394: opts.xtab_verification = false;
! 395: Log::error("config file %s line %d: ignoring %s because "
! 396: CFG_INSECURE_COMPAT " is set",
! 397: opts.config_file, lineno, key);
! 398: }
! 399: }
! 400: else if(!strcmp(key, CFG_INSECURE_COMPAT))
! 401: {
! 402: opts.insecure_compat = is_true(val);
! 403: //ehh... it would be nice to handle this a little better.
! 404: // if(opts.insecure_compat && opts.xtab_verification)
! 405: // {
! 406: // opts.xtab_verification = false;
! 407: // Log::error("config file %s line %d: %s overrides "
! 408: // CFG_XTAB_VERIFICATION,
! 409: // opts.config_file, lineno, key);
! 410: // }
! 411: }
! 412: else if(!strcmp(key, "disable_audit"))
! 413: {
! 414: opts.disable_audit = is_true(val);
! 415: }
! 416: else if(!strcmp(key, "disable_mac"))
! 417: {
! 418: opts.disable_mac = is_true(val);
! 419: }
! 420: else
! 421: {
! 422: Log::error("config file %s line %d: unrecognized key \"%s\"",
! 423: opts.config_file, lineno, key);
! 424: }
! 425: }
! 426:
! 427:
! 428: config_opts::config_opts()
! 429: {
! 430: memset(this, 0, sizeof(config_opts));
! 431:
! 432: config_file = CONFIG_ETC_CONFIG_PATH;
! 433: untrusted_user = NULL;
! 434: pollster_interval = 6;
! 435: activity_timeout = 5;
! 436: disable_pollster = false;
! 437: local_only = false;
! 438: xtab_verification = true;
! 439: #ifdef HAVE_AUDIT
! 440: disable_audit = (sysconf(_SC_AUDIT) != 1);
! 441: #else
! 442: disable_audit = true;
! 443: #endif
! 444: #ifdef HAVE_MAC
! 445: disable_mac = ((sysconf(_SC_MAC) != 1) || (sysconf(_SC_IP_SECOPTS) != 1));
! 446: #else
! 447: disable_mac = true;
! 448: #endif
! 449: insecure_compat = false;
! 450: debugging = false;
! 451: }
! 452:
! 453: static bool
! 454: is_true(const char *val)
! 455: {
! 456: if (!strcasecmp(val, "false") ||
! 457: !strcasecmp(val, "no") ||
! 458: !strcmp(val, "0"))
! 459: {
! 460: return false;
! 461: }
! 462: return true;
! 463: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>