Annotation of embedaddon/sudo/src/parse_args.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (c) 1993-1996, 1998-2011 Todd C. Miller <Todd.Miller@courtesan.com>
! 3: *
! 4: * Permission to use, copy, modify, and distribute this software for any
! 5: * purpose with or without fee is hereby granted, provided that the above
! 6: * copyright notice and this permission notice appear in all copies.
! 7: *
! 8: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 9: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 10: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 11: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 12: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 13: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 14: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 15: *
! 16: * Sponsored in part by the Defense Advanced Research Projects
! 17: * Agency (DARPA) and Air Force Research Laboratory, Air Force
! 18: * Materiel Command, USAF, under agreement number F39502-99-1-0512.
! 19: */
! 20:
! 21: #include <config.h>
! 22:
! 23: #include <sys/types.h>
! 24: #include <sys/param.h>
! 25:
! 26: #include <stdio.h>
! 27: #ifdef STDC_HEADERS
! 28: # include <stdlib.h>
! 29: # include <stddef.h>
! 30: #else
! 31: # ifdef HAVE_STDLIB_H
! 32: # include <stdlib.h>
! 33: # endif
! 34: #endif /* STDC_HEADERS */
! 35: #ifdef HAVE_STRING_H
! 36: # include <string.h>
! 37: #endif /* HAVE_STRING_H */
! 38: #ifdef HAVE_STRINGS_H
! 39: # include <strings.h>
! 40: #endif /* HAVE_STRINGS_H */
! 41: #ifdef HAVE_UNISTD_H
! 42: # include <unistd.h>
! 43: #endif /* HAVE_UNISTD_H */
! 44: #include <ctype.h>
! 45: #include <grp.h>
! 46: #include <pwd.h>
! 47:
! 48: #include <sudo_usage.h>
! 49: #include "sudo.h"
! 50: #include "lbuf.h"
! 51:
! 52: /* For getopt(3) */
! 53: extern char *optarg;
! 54: extern int optind;
! 55:
! 56: int tgetpass_flags;
! 57:
! 58: /*
! 59: * Local functions.
! 60: */
! 61: static void help(void) __attribute__((__noreturn__));
! 62: static void usage_excl(int);
! 63:
! 64: /*
! 65: * Mapping of command line flags to name/value settings.
! 66: */
! 67: static struct sudo_settings {
! 68: const char *name;
! 69: const char *value;
! 70: } sudo_settings[] = {
! 71: #define ARG_BSDAUTH_TYPE 0
! 72: { "bsdauth_type" },
! 73: #define ARG_LOGIN_CLASS 1
! 74: { "login_class" },
! 75: #define ARG_DEBUG_LEVEL 2
! 76: { "debug_level" },
! 77: #define ARG_PRESERVE_ENVIRONMENT 3
! 78: { "preserve_environment" },
! 79: #define ARG_RUNAS_GROUP 4
! 80: { "runas_group" },
! 81: #define ARG_SET_HOME 5
! 82: { "set_home" },
! 83: #define ARG_USER_SHELL 6
! 84: { "run_shell" },
! 85: #define ARG_LOGIN_SHELL 7
! 86: { "login_shell" },
! 87: #define ARG_IGNORE_TICKET 8
! 88: { "ignore_ticket" },
! 89: #define ARG_PROMPT 9
! 90: { "prompt" },
! 91: #define ARG_SELINUX_ROLE 10
! 92: { "selinux_role" },
! 93: #define ARG_SELINUX_TYPE 11
! 94: { "selinux_type" },
! 95: #define ARG_RUNAS_USER 12
! 96: { "runas_user" },
! 97: #define ARG_PROGNAME 13
! 98: { "progname" },
! 99: #define ARG_IMPLIED_SHELL 14
! 100: { "implied_shell" },
! 101: #define ARG_PRESERVE_GROUPS 15
! 102: { "preserve_groups" },
! 103: #define ARG_NONINTERACTIVE 16
! 104: { "noninteractive" },
! 105: #define ARG_SUDOEDIT 17
! 106: { "sudoedit" },
! 107: #define ARG_CLOSEFROM 18
! 108: { "closefrom" },
! 109: #define ARG_NET_ADDRS 19
! 110: { "network_addrs" },
! 111: #define NUM_SETTINGS 20
! 112: { NULL }
! 113: };
! 114:
! 115: /*
! 116: * Command line argument parsing.
! 117: * Sets nargc and nargv which corresponds to the argc/argv we'll use
! 118: * for the command to be run (if we are running one).
! 119: */
! 120: int
! 121: parse_args(int argc, char **argv, int *nargc, char ***nargv, char ***settingsp,
! 122: char ***env_addp)
! 123: {
! 124: int mode = 0; /* what mode is sudo to be run in? */
! 125: int flags = 0; /* mode flags */
! 126: int valid_flags, ch;
! 127: int i, j;
! 128: char *cp, **env_add, **settings;
! 129: int nenv = 0;
! 130: int env_size = 32;
! 131:
! 132: env_add = emalloc2(env_size, sizeof(char *));
! 133:
! 134: /* Pass progname to plugin so it can call setprogname() */
! 135: sudo_settings[ARG_PROGNAME].value = getprogname();
! 136:
! 137: /* First, check to see if we were invoked as "sudoedit". */
! 138: if (strcmp(getprogname(), "sudoedit") == 0) {
! 139: mode = MODE_EDIT;
! 140: sudo_settings[ARG_SUDOEDIT].value = "true";
! 141: }
! 142:
! 143: /* Load local IP addresses and masks. */
! 144: if (get_net_ifs(&cp) > 0)
! 145: sudo_settings[ARG_NET_ADDRS].value = cp;
! 146:
! 147: /* Returns true if the last option string was "--" */
! 148: #define got_end_of_args (optind > 1 && argv[optind - 1][0] == '-' && \
! 149: argv[optind - 1][1] == '-' && argv[optind - 1][2] == '\0')
! 150:
! 151: /* Returns true if next option is an environment variable */
! 152: #define is_envar (optind < argc && argv[optind][0] != '/' && \
! 153: strchr(argv[optind], '=') != NULL)
! 154:
! 155: /* Flags allowed when running a command */
! 156: valid_flags = MODE_BACKGROUND|MODE_PRESERVE_ENV|MODE_RESET_HOME|
! 157: MODE_LOGIN_SHELL|MODE_NONINTERACTIVE|MODE_SHELL;
! 158: /* XXX - should fill in settings at the end to avoid dupes */
! 159: for (;;) {
! 160: /*
! 161: * We disable arg permutation for GNU getopt().
! 162: * Some trickiness is required to allow environment variables
! 163: * to be interspersed with command line options.
! 164: */
! 165: if ((ch = getopt(argc, argv, "+Aa:bC:c:D:Eeg:HhiKklnPp:r:Sst:U:u:Vv")) != -1) {
! 166: switch (ch) {
! 167: case 'A':
! 168: SET(tgetpass_flags, TGP_ASKPASS);
! 169: break;
! 170: #ifdef HAVE_BSD_AUTH_H
! 171: case 'a':
! 172: sudo_settings[ARG_BSDAUTH_TYPE].value = optarg;
! 173: break;
! 174: #endif
! 175: case 'b':
! 176: SET(flags, MODE_BACKGROUND);
! 177: break;
! 178: case 'C':
! 179: if (atoi(optarg) < 3) {
! 180: warningx(_("the argument to -C must be a number greater than or equal to 3"));
! 181: usage(1);
! 182: }
! 183: sudo_settings[ARG_CLOSEFROM].value = optarg;
! 184: break;
! 185: #ifdef HAVE_LOGIN_CAP_H
! 186: case 'c':
! 187: sudo_settings[ARG_LOGIN_CLASS].value = optarg;
! 188: break;
! 189: #endif
! 190: case 'D':
! 191: if ((debug_level = atoi(optarg)) < 1 || debug_level > 9) {
! 192: warningx(_("the argument to -D must be between 1 and 9 inclusive"));
! 193: usage(1);
! 194: }
! 195: sudo_settings[ARG_DEBUG_LEVEL].value = optarg;
! 196: break;
! 197: case 'E':
! 198: sudo_settings[ARG_PRESERVE_ENVIRONMENT].value = "true";
! 199: break;
! 200: case 'e':
! 201: if (mode && mode != MODE_EDIT)
! 202: usage_excl(1);
! 203: mode = MODE_EDIT;
! 204: sudo_settings[ARG_SUDOEDIT].value = "true";
! 205: valid_flags = MODE_NONINTERACTIVE;
! 206: break;
! 207: case 'g':
! 208: runas_group = optarg;
! 209: sudo_settings[ARG_RUNAS_GROUP].value = optarg;
! 210: break;
! 211: case 'H':
! 212: sudo_settings[ARG_SET_HOME].value = "true";
! 213: break;
! 214: case 'h':
! 215: if (mode && mode != MODE_HELP) {
! 216: if (strcmp(getprogname(), "sudoedit") != 0)
! 217: usage_excl(1);
! 218: }
! 219: mode = MODE_HELP;
! 220: valid_flags = 0;
! 221: break;
! 222: case 'i':
! 223: sudo_settings[ARG_LOGIN_SHELL].value = "true";
! 224: SET(flags, MODE_LOGIN_SHELL);
! 225: break;
! 226: case 'k':
! 227: sudo_settings[ARG_IGNORE_TICKET].value = "true";
! 228: break;
! 229: case 'K':
! 230: sudo_settings[ARG_IGNORE_TICKET].value = "true";
! 231: if (mode && mode != MODE_KILL)
! 232: usage_excl(1);
! 233: mode = MODE_KILL;
! 234: valid_flags = 0;
! 235: break;
! 236: case 'l':
! 237: if (mode) {
! 238: if (mode == MODE_LIST)
! 239: SET(flags, MODE_LONG_LIST);
! 240: else
! 241: usage_excl(1);
! 242: }
! 243: mode = MODE_LIST;
! 244: valid_flags = MODE_NONINTERACTIVE|MODE_LONG_LIST;
! 245: break;
! 246: case 'n':
! 247: SET(flags, MODE_NONINTERACTIVE);
! 248: sudo_settings[ARG_NONINTERACTIVE].value = "true";
! 249: break;
! 250: case 'P':
! 251: sudo_settings[ARG_PRESERVE_GROUPS].value = "true";
! 252: break;
! 253: case 'p':
! 254: sudo_settings[ARG_PROMPT].value = optarg;
! 255: break;
! 256: #ifdef HAVE_SELINUX
! 257: case 'r':
! 258: sudo_settings[ARG_SELINUX_ROLE].value = optarg;
! 259: break;
! 260: case 't':
! 261: sudo_settings[ARG_SELINUX_TYPE].value = optarg;
! 262: break;
! 263: #endif
! 264: case 'S':
! 265: SET(tgetpass_flags, TGP_STDIN);
! 266: break;
! 267: case 's':
! 268: sudo_settings[ARG_USER_SHELL].value = "true";
! 269: SET(flags, MODE_SHELL);
! 270: break;
! 271: case 'U':
! 272: if ((getpwnam(optarg)) == NULL)
! 273: errorx(1, _("unknown user: %s"), optarg);
! 274: list_user = optarg;
! 275: break;
! 276: case 'u':
! 277: runas_user = optarg;
! 278: sudo_settings[ARG_RUNAS_USER].value = optarg;
! 279: break;
! 280: case 'v':
! 281: if (mode && mode != MODE_VALIDATE)
! 282: usage_excl(1);
! 283: mode = MODE_VALIDATE;
! 284: valid_flags = MODE_NONINTERACTIVE;
! 285: break;
! 286: case 'V':
! 287: if (mode && mode != MODE_VERSION)
! 288: usage_excl(1);
! 289: mode = MODE_VERSION;
! 290: valid_flags = 0;
! 291: break;
! 292: default:
! 293: usage(1);
! 294: }
! 295: } else if (!got_end_of_args && is_envar) {
! 296: if (nenv == env_size - 2) {
! 297: env_size *= 2;
! 298: env_add = erealloc3(env_add, env_size, sizeof(char *));
! 299: }
! 300: env_add[nenv++] = argv[optind];
! 301:
! 302: /* Crank optind and resume getopt. */
! 303: optind++;
! 304: } else {
! 305: /* Not an option or an environment variable -- we're done. */
! 306: break;
! 307: }
! 308: }
! 309: env_add[nenv] = NULL;
! 310:
! 311: argc -= optind;
! 312: argv += optind;
! 313:
! 314: if (!mode) {
! 315: /* Defer -k mode setting until we know whether it is a flag or not */
! 316: if (sudo_settings[ARG_IGNORE_TICKET].value != NULL) {
! 317: if (argc == 0) {
! 318: mode = MODE_INVALIDATE; /* -k by itself */
! 319: sudo_settings[ARG_IGNORE_TICKET].value = NULL;
! 320: valid_flags = 0;
! 321: }
! 322: }
! 323: if (!mode)
! 324: mode = MODE_RUN; /* running a command */
! 325: }
! 326:
! 327: if (argc > 0 && mode == MODE_LIST)
! 328: mode = MODE_CHECK;
! 329:
! 330: if (ISSET(flags, MODE_LOGIN_SHELL)) {
! 331: if (ISSET(flags, MODE_SHELL)) {
! 332: warningx(_("you may not specify both the `-i' and `-s' options"));
! 333: usage(1);
! 334: }
! 335: if (ISSET(flags, MODE_PRESERVE_ENV)) {
! 336: warningx(_("you may not specify both the `-i' and `-E' options"));
! 337: usage(1);
! 338: }
! 339: SET(flags, MODE_SHELL);
! 340: }
! 341: if ((flags & valid_flags) != flags)
! 342: usage(1);
! 343: if (mode == MODE_EDIT &&
! 344: (ISSET(flags, MODE_PRESERVE_ENV) || env_add[0] != NULL)) {
! 345: if (ISSET(mode, MODE_PRESERVE_ENV))
! 346: warningx(_("the `-E' option is not valid in edit mode"));
! 347: if (env_add[0] != NULL)
! 348: warningx(_("you may not specify environment variables in edit mode"));
! 349: usage(1);
! 350: }
! 351: if ((runas_user != NULL || runas_group != NULL) &&
! 352: !ISSET(mode, MODE_EDIT | MODE_RUN | MODE_CHECK | MODE_VALIDATE)) {
! 353: usage(1);
! 354: }
! 355: if (list_user != NULL && mode != MODE_LIST && mode != MODE_CHECK) {
! 356: warningx(_("the `-U' option may only be used with the `-l' option"));
! 357: usage(1);
! 358: }
! 359: if (ISSET(tgetpass_flags, TGP_STDIN) && ISSET(tgetpass_flags, TGP_ASKPASS)) {
! 360: warningx(_("the `-A' and `-S' options may not be used together"));
! 361: usage(1);
! 362: }
! 363: if ((argc == 0 && mode == MODE_EDIT) ||
! 364: (argc > 0 && !ISSET(mode, MODE_RUN | MODE_EDIT | MODE_CHECK)))
! 365: usage(1);
! 366: if (argc == 0 && mode == MODE_RUN && !ISSET(flags, MODE_SHELL)) {
! 367: SET(flags, (MODE_IMPLIED_SHELL | MODE_SHELL));
! 368: sudo_settings[ARG_IMPLIED_SHELL].value = "true";
! 369: }
! 370:
! 371: if (mode == MODE_HELP)
! 372: help();
! 373:
! 374: /*
! 375: * For shell mode we need to rewrite argv
! 376: */
! 377: if (ISSET(mode, MODE_RUN) && ISSET(flags, MODE_SHELL)) {
! 378: char **av;
! 379: int ac;
! 380:
! 381: if (argc == 0) {
! 382: /* just the shell */
! 383: ac = argc + 1;
! 384: av = emalloc2(ac + 1, sizeof(char *));
! 385: memcpy(av + 1, argv, argc * sizeof(char *));
! 386: } else {
! 387: /* shell -c "command" */
! 388: char *cmnd, *src, *dst;
! 389: size_t cmnd_size = (size_t) (argv[argc - 1] - argv[0]) +
! 390: strlen(argv[argc - 1]) + 1;
! 391:
! 392: cmnd = dst = emalloc2(cmnd_size, 2);
! 393: for (av = argv; *av != NULL; av++) {
! 394: for (src = *av; *src != '\0'; src++) {
! 395: /* quote potential meta characters */
! 396: if (!isalnum((unsigned char)*src) && *src != '_' && *src != '-')
! 397: *dst++ = '\\';
! 398: *dst++ = *src;
! 399: }
! 400: *dst++ = ' ';
! 401: }
! 402: if (cmnd != dst)
! 403: dst--; /* replace last space with a NUL */
! 404: *dst = '\0';
! 405:
! 406: ac = 3;
! 407: av = emalloc2(ac + 1, sizeof(char *));
! 408: av[1] = "-c";
! 409: av[2] = cmnd;
! 410: }
! 411: av[0] = (char *)user_details.shell; /* plugin may override shell */
! 412: av[ac] = NULL;
! 413:
! 414: argv = av;
! 415: argc = ac;
! 416: }
! 417:
! 418: /*
! 419: * Format setting_pairs into settings array.
! 420: */
! 421: settings = emalloc2(NUM_SETTINGS + 1, sizeof(char *));
! 422: for (i = 0, j = 0; i < NUM_SETTINGS; i++) {
! 423: if (sudo_settings[i].value) {
! 424: sudo_debug(9, "settings: %s=%s", sudo_settings[i].name,
! 425: sudo_settings[i].value);
! 426: settings[j] = fmt_string(sudo_settings[i].name,
! 427: sudo_settings[i].value);
! 428: if (settings[j] == NULL)
! 429: errorx(1, _("unable to allocate memory"));
! 430: j++;
! 431: }
! 432: }
! 433: settings[j] = NULL;
! 434:
! 435: if (mode == MODE_EDIT) {
! 436: #if defined(HAVE_SETRESUID) || defined(HAVE_SETREUID) || defined(HAVE_SETEUID)
! 437: /* Must have the command in argv[0]. */
! 438: argc++;
! 439: argv--;
! 440: argv[0] = "sudoedit";
! 441: #else
! 442: errorx(1, _("sudoedit is not supported on this platform"));
! 443: #endif
! 444: }
! 445:
! 446: *settingsp = settings;
! 447: *env_addp = env_add;
! 448: *nargc = argc;
! 449: *nargv = argv;
! 450: return mode | flags;
! 451: }
! 452:
! 453: static int
! 454: usage_err(const char *buf)
! 455: {
! 456: return fputs(buf, stderr);
! 457: }
! 458:
! 459: static int
! 460: usage_out(const char *buf)
! 461: {
! 462: return fputs(buf, stdout);
! 463: }
! 464:
! 465: /*
! 466: * Give usage message and exit.
! 467: * The actual usage strings are in sudo_usage.h for configure substitution.
! 468: */
! 469: void
! 470: usage(int fatal)
! 471: {
! 472: struct lbuf lbuf;
! 473: char *uvec[6];
! 474: int i, ulen;
! 475:
! 476: /*
! 477: * Use usage vectors appropriate to the progname.
! 478: */
! 479: if (strcmp(getprogname(), "sudoedit") == 0) {
! 480: uvec[0] = SUDO_USAGE5 + 3;
! 481: uvec[1] = NULL;
! 482: } else {
! 483: uvec[0] = SUDO_USAGE1;
! 484: uvec[1] = SUDO_USAGE2;
! 485: uvec[2] = SUDO_USAGE3;
! 486: uvec[3] = SUDO_USAGE4;
! 487: uvec[4] = SUDO_USAGE5;
! 488: uvec[5] = NULL;
! 489: }
! 490:
! 491: /*
! 492: * Print usage and wrap lines as needed, depending on the
! 493: * tty width.
! 494: */
! 495: ulen = (int)strlen(getprogname()) + 8;
! 496: lbuf_init(&lbuf, fatal ? usage_err : usage_out, ulen, NULL,
! 497: user_details.ts_cols);
! 498: for (i = 0; uvec[i] != NULL; i++) {
! 499: lbuf_append(&lbuf, "usage: %s%s", getprogname(), uvec[i]);
! 500: lbuf_print(&lbuf);
! 501: }
! 502: lbuf_destroy(&lbuf);
! 503: if (fatal)
! 504: exit(1);
! 505: }
! 506:
! 507: /*
! 508: * Tell which options are mutually exclusive and exit.
! 509: */
! 510: static void
! 511: usage_excl(int fatal)
! 512: {
! 513: warningx(_("Only one of the -e, -h, -i, -K, -l, -s, -v or -V options may be specified"));
! 514: usage(fatal);
! 515: }
! 516:
! 517: static void
! 518: help(void)
! 519: {
! 520: struct lbuf lbuf;
! 521: int indent = 16;
! 522: const char *pname = getprogname();
! 523:
! 524: lbuf_init(&lbuf, usage_out, indent, NULL, user_details.ts_cols);
! 525: if (strcmp(pname, "sudoedit") == 0)
! 526: lbuf_append(&lbuf, _("%s - edit files as another user\n\n"), pname);
! 527: else
! 528: lbuf_append(&lbuf, _("%s - execute a command as another user\n\n"), pname);
! 529: lbuf_print(&lbuf);
! 530:
! 531: usage(0);
! 532:
! 533: lbuf_append(&lbuf, _("\nOptions:\n"));
! 534: #ifdef HAVE_BSD_AUTH_H
! 535: lbuf_append(&lbuf, " -A %s",
! 536: _("use helper program for password prompting\n"));
! 537: #endif
! 538: lbuf_append(&lbuf, " -a type %s",
! 539: _("use specified BSD authentication type\n"));
! 540: lbuf_append(&lbuf, " -b %s",
! 541: _("run command in the background\n"));
! 542: lbuf_append(&lbuf, " -C fd %s",
! 543: _("close all file descriptors >= fd\n"));
! 544: #ifdef HAVE_LOGIN_CAP_H
! 545: lbuf_append(&lbuf, " -c class %s",
! 546: _("run command with specified login class\n"));
! 547: #endif
! 548: lbuf_append(&lbuf, " -E %s",
! 549: _("preserve user environment when executing command\n"));
! 550: lbuf_append(&lbuf, " -e %s",
! 551: _("edit files instead of running a command\n"));
! 552: lbuf_append(&lbuf, " -g group %s",
! 553: _("execute command as the specified group\n"));
! 554: lbuf_append(&lbuf, " -H %s",
! 555: _("set HOME variable to target user's home dir.\n"));
! 556: lbuf_append(&lbuf, " -h %s",
! 557: _("display help message and exit\n"));
! 558: lbuf_append(&lbuf, " -i [command] %s",
! 559: _("run a login shell as target user\n"));
! 560: lbuf_append(&lbuf, " -K %s",
! 561: _("remove timestamp file completely\n"));
! 562: lbuf_append(&lbuf, " -k %s",
! 563: _("invalidate timestamp file\n"));
! 564: lbuf_append(&lbuf, " -l[l] command %s",
! 565: _("list user's available commands\n"));
! 566: lbuf_append(&lbuf, " -n %s",
! 567: _("non-interactive mode, will not prompt user\n"));
! 568: lbuf_append(&lbuf, " -P %s",
! 569: _("preserve group vector instead of setting to target's\n"));
! 570: lbuf_append(&lbuf, " -p prompt %s",
! 571: _("use specified password prompt\n"));
! 572: #ifdef HAVE_SELINUX
! 573: lbuf_append(&lbuf, " -r role %s",
! 574: _("create SELinux security context with specified role\n"));
! 575: #endif
! 576: lbuf_append(&lbuf, " -S %s",
! 577: _("read password from standard input\n"));
! 578: lbuf_append(&lbuf,
! 579: " -s [command] %s", _("run a shell as target user\n"));
! 580: #ifdef HAVE_SELINUX
! 581: lbuf_append(&lbuf, " -t type %s",
! 582: _("create SELinux security context with specified role\n"));
! 583: #endif
! 584: lbuf_append(&lbuf, " -U user %s",
! 585: _("when listing, list specified user's privileges\n"));
! 586: lbuf_append(&lbuf, " -u user %s",
! 587: _("run command (or edit file) as specified user\n"));
! 588: lbuf_append(&lbuf, " -V %s",
! 589: _("display version information and exit\n"));
! 590: lbuf_append(&lbuf, " -v %s",
! 591: _("update user's timestamp without running a command\n"));
! 592: lbuf_append(&lbuf, " -- %s",
! 593: _("stop processing command line arguments\n"));
! 594: lbuf_print(&lbuf);
! 595: lbuf_destroy(&lbuf);
! 596: exit(0);
! 597: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>