[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

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>