This is main.c in view mode; [Download] [Up]
/* @(#)src/main.c 1.5 18 Feb 1991 15:31:08 */ /* * Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll * * See the file COPYING, distributed with smail, for restriction * and warranty information. */ /* * main.c: * process arguments, configure environment and process * messages. * * external functions: main, initialize_state, process_args */ #include <stdio.h> #include <ctype.h> #include <sys/types.h> #include <sys/stat.h> #include <pwd.h> #include <signal.h> #include "defs.h" #include <sys/time.h> #include <time.h> #if defined(HAVE_RLIMIT) # include <sys/resource.h> #endif /* HAVE_RLIMIT */ #include "config.h" #include "smail.h" #include "dys.h" #include "addr.h" #include "hash.h" #include "main.h" #include "log.h" #include "transport.h" #include "child.h" #include "exitcodes.h" #include "smailconf.h" #include "alloc.h" #ifndef DEPEND # include "extern.h" # include "debug.h" # include "error.h" #endif /* exported variables */ int islocal; /* TRUE if mail originated locally */ int exitvalue; /* call exit with this value */ char *program; /* argv[0] from main */ char *sender; /* sender of message */ int error_sender; /* TRUE if special sender <> given */ char *sender_name; /* full name of sender */ enum op_mode operation_mode; /* mode of operation */ int debug = 0; /* debugging level, 0 is off */ int dont_deliver = FALSE; /* if TRUE, don't actually deliver */ int process_queue; /* process spooled files */ unsigned queue_interval; /* process queues at this interval */ int hop_count; /* hop count so far for message */ int do_aliasing; /* do aliasing for local addresses */ int extract_addresses; /* get recipients from header */ int me_too; /* sender allowed in aliases */ enum er_proc error_processing; /* method of displaying errors */ enum dot_usage dot_usage; /* how do we treat . on input */ enum deliver_mode deliver_mode = DELIVER_DEFAULT; /* foreground, background or queued */ struct addr *recipients; /* list of recipient addresses */ char *primary_name; /* primary local name from hostnames */ FILE *errfile = NULL; /* file to write debug messages to */ int real_uid; /* saved real uid before ruid setup */ enum prog_type prog_type; /* type of program we are running as */ char **save_argv; /* saved pointer to arguments */ int some_deferred_addrs; /* don't unlink spool file */ /* as some addrs were deferred */ int prog_euid; /* effective uid of program */ int prog_egid; /* effective gid of program */ int force_zero_exitvalue = FALSE; /* if TRUE always exit with status 0 */ int call_defer_message; /* if TRUE must call defer_message() */ int sender_is_trusted; /* TRUE if sender is a trusted user */ #ifdef GLOTZNET char *glotzhost; char *getenv(); #endif /* GLOTZNET */ /* functions local to this file */ static void panic_if_null(); static void rmail_panic(); /* variables local to this file */ static int report_memory_usage = FALSE; /* if TRUE, report sbrk(0) when done */ static char *arg_second_config_file = NULL; /* second config set by args */ static char *arg_director_file = NULL; /* director file set by args */ static char *arg_router_file = NULL; /* router file set by args */ static char *arg_transport_file = NULL; /* transport file set by args */ static char *arg_qualify_file = NULL; /* domain qualification file set by args */ static char *arg_smail_lib_dir = NULL; /* smail lib dir set by args */ /* * main - what to do after being exec'd * * main decodes the argument list and then performs specified action */ /*ARGSUSED*/ void main(argc, argv) int argc; /* count of arguments passed */ char **argv; /* vector of arguments */ { char *save_config_file = config_file; struct stat statbuf; char *error; save_argv = argv; #ifdef GLOTZNET glotzhost = getenv("GLOTZHOST"); if (glotzhost == NULL) { glotzhost = "namei"; } #endif /* GLOTZNET */ /* set up the file for interactive error and debug messages */ if (!errfile) { /* is stderr a valid file descriptor? */ if (fstat(2, &statbuf) >= 0) { /* yes, use stderr */ errfile = stderr; } else { /* no, can't output to stderr */ errfile = NULL; } } /* close file descriptors left open by others */ close_all(); /* * get the basename for the program */ program = rindex(*argv, '/'); if (program == NULL) { program = *argv; } else { program++; } argv++; #ifdef HAVE_SETGROUPS /* clear out all extra groups. We don't want to have to deal with them */ (void) setgroups(0, (int *)NULL); #endif /* get rid of any limits that might affect operation */ #if defined(HAVE_ULIMIT) && !defined(HAVE_RLIMIT) /* kill limits on file size */ (void) ulimit(2, ((long)1 << (BITS_PER_LONG - 2))/512); #endif /* HAVE_ULIMIT && !defined(HAVE_RLIMIT) */ /* always get a write error for a SIGPIPE, rather than dying */ (void) signal(SIGPIPE, SIG_IGN); #if defined(HAVE_RLIMIT) /* kill limits on file size, cpu, data segment, and unreasonable * limits on stack size */ { struct rlimit rl; rl.rlim_cur = RLIM_INFINITY; rl.rlim_max = RLIM_INFINITY; (void) setrlimit(RLIMIT_CPU, &rl); (void) setrlimit(RLIMIT_FSIZE, &rl); #if defined(DATA_RLIMIT) rl.rlim_cur = DATA_RLIMIT; #endif /* DATA_RLIMIT */ (void) setrlimit(RLIMIT_DATA, &rl); #if defined(STACK_RLIMIT) rl.rlim_cur = STACK_RLIMIT; #endif /* STACK_RLIMIT */ (void) setrlimit(RLIMIT_STACK, &rl); } #endif /* HAVE_RLIMIT */ /* Xenix systems must have TZ in the environment */ #ifdef REQUIRE_TZ /* if no timezone specified, assume GMT */ if (getenv("TZ") == NULL) { (void) putenv("TZ=GMT0"); } #endif /* we will always be supplying exactly the mode we want */ (void) umask(0); /* set the program type based on the program's basename */ prog_type = PROG_SMAIL; if (EQ(program, "rmail")) { prog_type = PROG_RMAIL; } else if (EQ(program, "pathto")) { prog_type = PROG_PATHTO; } else if (EQ(program, "optto")) { prog_type = PROG_OPTTO; } else if (EQ(program, "uupath")) { prog_type = PROG_UUPATH; } else if (EQ(program, "newaliases")) { prog_type = PROG_NEWALIASES; } else if (EQ(program, "smailconf")) { prog_type = PROG_SMAILCONF; } else if (EQ(program, "mailq")) { prog_type = PROG_MAILQ; } else if (EQ(program, "runq")) { prog_type = PROG_RUNQUEUE; } else if (EQ(program, "smtpd")) { /* * if there is no file on stdout, then dup stdin to stdout. * This is done because processes started from inetd will have * fd 0 set to the socket, but fd 1 will not be set. It will * need to be dup'd for this to work. */ if (fstat(1, &statbuf) < 0) { dup2(0, 1); } prog_type = PROG_SMTPD; } else if (EQ(program, "rsmtp")) { prog_type = PROG_RSMTP; } else if (EQ(program, "rogue") || EQ(program, "hack")) { prog_type = PROG_ROGUE; } else if (EQ(program, "..execmail") || EQ(program, "execmail")) { prog_type = PROG_EXECMAIL; } /* initialize per-message state information */ initialize_state(); /* set state information which depends on program type */ if (prog_type == PROG_NEWALIASES) { operation_mode = REBUILD_ALIASES; } else if (prog_type == PROG_SMAILCONF) { operation_mode = FREEZE_CONFIG; } else if (prog_type == PROG_MAILQ) { operation_mode = PRINT_QUEUE; } else if (prog_type == PROG_RSMTP) { operation_mode = BATCH_SMTP_MODE; } else if (prog_type == PROG_SMTPD) { operation_mode = SMTP_MODE; } else if (prog_type == PROG_PATHTO) { pathto(argv); } else if (prog_type == PROG_OPTTO) { optto(argv); } else if (prog_type == PROG_UUPATH) { uupath(argv); } else if (prog_type == PROG_RMAIL) { dot_usage = NO_DOT_PROTOCOL; } /* process the args given by the user */ process_args(argv); if (prog_type == PROG_RUNQUEUE) { if (operation_mode == MODE_DEFAULT || operation_mode == DAEMON_MODE) { process_queue = TRUE; } } if (operation_mode == MODE_DEFAULT) { /* * when performing a queue run, no other operations are * performed, by default. Currently no other operations * are allowed, either, though this may change in the * future. */ if (prog_type == PROG_RUNQUEUE || process_queue) { operation_mode = NOOP_MODE; } else { operation_mode = DELIVER_MAIL; } } if (prog_type == PROG_ROGUE) { operation_mode = ROGUE_MODE; } if (config_file != save_config_file || arg_second_config_file || arg_director_file || arg_router_file || arg_transport_file || arg_qualify_file || arg_smail_lib_dir) { /* * the config_file was set, or unset from the command args * then watch out for set-uid execs; i.e., go back to * the real uid under which we were invoked. */ setgid(getgid()); setuid(getuid()); } /* read in the config files, if they exists */ if (arg_smail_lib_dir) { smail_lib_dir = arg_smail_lib_dir; } error = read_config_file(config_file = make_lib_fn(config_file)); /* we need to set this again, in case it was changed in the config files */ if (arg_smail_lib_dir) { smail_lib_dir = arg_smail_lib_dir; } if (arg_second_config_file) { second_config_file = arg_second_config_file; } second_config_file = make_lib_fn(second_config_file); if (error == NULL && second_config_file) { error = read_config_file(second_config_file); } /* we need to set this again, in case it was changed in the config files */ if (arg_smail_lib_dir) { smail_lib_dir = arg_smail_lib_dir; } if (arg_smail_lib_dir) { smail_lib_dir = arg_smail_lib_dir; } if (arg_director_file) { director_file = arg_director_file; } if (arg_router_file) { router_file = arg_router_file; } if (arg_transport_file) { transport_file = arg_transport_file; } if (arg_qualify_file) { qualify_file = arg_qualify_file; } /* get the config file names within the lib directory */ director_file = make_lib_fn(director_file); router_file = make_lib_fn(router_file); transport_file = make_lib_fn(transport_file); method_dir = make_lib_fn(method_dir); qualify_file = make_lib_fn(qualify_file); copying_file = make_lib_fn(copying_file); smail = make_lib_fn(smail); if (error) { /* * error in the config file: not a good thing. * * Revert back to the initial values of vital attributes, * and set queue_only to avoid trying to perform delivery * with a potentially bad configuration. */ max_message_size = MAX_MESSAGE_SIZE; log_fn = LOGFILE; panic_fn = PANIC_LOG; cons_fn = CONSOLE; spool_dirs = SPOOL_DIRS; spool_mode = SPOOL_MODE; lock_mode = LOCK_MODE; log_mode = LOG_MODE; message_log_mode = MESSAGE_LOG_MODE; message_bufsiz = MESSAGE_BUF_SIZE; queue_only = TRUE; /* * if we are not actually going to be reading in messages, * then panic. Also, allow some trivial operations. */ switch (operation_mode) { case PRINT_QUEUE: case PRINT_VERSION: case SMTP_MODE: case BATCH_SMTP_MODE: case DELIVER_MAIL: case PRINT_VARS_MODE: write_log(LOG_TTY|LOG_PANIC, "%s", error); break; default: panic(EX_OSFILE, "%s", error); /*NOTREACHED*/ } } /* * read in the transport, router and director files, if needed * * NOTE: if queue_only is FALSE and mode is DELIVER_MAIL, * we will need to read these files, though do this later * to avoid wasting time on it before the spool file is * created. */ switch (operation_mode) { case NOOP_MODE: case DAEMON_MODE: /* * stat our binary so we can see if it has been touched later */ if (stat(smail, &statbuf) < 0) { panic(EX_SOFTWARE, "main: bad stat of smail binary %s", smail); } else { add_config_stat(smail, &statbuf); } /*FALL THROUGH*/ case TEST_MODE: case VERIFY_ADDRS: case BATCH_SMTP_MODE: case SMTP_MODE: if ((error = read_transport_file()) || (error = read_router_file()) || (error = read_director_file()) || (error = read_qualify_file())) { panic(EX_OSFILE, "%s", error); } break; } switch (operation_mode) { case NOOP_MODE: case DAEMON_MODE: case TEST_MODE: cache_directors(); cache_routers(); cache_transports(); break; } /* * Save away the real uid and set the real to the effective. * After this point, the real uid is no longer at all interesting. * In BSD, if the mailer runs as root, we can now freely set the * real or effective uid to whatever we want without worrying about * swapping them. Also, if the mailer runs as a user other than * root, we no longer have to worry about child processes being * able to do a setuid(getuid) to get root priveledges when root * sends mail. */ real_uid = getuid(); prog_euid = geteuid(); /* keep a copy of the effictive id's */ prog_egid = getegid(); setuid(prog_euid); setgid(prog_egid); /* * error processing can be other than TERMINAL only for * mail delivery modes */ switch (operation_mode) { case DELIVER_MAIL: case NOOP_MODE: case DAEMON_MODE: case SMTP_MODE: case BATCH_SMTP_MODE: if (error_processing == ERROR_DEFAULT) { if (debug) { error_processing = TERMINAL; } else { error_processing = MAIL_BACK; } } break; default: error_processing = TERMINAL; break; } if (process_queue && operation_mode != NOOP_MODE && operation_mode != DAEMON_MODE) { if (errfile) { fprintf(errfile, "%s: operation mode not compatible with queue runs\n", program); } exit(EX_USAGE); } /* * setup the delivery mode used for delivering new messages */ if (deliver_mode == DELIVER_DEFAULT) { /* * if not set explicity in the arguments, key off the first * letter of the configuration parameter */ switch (delivery_mode_string[0]) { case 'f': deliver_mode = FOREGROUND; break; case 'b': deliver_mode = BACKGROUND; break; default: deliver_mode = QUEUE_MESSAGE; break; } } /* * invoke the correct mode of operation */ switch (operation_mode) { case TEST_MODE: /* test addresses from stdin */ test_addresses(); /* read addrs from stdin, for tests */ break; case NOOP_MODE: /* generally, this means run queue */ dont_deliver = FALSE; /* it is too dangerous to allow this */ noop_mode(); break; case PRINT_QUEUE: /* print the mail queue */ print_queue(); break; case PRINT_VERSION: print_version(); break; case VERIFY_ADDRS: /* spit out resoved addresses */ if (recipients == NULL && !extract_addresses) { if (errfile) { (void) fprintf(errfile, "Usage: %s [flags] address...\n", program); } exitvalue = EX_USAGE; break; } verify_addresses(); break; case SMTP_MODE: /* read SMTP requests on stdin */ smtp_mode(stdin, stdout); break; case BATCH_SMTP_MODE: /* batched SMTP requests on stdin */ smtp_mode(stdin, (FILE *)NULL); break; case DAEMON_MODE: /* be a daemon waiting for requests */ dont_deliver = FALSE; /* it is too dangerous to allow this */ daemon_mode(); break; case FREEZE_CONFIG: /* freeze the configuration */ if (errfile) { (void) fprintf(errfile, "%s: operation not currently supported\n", program); } exitvalue = EX_UNAVAILABLE; break; case DELIVER_MAIL: /* deliver to all addresses found */ if (recipients == NULL && !extract_addresses) { if (errfile) { (void) fprintf(errfile, "Usage: %s [flags] address...\n", program); } exitvalue = EX_USAGE; break; } perform_deliver_mail(); break; case ROGUE_MODE: /* print a rogue tombstone */ silly(); break; case COPYING_MODE: print_copying_file(); break; case PRINT_VARS_MODE: print_variables(); break; default: if (errfile) { (void) fprintf(errfile, "%s: option not supported\n", program); } exitvalue = EX_UNAVAILABLE; } /* * all done. */ if (report_memory_usage) { if (errfile) { extern caddr_t sbrk(); (void) fprintf(errfile, "%s: sbrk(0) = %ld\n", program, (long)sbrk(0)); } } if (force_zero_exitvalue) { exit(0); } exit(exitvalue); } /* * initialize_state - set some parameters to their default value */ void initialize_state() { send_to_postmaster = FALSE; return_to_sender = FALSE; islocal = FALSE; exitvalue = EX_OK; sender = NULL; error_sender = FALSE; path_to_sender = NULL; sender_name = NULL; operation_mode = MODE_DEFAULT; process_queue = FALSE; queue_interval = 0; hop_count = -1; do_aliasing = TRUE; extract_addresses = FALSE; dot_usage = DOT_ENDS_MESSAGE; me_too = FALSE; error_processing = ERROR_DEFAULT; recipients = NULL; some_deferred_addrs = FALSE; call_defer_message = FALSE; sender_is_trusted = TRUE; dont_deliver = FALSE; /* * generate a new address hit table where case is ignored and * all data resides in memory */ /* XXX - hit_table should be associated with a block */ hit_table = new_hash_table(hit_table_len, (struct block *)NULL, HASH_DEFAULT); } /* * process_args - process the arguments passed to the mailer * * In general use sendmail semantics, with different argument * processing based on name at invocation. */ void process_args(args) register char **args; /* vector of arguments */ { struct addr *cur; /* temp addr list entry */ char *arg; /* single string from args */ char *error; /* error message */ char *newsender; /* temp for process sender */ static char *end_arg = ""; /* swallow remaining chars in arg */ /* * go through the list of arguments in search of options and * addresses. */ while (arg = *args++) { /* option arguments begin with '-', of course */ if (arg[0] == '-') { /* switch on each letter */ arg++; while (*arg) switch(*arg++) { case 'd': /* set debug level */ case 'v': /* verbose, same as debug */ if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) { rmail_panic(); } if (arg[0]) { char *error = NULL; debug = (int)c_atol(arg, &error); if (error || debug < 0) { if (errfile) { (void) fprintf(errfile, "%s: -%c flag takes an optional non-negative number\n", program, arg[-1]); } exit(EX_USAGE); } arg = end_arg; } else { debug = 1; /* if no number, default to 1 */ } break; #ifdef GLOTZNET case 'G': glotzhost = arg; arg = end_arg; /* if no string there, take next arg */ if (sender_name[0] == '\0') { glotzhost = *args++; panic_if_null(glotzhost, "G"); } break; #endif /* GLOTZNET */ case 'V': operation_mode = PRINT_VERSION; break; case 'F': /* set full name of sender */ sender_name = arg; arg = end_arg; /* terminate args in current argv */ /* if no string there, take next arg */ if (sender_name[0] == '\0') { sender_name = *args++; panic_if_null(sender_name, "F"); } break; case 'r': /* set path to sender */ /* SCO Execmail '-r' option not applicable to smail */ if (prog_type == PROG_EXECMAIL) break; /* FALL THROUGH */ case 'f': /* set path to sender */ newsender = arg; arg = end_arg; /* terminate args in current argv */ /* if no string there, take next arg */ if (newsender[0] == '\0') { newsender = *args++; panic_if_null(newsender, "f"); } /* * don't use this sender if it has been determined that * the local originator of mail is not a user expected * to receive remote mail. */ if (sender_is_trusted) { sender = newsender; /* special form of sender for SMTP error mail */ if (EQ(sender, "<>")) { sender = "MAILER-DAEMON"; error_sender = TRUE; islocal = FALSE; } else { newsender = preparse_address(sender, &error); if (newsender == NULL) { if (errfile) { (void)fprintf(errfile, "%s: error in sender name: %s", program, error); } sender = "MAILER-DAEMON"; islocal = FALSE; } islocal = (parse_address(sender, (char **)NULL, &error) == LOCAL); } } break; case 'N': /* don't deliver message */ dont_deliver = TRUE; break; case 'C': /* set config file name */ if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) { rmail_panic(); } config_file = arg; arg = end_arg; /* terminate args in current argv */ /* if no string there, take next arg */ if (config_file[0] == '\0') { config_file = *args++; panic_if_null(config_file, "C"); } break; case 'q': /* check queue (at interval) */ if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) { rmail_panic(); } process_queue = TRUE; if (arg[0]) { long l = ivaltol(arg); if (l < 0) { if (errfile) { (void) fprintf(errfile, "%s: %s: malformed interval\n", program, arg); exit(EX_USAGE); } } queue_interval = (unsigned)l; if (l != queue_interval) { (void) fprintf(errfile, "%s: %s: interval too large\n", program, arg); exit(EX_USAGE); } arg = end_arg; /* uses rest of argument */ } break; case 'h': /* hopcount, number is the count */ { char *error = NULL; if (arg[0]) { hop_count = (int)c_atol(arg, &error); arg = end_arg; } else { hop_count = atoi(*args++); } if (error || hop_count < 0) { if (errfile) { (void) fprintf(errfile, "%s: -h flag takes a non-negative number\n", program); } exit(EX_USAGE); } } break; case 'n': /* don't do aliasing */ if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) { rmail_panic(); } do_aliasing = FALSE; break; case 't': /* read recipients from message */ extract_addresses = TRUE; break; case 'i': /* don't treat dots specially */ dot_usage = NO_DOT_PROTOCOL; break; case 'I': /* use hidden-dot protocol on input */ dot_usage = HIDDEN_DOTS; break; case 'm': /* author can be included in alias */ me_too = TRUE; break; case 'Q': queue_only = TRUE; /* spool but do not deliver, yet */ break; case 'e': /* what to do on errors */ if (arg[0] == '\0') { arg = *args++; panic_if_null(arg, "e"); } switch(*arg) { case 'e': /* we don't support berkenet */ case 'm': /* mail back errors */ error_processing = MAIL_BACK; break; case 'w': /* send via "write" */ error_processing = WRITE_BACK; break; case 'p': /* print errors on screen */ error_processing = TERMINAL; break; case 'q': /* be quiet about errors */ error_processing = DEV_NULL; break; } arg = end_arg; /* swallows complete argument */ break; case 'o': /* set various option */ if (arg[0] == '\0') { arg = *args++; panic_if_null(arg, "o"); } switch (*arg++) { case 'i': /* same as -i */ dot_usage = NO_DOT_PROTOCOL; break; case 'I': /* same as -I */ dot_usage = HIDDEN_DOTS; break; case 'M': report_memory_usage = TRUE; break; case 'e': /* same as -eX */ if (*arg == '\0') { arg = *args++; panic_if_null(arg, "oe"); } switch (*arg) { case 'm': error_processing = MAIL_BACK; break; case 'w': error_processing = WRITE_BACK; break; case 'p': error_processing = TERMINAL; break; case 'q': error_processing = DEV_NULL; break; } break; case 'd': /* delivery mode */ if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) { rmail_panic(); } if (*arg == '\0') { arg = *args++; panic_if_null(arg, "od"); } switch (*arg) { case 'f': deliver_mode = FOREGROUND; break; case 'b': deliver_mode = BACKGROUND; break; case 'q': deliver_mode = QUEUE_MESSAGE; break; } break; case 'C': /* name of config file */ if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) { rmail_panic(); } if (*arg == '\0') { arg = *args++; panic_if_null(arg, "oC"); } config_file = arg; break; case 'L': if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) { rmail_panic(); } if (*arg == '\0') { arg = *args++; panic_if_null(arg, "oL"); } arg_smail_lib_dir = arg; break; case 'S': /* name of secondary config file */ if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) { rmail_panic(); } if (*arg == '\0') { arg = *args++; panic_if_null(arg, "oS"); } arg_second_config_file = arg; break; case 'D': /* name of director file */ if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) { rmail_panic(); } if (*arg == '\0') { arg = *args++; panic_if_null(arg, "oD"); } arg_director_file = arg; break; case 'Q': if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) { rmail_panic(); } if (*arg == '\0') { arg = *args++; panic_if_null(arg, "oQ"); } arg_qualify_file = arg; break; case 'R': if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) { rmail_panic(); } if (*arg == '\0') { arg = *args++; panic_if_null(arg, "oR"); } arg_router_file = arg; break; case 'T': if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) { rmail_panic(); } if (*arg == '\0') { arg = *args++; panic_if_null(arg, "oT"); } arg_transport_file = arg; break; case 'm': /* same as -m */ me_too = TRUE; break; } arg = end_arg; break; case 'b': /* set operating mode */ if (*arg == '\0') { arg = *args++; panic_if_null(arg, "b"); } switch (*arg) { case 'd': /* operate as daemon */ if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) { rmail_panic(); } operation_mode = DAEMON_MODE; break; case 'i': /* initialize aliases database */ if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) { rmail_panic(); } operation_mode = REBUILD_ALIASES; break; case 'm': /* just deliver mail */ operation_mode = DELIVER_MAIL; break; case 'p': /* print the queue */ if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) { rmail_panic(); } operation_mode = PRINT_QUEUE; break; case 't': /* run in address test mode */ if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) { rmail_panic(); } operation_mode = TEST_MODE; break; case 'v': /* verify addresses only */ operation_mode = VERIFY_ADDRS; break; case 'V': operation_mode = PRINT_VERSION; break; case 's': /* process smtp on input */ operation_mode = SMTP_MODE; break; case 'S': /* batched SMTP mode */ operation_mode = BATCH_SMTP_MODE; break; case 'z': /* freeze config file */ if (prog_type == PROG_RMAIL || prog_type == PROG_RSMTP) { rmail_panic(); } operation_mode = FREEZE_CONFIG; break; case 'R': /* rogue tombstone mode */ operation_mode = ROGUE_MODE; break; case 'c': /* print COPYING file */ operation_mode = COPYING_MODE; break; case 'P': operation_mode = PRINT_VARS_MODE; break; } arg = end_arg; break; } } else { /* * not a flag, arg must be a recipient address so insert * it in the list. */ cur = alloc_addr(); cur->in_addr = arg; cur->uid = nobody_uid; cur->gid = nobody_gid; cur->succ = recipients; recipients = cur; } } } /* * panic_if_null - complain with a usage message if the given pointer is NULL */ static void panic_if_null(p, fl) char *p; char *fl; /* name of flag to give usage for */ { if (p == NULL) { if (errfile) { (void) fprintf(errfile, "%s: argument expected after -%s\n", program, fl); } exit(EX_USAGE); } } /* * rmail_panic - complain about an option not allowed with rmail or rsmtp */ static void rmail_panic() { if (errfile) { (void) fprintf(errfile, "%s: usage with rmail and rsmtp is restricted\n", program); } exit(EX_USAGE); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.