[BACK]Return to main.c++ CVS log [TXT][DIR] Up to [Development] / fam / fam

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>