]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - sys-utils/setarch.c
scriptreplay: cleanup usage()
[thirdparty/util-linux.git] / sys-utils / setarch.c
index 97269f45aef7c0bfb81f4793578c17ba2f3731ca..1a2ae1b68ccce9645643f24632c5174911ab6841 100644 (file)
@@ -24,8 +24,7 @@
  * sparc32 util by Jakub Jelinek (1998, 1999)
  */
 
-#include <syscall.h>
-#include <linux/personality.h>
+#include <sys/personality.h>
 #include <unistd.h>
 #include <stdio.h>
 #include <string.h>
 #include "c.h"
 #include "closestream.h"
 
-#define set_pers(pers) ((long)syscall(SYS_personality, pers))
-
-/* Options without equivalent short options */
-enum {
-       OPT_4GB         = CHAR_MAX + 1,
-       OPT_UNAME26
-};
+#ifndef HAVE_PERSONALITY
+# include <syscall.h>
+# define personality(pers) ((long)syscall(SYS_personality, pers))
+#endif
 
 #define turn_on(_flag, _opts) \
        do { \
@@ -52,294 +48,411 @@ enum {
                        printf(_("Switching on %s.\n"), #_flag); \
        } while(0)
 
-
-#if !HAVE_DECL_UNAME26
+#ifndef UNAME26
 # define UNAME26                 0x0020000
 #endif
-#if !HAVE_DECL_ADDR_NO_RANDOMIZE
+#ifndef ADDR_NO_RANDOMIZE
 # define ADDR_NO_RANDOMIZE       0x0040000
 #endif
-#if !HAVE_DECL_FDPIC_FUNCPTRS
+#ifndef FDPIC_FUNCPTRS
 # define FDPIC_FUNCPTRS          0x0080000
 #endif
-#if !HAVE_DECL_MMAP_PAGE_ZERO
+#ifndef MMAP_PAGE_ZERO
 # define MMAP_PAGE_ZERO          0x0100000
 #endif
-#if !HAVE_DECL_ADDR_COMPAT_LAYOUT
+#ifndef ADDR_COMPAT_LAYOUT
 # define ADDR_COMPAT_LAYOUT      0x0200000
 #endif
-#if !HAVE_DECL_READ_IMPLIES_EXEC
+#ifndef READ_IMPLIES_EXEC
 # define READ_IMPLIES_EXEC       0x0400000
 #endif
-#if !HAVE_DECL_ADDR_LIMIT_32BIT
+#ifndef ADDR_LIMIT_32BIT
 # define ADDR_LIMIT_32BIT        0x0800000
 #endif
-#if !HAVE_DECL_SHORT_INODE
+#ifndef SHORT_INODE
 # define SHORT_INODE             0x1000000
 #endif
-#if !HAVE_DECL_WHOLE_SECONDS
+#ifndef WHOLE_SECONDS
 # define WHOLE_SECONDS           0x2000000
 #endif
-#if !HAVE_DECL_STICKY_TIMEOUTS
+#ifndef STICKY_TIMEOUTS
 # define STICKY_TIMEOUTS         0x4000000
 #endif
-#if !HAVE_DECL_ADDR_LIMIT_3GB
+#ifndef ADDR_LIMIT_3GB
 # define ADDR_LIMIT_3GB          0x8000000
 #endif
 
-static void __attribute__((__noreturn__))
-show_help(void)
-{
-   printf(USAGE_HEADER);
-   printf(_(" %s%s [options] [program [program arguments]]\n"),
-         program_invocation_short_name,
-        !strcmp(program_invocation_short_name, "setarch") ? " <arch>" : "");
-
-   printf(USAGE_OPTIONS);
-   printf(_(
-   " -v, --verbose            says what options are being switched on\n"
-   " -R, --addr-no-randomize  disables randomization of the virtual address space\n"
-   " -F, --fdpic-funcptrs     makes function pointers point to descriptors\n"
-   " -Z, --mmap-page-zero     turns on MMAP_PAGE_ZERO\n"
-   " -L, --addr-compat-layout changes the way virtual memory is allocated\n"
-   " -X, --read-implies-exec  turns on READ_IMPLIES_EXEC\n"
-   " -B, --32bit              turns on ADDR_LIMIT_32BIT\n"
-   " -I, --short-inode        turns on SHORT_INODE\n"
-   " -S, --whole-seconds      turns on WHOLE_SECONDS\n"
-   " -T, --sticky-timeouts    turns on STICKY_TIMEOUTS\n"
-   " -3, --3gb                limits the used address space to a maximum of 3 GB\n"
-   "     --4gb                ignored (for backward compatibility only)\n"
-   "     --uname-2.6          turns on UNAME26\n"));
-
-  printf(USAGE_SEPARATOR);
-  printf(USAGE_HELP);
-  printf(USAGE_VERSION);
-  printf(USAGE_MAN_TAIL("setarch(8)"));
-
-  exit(EXIT_SUCCESS);
-}
 
-static void __attribute__((__noreturn__))
-show_usage(const char *s)
-{
-  errx(EXIT_FAILURE, _("%s\nTry `%s --help' for more information."), s, program_invocation_short_name);
-}
+struct arch_domain {
+       int             perval;         /* PER_* */
+       const char      *target_arch;
+       const char      *result_arch;
+};
 
-static void __attribute__((__noreturn__))
-show_version(void)
+
+static void __attribute__((__noreturn__)) usage(int archwrapper)
 {
-  printf(UTIL_LINUX_VERSION);
-  exit(EXIT_SUCCESS);
+       fputs(USAGE_HEADER, stdout);
+       if (!archwrapper)
+               printf(_(" %s [<arch>] [options] [<program> [<argument>...]]\n"), program_invocation_short_name);
+       else
+               printf(_(" %s [options] [<program> [<argument>...]]\n"), program_invocation_short_name);
+
+       fputs(USAGE_SEPARATOR, stdout);
+       fputs(_("Change the reported architecture and set personality flags.\n"), stdout);
+
+       fputs(USAGE_OPTIONS, stdout);
+       fputs(_(" -B, --32bit              turns on ADDR_LIMIT_32BIT\n"), stdout);
+       fputs(_(" -F, --fdpic-funcptrs     makes function pointers point to descriptors\n"), stdout);
+       fputs(_(" -I, --short-inode        turns on SHORT_INODE\n"), stdout);
+       fputs(_(" -L, --addr-compat-layout changes the way virtual memory is allocated\n"), stdout);
+       fputs(_(" -R, --addr-no-randomize  disables randomization of the virtual address space\n"), stdout);
+       fputs(_(" -S, --whole-seconds      turns on WHOLE_SECONDS\n"), stdout);
+       fputs(_(" -T, --sticky-timeouts    turns on STICKY_TIMEOUTS\n"), stdout);
+       fputs(_(" -X, --read-implies-exec  turns on READ_IMPLIES_EXEC\n"), stdout);
+       fputs(_(" -Z, --mmap-page-zero     turns on MMAP_PAGE_ZERO\n"), stdout);
+       fputs(_(" -3, --3gb                limits the used address space to a maximum of 3 GB\n"), stdout);
+       fputs(_("     --4gb                ignored (for backward compatibility only)\n"), stdout);
+       fputs(_("     --uname-2.6          turns on UNAME26\n"), stdout);
+       fputs(_(" -v, --verbose            say what options are being switched on\n"), stdout);
+
+       if (!archwrapper)
+               fputs(_("     --list               list settable architectures, and exit\n"), stdout);
+
+       fputs(USAGE_SEPARATOR, stdout);
+       printf(USAGE_HELP_OPTIONS(26));
+       printf(USAGE_MAN_TAIL("setarch(8)"));
+
+       exit(EXIT_SUCCESS);
 }
 
-int set_arch(const char *pers, unsigned long options)
+/*
+ * Returns inilialized list of all available execution domains.
+ */
+static struct arch_domain *init_arch_domains(void)
 {
-  struct utsname un;
-  int i;
-  unsigned long pers_value;
-
-  struct {
-    int perval;
-    const char *target_arch, *result_arch;
-  } transitions[] = {
-    {PER_LINUX32, "linux32", NULL},
-    {PER_LINUX, "linux64", NULL},
+       static struct utsname un;
+       size_t i;
+
+       static struct arch_domain transitions[] =
+       {
+               {UNAME26,       "uname26",      NULL},
+               {PER_LINUX32,   "linux32",      NULL},
+               {PER_LINUX,     "linux64",      NULL},
 #if defined(__powerpc__) || defined(__powerpc64__)
-    {PER_LINUX32, "ppc32", "ppc"},
-    {PER_LINUX32, "ppc", "ppc"},
-    {PER_LINUX, "ppc64", "ppc64"},
-    {PER_LINUX, "ppc64pseries", "ppc64"},
-    {PER_LINUX, "ppc64iseries", "ppc64"},
+# ifdef __BIG_ENDIAN__
+               {PER_LINUX32,   "ppc32",        "ppc"},
+               {PER_LINUX32,   "ppc",          "ppc"},
+               {PER_LINUX,     "ppc64",        "ppc64"},
+               {PER_LINUX,     "ppc64pseries", "ppc64"},
+               {PER_LINUX,     "ppc64iseries", "ppc64"},
+# else
+               {PER_LINUX32,   "ppc32",        "ppcle"},
+               {PER_LINUX32,   "ppc",          "ppcle"},
+               {PER_LINUX32,   "ppc32le",      "ppcle"},
+               {PER_LINUX32,   "ppcle",        "ppcle"},
+               {PER_LINUX,     "ppc64le",      "ppc64le"},
+# endif
 #endif
 #if defined(__x86_64__) || defined(__i386__) || defined(__ia64__)
-    {PER_LINUX32, "i386", "i386"},
-    {PER_LINUX32, "i486", "i386"},
-    {PER_LINUX32, "i586", "i386"},
-    {PER_LINUX32, "i686", "i386"},
-    {PER_LINUX32, "athlon", "i386"},
+               {PER_LINUX32,   "i386",         "i386"},
+               {PER_LINUX32,   "i486",         "i386"},
+               {PER_LINUX32,   "i586",         "i386"},
+               {PER_LINUX32,   "i686",         "i386"},
+               {PER_LINUX32,   "athlon",       "i386"},
 #endif
 #if defined(__x86_64__) || defined(__i386__)
-    {PER_LINUX, "x86_64", "x86_64"},
+               {PER_LINUX,     "x86_64",       "x86_64"},
 #endif
 #if defined(__ia64__) || defined(__i386__)
-    {PER_LINUX, "ia64", "ia64"},
+               {PER_LINUX,     "ia64",         "ia64"},
 #endif
 #if defined(__hppa__)
-    {PER_LINUX32, "parisc32", "parisc"},
-    {PER_LINUX32, "parisc", "parisc"},
-    {PER_LINUX, "parisc64", "parisc64"},
+               {PER_LINUX32,   "parisc32",     "parisc"},
+               {PER_LINUX32,   "parisc",       "parisc"},
+               {PER_LINUX,     "parisc64",     "parisc64"},
 #endif
 #if defined(__s390x__) || defined(__s390__)
-    {PER_LINUX32, "s390", "s390"},
-    {PER_LINUX, "s390x", "s390x"},
+               {PER_LINUX32,   "s390",         "s390"},
+               {PER_LINUX,     "s390x",        "s390x"},
 #endif
 #if defined(__sparc64__) || defined(__sparc__)
-    {PER_LINUX32, "sparc", "sparc"},
-    {PER_LINUX32, "sparc32bash", "sparc"},
-    {PER_LINUX32, "sparc32", "sparc"},
-    {PER_LINUX, "sparc64", "sparc64"},
+               {PER_LINUX32,   "sparc",        "sparc"},
+               {PER_LINUX32,   "sparc32bash",  "sparc"},
+               {PER_LINUX32,   "sparc32",      "sparc"},
+               {PER_LINUX,     "sparc64",      "sparc64"},
 #endif
 #if defined(__mips64__) || defined(__mips__)
-    {PER_LINUX32, "mips32", "mips"},
-    {PER_LINUX32, "mips", "mips"},
-    {PER_LINUX, "mips64", "mips64"},
+               {PER_LINUX32,   "mips32",       "mips"},
+               {PER_LINUX32,   "mips",         "mips"},
+               {PER_LINUX,     "mips64",       "mips64"},
 #endif
 #if defined(__alpha__)
-    {PER_LINUX, "alpha", "alpha"},
-    {PER_LINUX, "alphaev5", "alpha"},
-    {PER_LINUX, "alphaev56", "alpha"},
-    {PER_LINUX, "alphaev6", "alpha"},
-    {PER_LINUX, "alphaev67", "alpha"},
+               {PER_LINUX,     "alpha",        "alpha"},
+               {PER_LINUX,     "alphaev5",     "alpha"},
+               {PER_LINUX,     "alphaev56",    "alpha"},
+               {PER_LINUX,     "alphaev6",     "alpha"},
+               {PER_LINUX,     "alphaev67",    "alpha"},
 #endif
-    {-1, NULL, NULL}
-  };
-
-  for(i = 0; transitions[i].perval >= 0; i++)
-      if(!strcmp(pers, transitions[i].target_arch))
-       break;
-
-  if(transitions[i].perval < 0)
-    errx(EXIT_FAILURE, _("%s: Unrecognized architecture"), pers);
-
-  pers_value = transitions[i].perval | options;
-  if (set_pers(pers_value) == -EINVAL)
-    return 1;
-
-  uname(&un);
-  if(transitions[i].result_arch &&
-       strcmp(un.machine, transitions[i].result_arch))
-  {
-    if(strcmp(transitions[i].result_arch, "i386")
-       || (strcmp(un.machine, "i486")
-          && strcmp(un.machine, "i586")
-          && strcmp(un.machine, "i686")
-          && strcmp(un.machine, "athlon")))
-      errx(EXIT_FAILURE, _("%s: Unrecognized architecture"), pers);
-  }
-
-  return 0;
+#if defined(__e2k__)
+               {PER_LINUX,     "e2k",      "e2k"},
+               {PER_LINUX,     "e2kv4",        "e2k"},
+               {PER_LINUX,     "e2kv5",        "e2k"},
+               {PER_LINUX,     "e2kv6",        "e2k"},
+               {PER_LINUX,     "e2k4c",        "e2k"},
+               {PER_LINUX,     "e2k8c",        "e2k"},
+               {PER_LINUX,     "e2k1cp",       "e2k"},
+               {PER_LINUX,     "e2k8c2",       "e2k"},
+               {PER_LINUX,     "e2k12c",       "e2k"},
+               {PER_LINUX,     "e2k16c",       "e2k"},
+               {PER_LINUX,     "e2k2c3",       "e2k"},
+#endif
+               /* place holder, will be filled up at runtime */
+               {-1,            NULL,           NULL},
+               {-1,            NULL,           NULL}
+       };
+
+       /* Add the trivial transition {PER_LINUX, machine, machine} if no
+        * such target_arch is hardcoded yet.  */
+       uname(&un);
+       for (i = 0; transitions[i].perval >= 0; i++)
+               if (!strcmp(un.machine, transitions[i].target_arch))
+                       break;
+       if (transitions[i].perval < 0) {
+               unsigned long wrdsz = CHAR_BIT * sizeof(void *);
+               if (wrdsz == 32 || wrdsz == 64) {
+                       /* fill up the place holder */
+                       transitions[i].perval = wrdsz == 32 ? PER_LINUX32 : PER_LINUX;
+                       transitions[i].target_arch = un.machine;
+                       transitions[i].result_arch = un.machine;
+               }
+       }
+
+       return transitions;
+}
+
+/*
+ * List all execution domains from transitions
+ */
+static void list_arch_domains(struct arch_domain *doms)
+{
+       struct arch_domain *d;
+
+       for (d = doms; d->target_arch != NULL; d++)
+               printf("%s\n", d->target_arch);
+}
+
+static struct arch_domain *get_arch_domain(struct arch_domain *doms, const char *pers)
+{
+       struct arch_domain *d;
+
+       for (d = doms; d && d->perval >= 0; d++) {
+               if (!strcmp(pers, d->target_arch))
+                       break;
+       }
+
+       return !d || d->perval < 0 ? NULL : d;
+}
+
+static void verify_arch_domain(struct arch_domain *dom, const char *wanted)
+{
+       struct utsname un;
+
+       if (!dom || !dom->result_arch)
+               return;
+
+       uname(&un);
+       if (strcmp(un.machine, dom->result_arch)) {
+               if (strcmp(dom->result_arch, "i386")
+                   || (strcmp(un.machine, "i486")
+                       && strcmp(un.machine, "i586")
+                       && strcmp(un.machine, "i686")
+                       && strcmp(un.machine, "athlon")))
+                       errx(EXIT_FAILURE, _("Kernel cannot set architecture to %s"), wanted);
+       }
 }
 
 int main(int argc, char *argv[])
 {
-  const char *p;
-  unsigned long options = 0;
-  int verbose = 0;
-  int c;
-
-  /* Options --3gb and --4gb are for compatibitity with an old Debian setarch
-     implementation. */
-  static const struct option longopts[] =
-  {
-      { "help",               0, 0, 'h' },
-      { "version",            0, 0, 'V' },
-      { "verbose",            0, 0, 'v' },
-      { "addr-no-randomize",  0, 0, 'R' },
-      { "fdpic-funcptrs",     0, 0, 'F' },
-      { "mmap-page-zero",     0, 0, 'Z' },
-      { "addr-compat-layout", 0, 0, 'L' },
-      { "read-implies-exec",  0, 0, 'X' },
-      { "32bit",              0, 0, 'B' },
-      { "short-inode",        0, 0, 'I' },
-      { "whole-seconds",      0, 0, 'S' },
-      { "sticky-timeouts",    0, 0, 'T' },
-      { "3gb",                0, 0, '3' },
-      { "4gb",                0, 0, OPT_4GB },
-      { "uname-2.6",          0, 0, OPT_UNAME26 },
-      { NULL,                 0, 0, 0 }
-  };
-
-  setlocale(LC_ALL, "");
-  bindtextdomain(PACKAGE, LOCALEDIR);
-  textdomain(PACKAGE);
-  atexit(close_stdout);
-
-  if (argc < 1)
-    show_usage(_("Not enough arguments"));
-
-  p = program_invocation_short_name;
-  if (!strcmp(p, "setarch")) {
-    argv++;
-    argc--;
-    if (argc < 1)
-      show_usage(_("Not enough arguments"));
-    p = argv[0];
-    argv[0] = argv[-1];      /* for getopt_long() to get the program name */
-    if (!strcmp(p, "-h") || !strcmp(p, "--help"))
-      show_help();
-    else if (!strcmp(p, "-V") || !strcmp(p, "--version"))
-      show_version();
-  }
-  #if defined(__sparc64__) || defined(__sparc__)
-   if (!strcmp(p, "sparc32bash")) {
-       if (set_arch(p, 0L))
-           err(EXIT_FAILURE, _("Failed to set personality to %s"), p);
-       execl("/bin/bash", NULL);
-       err(EXIT_FAILURE, "/bin/bash");
-   }
-  #endif
-
-  while ((c = getopt_long(argc, argv, "+hVv3BFILRSTXZ", longopts, NULL)) != -1) {
-    switch (c) {
-    case 'h':
-      show_help();
-      break;
-    case 'V':
-      show_version();
-      break;
-    case 'v':
-      verbose = 1;
-      break;
-    case 'R':
-       turn_on(ADDR_NO_RANDOMIZE, options);
-       break;
-    case 'F':
-       turn_on(FDPIC_FUNCPTRS, options);
-       break;
-    case 'Z':
-       turn_on(MMAP_PAGE_ZERO, options);
-       break;
-    case 'L':
-       turn_on(ADDR_COMPAT_LAYOUT, options);
-       break;
-    case 'X':
-       turn_on(READ_IMPLIES_EXEC, options);
-       break;
-    case 'B':
-       turn_on(ADDR_LIMIT_32BIT, options);
-       break;
-    case 'I':
-       turn_on(SHORT_INODE, options);
-       break;
-    case 'S':
-       turn_on(WHOLE_SECONDS, options);
-       break;
-    case 'T':
-       turn_on(STICKY_TIMEOUTS, options);
-       break;
-    case '3':
-       turn_on(ADDR_LIMIT_3GB, options);
-       break;
-    case OPT_4GB:          /* just ignore this one */
-      break;
-    case OPT_UNAME26:
-       turn_on(UNAME26, options);
-       break;
-    }
-  }
-
-  argc -= optind;
-  argv += optind;
-
-  if (set_arch(p, options))
-    err(EXIT_FAILURE, _("Failed to set personality to %s"), p);
-
-  if (!argc) {
-    execl("/bin/sh", "-sh", NULL);
-    err(EXIT_FAILURE, "/bin/sh");
-  }
-
-  execvp(argv[0], argv);
-  err(EXIT_FAILURE, "%s", argv[0]);
-  return EXIT_FAILURE;
+       const char *arch = NULL;
+       unsigned long options = 0;
+       int verbose = 0;
+       int archwrapper;
+       int c;
+       struct arch_domain *doms, *target = NULL;
+       unsigned long pers_value = 0;
+       char *shell = NULL, *shell_arg = NULL;
+
+       /* Options without equivalent short options */
+       enum {
+               OPT_4GB = CHAR_MAX + 1,
+               OPT_UNAME26,
+               OPT_LIST
+       };
+
+       /* Options --3gb and --4gb are for compatibility with an old
+        * Debian setarch implementation.  */
+       static const struct option longopts[] = {
+               {"help",                no_argument,    NULL,   'h'},
+               {"version",             no_argument,    NULL,   'V'},
+               {"verbose",             no_argument,    NULL,   'v'},
+               {"addr-no-randomize",   no_argument,    NULL,   'R'},
+               {"fdpic-funcptrs",      no_argument,    NULL,   'F'},
+               {"mmap-page-zero",      no_argument,    NULL,   'Z'},
+               {"addr-compat-layout",  no_argument,    NULL,   'L'},
+               {"read-implies-exec",   no_argument,    NULL,   'X'},
+               {"32bit",               no_argument,    NULL,   'B'},
+               {"short-inode",         no_argument,    NULL,   'I'},
+               {"whole-seconds",       no_argument,    NULL,   'S'},
+               {"sticky-timeouts",     no_argument,    NULL,   'T'},
+               {"3gb",                 no_argument,    NULL,   '3'},
+               {"4gb",                 no_argument,    NULL,   OPT_4GB},
+               {"uname-2.6",           no_argument,    NULL,   OPT_UNAME26},
+               {"list",                no_argument,    NULL,   OPT_LIST},
+               {NULL,                  0,              NULL,   0}
+       };
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+       close_stdout_atexit();
+
+       if (argc < 1) {
+               warnx(_("Not enough arguments"));
+               errtryhelp(EXIT_FAILURE);
+       }
+       archwrapper = strcmp(program_invocation_short_name, "setarch") != 0;
+       if (archwrapper) {
+               arch = program_invocation_short_name;   /* symlinks to setarch */
+
+               /* Don't use ifdef sparc here, we get "Unrecognized architecture"
+                * error message later if necessary */
+               if (strcmp(arch, "sparc32bash") == 0) {
+                       shell = "/bin/bash";
+                       shell_arg = "";
+                       goto set_arch;
+               }
+       } else {
+               if (1 < argc && *argv[1] != '-') {
+                       arch = argv[1];
+                       argv[1] = argv[0];      /* for getopt_long() to get the program name */
+                       argv++;
+                       argc--;
+               }
+       }
+
+       while ((c = getopt_long(argc, argv, "+hVv3BFILRSTXZ", longopts, NULL)) != -1) {
+               switch (c) {
+               case 'v':
+                       verbose = 1;
+                       break;
+               case 'R':
+                       turn_on(ADDR_NO_RANDOMIZE, options);
+                       break;
+               case 'F':
+                       turn_on(FDPIC_FUNCPTRS, options);
+                       break;
+               case 'Z':
+                       turn_on(MMAP_PAGE_ZERO, options);
+                       break;
+               case 'L':
+                       turn_on(ADDR_COMPAT_LAYOUT, options);
+                       break;
+               case 'X':
+                       turn_on(READ_IMPLIES_EXEC, options);
+                       break;
+               case 'B':
+                       turn_on(ADDR_LIMIT_32BIT, options);
+                       break;
+               case 'I':
+                       turn_on(SHORT_INODE, options);
+                       break;
+               case 'S':
+                       turn_on(WHOLE_SECONDS, options);
+                       break;
+               case 'T':
+                       turn_on(STICKY_TIMEOUTS, options);
+                       break;
+               case '3':
+                       turn_on(ADDR_LIMIT_3GB, options);
+                       break;
+               case OPT_4GB:   /* just ignore this one */
+                       break;
+               case OPT_UNAME26:
+                       turn_on(UNAME26, options);
+                       break;
+               case OPT_LIST:
+                       if (!archwrapper) {
+                               list_arch_domains(init_arch_domains());
+                               return EXIT_SUCCESS;
+                       } else
+                               warnx(_("unrecognized option '--list'"));
+                       /* fallthrough */
+
+               default:
+                       errtryhelp(EXIT_FAILURE);
+               case 'h':
+                       usage(archwrapper);
+               case 'V':
+                       print_version(EXIT_SUCCESS);
+               }
+       }
+
+       if (!arch && !options)
+               errx(EXIT_FAILURE, _("no architecture argument or personality flags specified"));
+
+       argc -= optind;
+       argv += optind;
+
+set_arch:
+       /* get execution domain (architecture) */
+       if (arch) {
+               doms = init_arch_domains();
+               target = get_arch_domain(doms, arch);
+
+               if (!target)
+                       errx(EXIT_FAILURE, _("%s: Unrecognized architecture"), arch);
+               pers_value = target->perval;
+       }
+
+       /* add personality flags */
+       pers_value |= options;
+
+       /* call kernel */
+       if (personality(pers_value) < 0) {
+               /*
+                * Depending on architecture and kernel version, personality
+                * syscall is either capable or incapable of returning an error.
+                * If the return value is not an error, then it's the previous
+                * personality value, which can be an arbitrary value
+                * undistinguishable from an error value.
+                * To make things clear, a second call is needed.
+                */
+               if (personality(pers_value) < 0)
+                       err(EXIT_FAILURE, _("failed to set personality to %s"), arch);
+       }
+
+       /* make sure architecture is set as expected */
+       if (arch)
+               verify_arch_domain(target, arch);
+
+       if (!argc) {
+               shell = "/bin/sh";
+               shell_arg = "-sh";
+       }
+       if (verbose) {
+               printf(_("Execute command `%s'.\n"), shell ? shell : argv[0]);
+               /* flush all output streams before exec */
+               fflush(NULL);
+       }
+
+       /* Execute shell */
+       if (shell) {
+               execl(shell, shell_arg, NULL);
+               errexec(shell);
+       }
+
+       /* Execute on command line specified command */
+       execvp(argv[0], argv);
+       errexec(argv[0]);
 }