rewrote it
authorEnrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
Mon, 9 Feb 2004 23:35:49 +0000 (23:35 +0000)
committerEnrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
Mon, 9 Feb 2004 23:35:49 +0000 (23:35 +0000)
git-svn-id: http://svn.linux-vserver.org/svn/util-vserver/trunk@849 94cd875c-1c1d-0410-91d2-eb244daf1a30

util-vserver/src/chbind.c
util-vserver/src/reducecap.c

index d2074f3..21981ce 100644 (file)
@@ -20,7 +20,9 @@
 #ifdef HAVE_CONFIG_H
 #  include <config.h>
 #endif
-#include "compat.h"
+
+#include "vserver.h"
+#include "util.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <netdb.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
-#include <netinet/in.h>
 #include <net/if.h>
 #include <unistd.h>
 #include <errno.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
 
-#include "vserver.h"
+#define ENSC_WRAPPERS_IO       1
+#define ENSC_WRAPPERS_UNISTD   1
+#include "wrappers.h"
+
+#define CMD_HELP       0x1000
+#define CMD_VERSION    0x1001
+
+#define CMD_SILENT     0x2000
+#define CMD_IP         0x2001
+#define CMD_BCAST      0x2002
+
+int wrapper_exit_code = 255;
+
+
+static struct option const
+CMDLINE_OPTIONS[] = {
+  { "help",     no_argument,  0, CMD_HELP },
+  { "version",  no_argument,  0, CMD_VERSION },
+  { "silent",   no_argument,  0, CMD_SILENT },
+  { "ip",       required_argument, 0, CMD_IP },
+  { "bcast",    required_argument, 0, CMD_BCAST },
+  { 0,0,0,0 }
+};
+
+static void
+showHelp(int fd, char const *cmd, int res)
+{
+  WRITE_MSG(fd, "Usage:\n  ");
+  WRITE_STR(fd, cmd);
+  WRITE_MSG(fd,
+           " [--silent] [--ip <ip_num>[/<mask>]] [--bcast <broadcast>] [--] <commands> <args>*\n\n"
+           "Please report bugs to " PACKAGE_BUGREPORT "\n");
+
+  exit(res);
+}
 
-static void usage()
+static void
+showVersion()
 {
-       fprintf (stderr,"chbind version %s\n",VERSION);
-       fprintf (stderr,"chbind [ --silent ] [ --ip ip_num[/mask] ] [ --bcast broadcast ] command argument\n");
-       exit (-1);
+  WRITE_MSG(1,
+           "chbind " VERSION " -- bind to an ip and execute a program\n"
+           "This program is part of " PACKAGE_STRING "\n\n"
+           "Copyright (C) 2003,2004 Enrico Scholz\n"
+           VERSION_COPYRIGHT_DISCLAIMER);
+  exit(0);
 }
 
 /*
@@ -49,26 +92,33 @@ static void usage()
 
        Return != 0 if the device exist.
 */
-static int chbind_devexist (const char *dev)
+static bool
+existsDevice(char const *dev_raw)
 {
-       int ret = 0;
-       FILE *fin = fopen ("/proc/net/dev","r");
-       if (fin != NULL){
-               int len = strlen(dev);
-               char buf[1000];
-               fgets(buf,sizeof(buf)-1,fin);   // Skip one line
-               while (fgets(buf,sizeof(buf)-1,fin)!=NULL){
-                       const char *pt = strstr(buf,dev);
-                       if (pt != NULL && pt[len] == ':'){
-                               ret = 1;
-                               break;
-                       }
-               }
-               fclose (fin);
-       }
-       return ret;
-}
+  size_t       buf_size=8192;
+  char         dev[strlen(dev_raw)+2];
+
+  strcpy(dev, dev_raw);
+  strcat(dev, ":");
+  for (;;) {
+    char       buf[buf_size];
+    char *     pos;
+    bool       too_small;
+    int                fd=open("/proc/net/dev", O_RDONLY);
+    
+    if (fd==-1) return false;
+    too_small = EreadAll(fd, buf, buf_size);
+    close(fd);
 
+    if (too_small) {
+      buf_size *= 2;
+      continue;
+    }
+
+    pos = strstr(buf, dev);
+    return (pos && (pos==buf || pos[-1]==' ' || pos[-1]=='\n'));
+  }
+}
 
 static int ifconfig_ioctl(
        int fd,
@@ -87,12 +137,12 @@ static int ifconfig_ioctl(
 */
 int ifconfig_getaddr (
        const char *ifname,
-       unsigned long *addr,
-       unsigned long *mask,
-       unsigned long *bcast)
+       uint32_t *addr,
+       uint32_t *mask,
+       uint32_t *bcast)
 {
        int ret = -1;
-       if (chbind_devexist(ifname)){
+       if (existsDevice(ifname)){
                int skfd = socket(AF_INET, SOCK_DGRAM, 0);
                *addr = 0;
                *bcast = 0xffffffff;
@@ -119,118 +169,154 @@ int ifconfig_getaddr (
        return ret;
 }
 
+static void
+readIP(char const *str, struct vc_ip_mask_pair *ip, uint32_t *bcast)
+{
+  if (ifconfig_getaddr(str, &ip->ip, &ip->mask, bcast)==-1) {
+    char               *pt;
+    char               tmpopt[strlen(str)+1];
+    struct hostent     *h;
+
+    strcpy(tmpopt,str);
+    pt = strchr(tmpopt,'/');
+    
+    if (pt==0)
+      ip->mask = ntohl(0xffffff00);
+    else {
+      *pt++ = '\0';
+
+      // Ok, we have a network size, not a netmask
+      if (strchr(pt,'.')==0) {
+       int             sz = atoi(pt);
+       ;
+       for (ip->mask = 0; sz>0; --sz) {
+         ip->mask >>= 1;
+         ip->mask  |= 0x80000000;
+       }
+       ip->mask = ntohl(ip->mask);
+      }
+      else { 
+       struct hostent *h = gethostbyname (pt);
+       if (h==0) {
+         WRITE_MSG(2, "Invalid netmask '");
+         WRITE_STR(2, pt);
+         WRITE_MSG(2, "'\n");
+         exit(wrapper_exit_code);
+       }
+
+       memcpy (&ip->mask, h->h_addr, sizeof(ip->mask));
+      }
+    }
 
+    h = gethostbyname (tmpopt);
+    if (h==0) {
+      WRITE_MSG(2, "Invalid IP number or host name '");
+      WRITE_STR(2, tmpopt);
+      WRITE_MSG(2, "'\n");
+      exit(wrapper_exit_code);
+    }
 
+    memcpy (&ip->ip, h->h_addr,sizeof(ip->ip));
+  }
+}
+
+static void
+readBcast(char const *str, uint32_t *bcast)
+{
+  uint32_t     tmp;
+  if (ifconfig_getaddr(str, &tmp, &tmp, bcast)==-1){
+    struct hostent *h = gethostbyname (str);
+    if (h==0){
+      WRITE_MSG(2, "Invalid broadcast number '");
+      WRITE_STR(2, optarg);
+      WRITE_MSG(2, "'\n");
+      exit(wrapper_exit_code);
+    }
+    memcpy (bcast, h->h_addr,sizeof(*bcast));
+  }
+}
 
 int main (int argc, char *argv[])
 {
-       int ret = -1;
-       int silent = 0;
-       int i;
-       struct vc_ip_mask_pair  ips[16];
-       int nbaddrs = 0;
-       unsigned long bcast = 0xffffffff;
-       for (i=1; i<argc; i++){
-               const char *arg = argv[i];
-               const char *opt = argv[i+1];
-               if (strcmp(arg,"--ip")==0){
-                       unsigned long addr,mask;
-                       if (nbaddrs == 16){
-                               fprintf (stderr,"Too many IP numbers, max 16, ignored\n");
-
-                       }else if (ifconfig_getaddr(opt,&addr,&mask,&bcast)==-1){
-                               unsigned long mask = 0x00ffffff;
-                               const char *pt = strchr(opt,'/');
-                               char tmpopt[strlen(opt)+1];
-                               struct hostent *h;
-                               
-                               if (pt != NULL){
-                                       strcpy (tmpopt,opt);
-                                       tmpopt[pt-opt] = '\0';
-                                       opt = tmpopt;
-                                       pt++;
-                                       if (strchr(pt,'.')==NULL){
-                                               // Ok, we have a network size, not a netmask
-                                               int size = atoi(pt);
-                                               int i;
-                                               mask = 0;
-                                               for (i=0; i<size; i++){
-                                                       mask = mask >> 1;
-                                                       mask |= 0x80000000;
-                                               }
-                                               mask = ntohl(mask);
-                                       }else{
-                                               struct hostent *h = gethostbyname (pt);
-                                               if (h != NULL){
-                                                       memcpy (&mask,h->h_addr,sizeof(mask));
-                                               }else{
-                                                       fprintf (stderr,"Invalid netmask: %s\n",pt);
-                                                       usage();
-                                               }
-                                       }
-                                                       
-                               }
-
-                               h = gethostbyname (opt);
-                               if (h == NULL){
-                                       fprintf (stderr,"Invalid IP number or host name: %s\n",opt);
-                                       usage();
-                               }else{
-                                       memcpy (&addr,h->h_addr,sizeof(addr));
-                                       ips[nbaddrs].ip   = addr;
-                                       ips[nbaddrs].mask = mask;
-                                       ++nbaddrs;
-                               }
-                       }else{
-                             ips[nbaddrs].ip   = addr;
-                             ips[nbaddrs].mask = mask;
-                             ++nbaddrs;
-                       }
-                       i++;
-               }else if (strcmp(arg,"--bcast")==0){
-                       unsigned long tmp;
-                       if (ifconfig_getaddr(opt,&tmp,&tmp,&bcast)==-1){
-                               struct hostent *h = gethostbyname (opt);
-                               if (h == NULL){
-                                       fprintf (stderr,"Invalid broadcast number: %s\n",opt);
-                                       usage();
-                               }else{
-                                       memcpy (&bcast,h->h_addr,sizeof(bcast));
-                               }
-                       }
-                       i++;
-               }else if (strcmp(arg,"--silent")==0){
-                       silent = 1;
-               }else{
-                       break;
-               }
-       }
-       if (i == argc){
-               usage();
-       }else if (argv[i][0] == '-'){
-               usage();
-       }else{
-             if (vc_set_ipv4root(bcast,nbaddrs,ips)==0){
-                       if (!silent){
-                               int i;
-                               printf ("ipv4root is now");
-                               for (i=0; i<nbaddrs; i++){
-                                       unsigned long hostaddr = ntohl(ips[i].ip);
-                                       printf (" %ld.%ld.%ld.%ld"
-                                               ,hostaddr>>24
-                                               ,(hostaddr>>16)&0xff
-                                               ,(hostaddr>>8)&0xff
-                                               ,hostaddr &0xff);
-                               }
-                               printf ("\n");
-                       }
-                       execvp (argv[i],argv+i);
-                       fprintf (stderr,"Can't exec %s (%s)\n",argv[i],strerror(errno));
-               }else{
-                       fprintf (stderr,"Can't set the ipv4 root (%s)\n",strerror(errno));
-               }
+  bool                         is_silent = false;
+  struct vc_ip_mask_pair       ips[16];
+  size_t                       nbaddrs = 0;
+  uint32_t                     bcast = 0xffffffff;
+  
+  while (1) {
+    int                c = getopt_long(argc, argv, "+", CMDLINE_OPTIONS, 0);
+    if (c==-1) break;
+
+    switch (c) {
+      case CMD_HELP            :  showHelp(1, argv[0], 0);
+      case CMD_VERSION         :  showVersion();
+      case CMD_SILENT          :  is_silent = true; break;
+      case CMD_BCAST           :  readBcast(optarg, &bcast); break;
+      case CMD_IP              :
+       if (nbaddrs>=16) {
+         WRITE_MSG(2, "Too many IP numbers, max 16\n");
+         exit(wrapper_exit_code);
        }
-       return ret;
+       readIP(optarg, ips+nbaddrs, &bcast);
+       ++nbaddrs;
+       break;
+      default          :
+       WRITE_MSG(2, "Try '");
+       WRITE_STR(2, argv[0]);
+       WRITE_MSG(2, " --help\" for more information.\n");
+       exit(wrapper_exit_code);
+       break;
+    }
+  }
+
+  if (optind==argc) {
+    WRITE_MSG(2, "No command given; try '--help' for more information\n");
+    exit(wrapper_exit_code);
+  }
+  
+
+  if (vc_set_ipv4root(bcast,nbaddrs,ips)!=0) {
+    perror("vc_set_ipv4root()");
+    exit(wrapper_exit_code);
+  }
+
+  if (!is_silent) {
+    size_t             i;
+    
+    WRITE_MSG(1, "ipv4root is now");
+    for (i=0; i<nbaddrs; ++i) {
+      WRITE_MSG(1, " ");
+      WRITE_STR(1, inet_ntoa(*reinterpret_cast(struct in_addr *)(&ips[i].ip)));
+    }
+    WRITE_MSG(1, "\n");
+  }
+
+  Eexecvp (argv[optind],argv+optind);
+  return EXIT_SUCCESS;
 }
 
+#ifdef ENSC_TESTSUITE
+#include <assert.h>
 
+void test()
+{
+  struct vc_ip_mask_pair       ip;
+  uint32_t                     bcast;
+
+  bcast = 0;
+  readIP("1.2.3.4", &ip, &bcast);
+  assert(ip.ip==ntohl(0x01020304) && ip.mask==ntohl(0xffffff00) && bcast==0);
+
+  readIP("1.2.3.4/8", &ip, &bcast);
+  assert(ip.ip==ntohl(0x01020304) && ip.mask==ntohl(0xff000000) && bcast==0);
+
+  readIP("1.2.3.4/255.255.0.0", &ip, &bcast);
+  assert(ip.ip==ntohl(0x01020304) && ip.mask==ntohl(0xffff0000) && bcast==0);
+
+  readIP("localhost", &ip, &bcast);
+  assert(ip.ip==ntohl(0x7f000001) && ip.mask==ntohl(0xffffff00) && bcast==0);
+  
+  readIP("lo", &ip, &bcast);
+  assert(ip.ip==ntohl(0x7f000001) && ip.mask==ntohl(0xff000000) && bcast==ntohl(0x7fffffff));
+}
+#endif
index 2852dcd..caf6407 100644 (file)
 #ifdef HAVE_CONFIG_H
 #  include <config.h>
 #endif
-#include "compat.h"
+
+#include "util.h"
+#include "vserver.h"
 
 #include <stdio.h>
 #include <errno.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
+#include <getopt.h>
+#include <sys/param.h>
 
-#include "vserver.h"
 #include "linuxcaps.h"
 
-#ifndef CAP_QUOTACTL
-#  define CAP_QUOTACTL         VC_CAP_QUOTACTL
+#define ENSC_WRAPPERS_VSERVER  1
+#define ENSC_WRAPPERS_UNISTD   1
+#include <wrappers.h>
+
+
+#define CMD_HELP       0x1000
+#define CMD_VERSION    0x1001
+
+#define CMD_SHOW       0x2000
+#define CMD_PID                0x2001
+
+#define CMD_CAP                0x4000
+#define CMD_FLAG       0x4004
+#define CMD_SECURE     0x4006
+
+#ifdef VC_ENABLE_API_LEGACY
+#  define CMD_OBSOLETE_CHOWN                   0x8000
+#  define CMD_OBSOLETE_DAC_OVERRIDE            0x8001
+#  define CMD_OBSOLETE_DAC_READ_SEARCH         0x8002
+#  define CMD_OBSOLETE_FOWNER                  0x8003
+#  define CMD_OBSOLETE_FSETID                  0x8004
+#  define CMD_OBSOLETE_KILL                    0x8005
+#  define CMD_OBSOLETE_SETGID                  0x8006
+#  define CMD_OBSOLETE_SETUID                  0x8007
+#  define CMD_OBSOLETE_SETPCAP                 0x8008
+#  define CMD_OBSOLETE_SYS_TTY_CONFIG          0x8009
+#  define CMD_OBSOLETE_LEASE                   0x800a
+#  define CMD_OBSOLETE_SYS_CHROOT              0x800b
+#  define CMD_OBSOLETE_X_LINUX_IMMUTABLE       0x800c
+#  define CMD_OBSOLETE_X_NET_BIND_SERVICE      0x800d
+#  define CMD_OBSOLETE_X_NET_BROADCAST         0x800e
+#  define CMD_OBSOLETE_X_NET_ADMIN             0x800f
+#  define CMD_OBSOLETE_X_NET_RAW               0x8010
+#  define CMD_OBSOLETE_X_IPC_LOCK              0x8011
+#  define CMD_OBSOLETE_X_IPC_OWNER             0x8012
+#  define CMD_OBSOLETE_X_SYS_MODULE            0x8013
+#  define CMD_OBSOLETE_X_SYS_RAWIO             0x8014
+#  define CMD_OBSOLETE_X_SYS_PACCT             0x8015
+#  define CMD_OBSOLETE_X_SYS_ADMIN             0x8016
+#  define CMD_OBSOLETE_X_SYS_BOOT              0x8017
+#  define CMD_OBSOLETE_X_SYS_NICE              0x8018
+#  define CMD_OBSOLETE_X_SYS_RESOURCE          0x8019
+#  define CMD_OBSOLETE_X_SYS_TIME              0x801a
+#  define CMD_OBSOLETE_X_MKNOD                 0x801b
+#  define CMD_OBSOLETE_X_QUOTACTL              0x801c
+
+static char const * const      OBSOLETE_MAPPING[] = {
+  // 0                  1                  2                  3
+  "CHOWN",           "DAC_OVERRIDE",     "DAC_READ_SEARCH", "FOWNER",
+  "FSETID",          "KILL",             "SETGID",          "SETUID",
+  "SETPCAP",         "SYS_TTY_CONFIG",   "LEASE",           "SYS_CHROOT",
+  "LINUX_IMMUTABLE", "NET_BIND_SERVICE", "NET_BROADCAST",   "NET_ADMIN",
+  "NET_RAW",         "IPC_LOCK",         "IPC_OWNER",       "SYS_MODULE",
+  "SYS_RAWIO",       "SYS_PACCT",        "SYS_ADMIN",       "SYS_BOOT",
+  "SYS_NICE",        "SYS_RESOURCE",     "SYS_TIME",        "MKNOD",
+  "QUOTACTL" };
+#endif
+
+struct option const
+CMDLINE_OPTIONS[] = {
+  { "help",     no_argument,  0, CMD_HELP },
+  { "version",  no_argument,  0, CMD_VERSION },
+  { "cap",        required_argument,  0, CMD_CAP },
+  { "flag",       required_argument,  0, CMD_FLAG },
+  { "secure",     no_argument,        0, CMD_SECURE },
+  { "show",       no_argument,        0, CMD_SHOW },
+  { "pid",        required_argument,  0, CMD_PID },
+#ifdef VC_ENABLE_API_LEGACY
+  { "CAP_CHOWN",              no_argument,  0, CMD_OBSOLETE_CHOWN },
+  { "CAP_DAC_OVERRIDE",       no_argument,  0, CMD_OBSOLETE_DAC_OVERRIDE },
+  { "CAP_DAC_READ_SEARCH",    no_argument,  0, CMD_OBSOLETE_DAC_READ_SEARCH },
+  { "CAP_FOWNER",             no_argument,  0, CMD_OBSOLETE_FOWNER },
+  { "CAP_FSETID",             no_argument,  0, CMD_OBSOLETE_FSETID },
+  { "CAP_KILL",               no_argument,  0, CMD_OBSOLETE_KILL },
+  { "CAP_SETGID",             no_argument,  0, CMD_OBSOLETE_SETGID },
+  { "CAP_SETUID",             no_argument,  0, CMD_OBSOLETE_SETUID },
+  { "CAP_SETPCAP",            no_argument,  0, CMD_OBSOLETE_SETPCAP },
+  { "CAP_SYS_TTY_CONFIG",     no_argument,  0, CMD_OBSOLETE_SYS_TTY_CONFIG },
+  { "CAP_LEASE",              no_argument,  0, CMD_OBSOLETE_LEASE },
+  { "CAP_SYS_CHROOT",         no_argument,  0, CMD_OBSOLETE_SYS_CHROOT },
+  { "--CAP_LINUX_IMMUTABLE",  no_argument,  0, CMD_OBSOLETE_X_LINUX_IMMUTABLE },
+  { "--CAP_NET_BIND_SERVICE", no_argument,  0, CMD_OBSOLETE_X_NET_BIND_SERVICE },
+  { "--CAP_NET_BROADCAST",    no_argument,  0, CMD_OBSOLETE_X_NET_BROADCAST },
+  { "--CAP_NET_ADMIN",        no_argument,  0, CMD_OBSOLETE_X_NET_ADMIN },
+  { "--CAP_NET_RAW",          no_argument,  0, CMD_OBSOLETE_X_NET_RAW },
+  { "--CAP_IPC_LOCK",         no_argument,  0, CMD_OBSOLETE_X_IPC_LOCK },
+  { "--CAP_IPC_OWNER",        no_argument,  0, CMD_OBSOLETE_X_IPC_OWNER },
+  { "--CAP_SYS_MODULE",       no_argument,  0, CMD_OBSOLETE_X_SYS_MODULE },
+  { "--CAP_SYS_RAWIO",        no_argument,  0, CMD_OBSOLETE_X_SYS_RAWIO },
+  { "--CAP_SYS_PACCT",        no_argument,  0, CMD_OBSOLETE_X_SYS_PACCT },
+  { "--CAP_SYS_ADMIN",        no_argument,  0, CMD_OBSOLETE_X_SYS_ADMIN },
+  { "--CAP_SYS_BOOT",         no_argument,  0, CMD_OBSOLETE_X_SYS_BOOT },
+  { "--CAP_SYS_NICE",         no_argument,  0, CMD_OBSOLETE_X_SYS_NICE },
+  { "--CAP_SYS_RESOURCE",     no_argument,  0, CMD_OBSOLETE_X_SYS_RESOURCE },
+  { "--CAP_SYS_TIME",         no_argument,  0, CMD_OBSOLETE_X_SYS_TIME },
+  { "--CAP_MKNOD",            no_argument,  0, CMD_OBSOLETE_X_MKNOD },
+  { "--CAP_QUOTACTL",         no_argument,  0, CMD_OBSOLETE_X_QUOTACTL }, 
 #endif
+  { 0,0,0,0 }
+};
+
+int wrapper_exit_code  = 255;
 
 extern int capget (struct __user_cap_header_struct *, struct __user_cap_data_struct *);
 extern int capset (struct __user_cap_header_struct *, struct __user_cap_data_struct *);
 
-static void usage()
+static void
+showHelp(int fd, char const *cmd, int res)
 {
-       fprintf (stderr,"reducecap version %s\n",VERSION);
-       fprintf (stderr,"reducecap [ options ] command argument\n");
-       exit (-1);
+  WRITE_MSG(fd, "Usage:\n  ");
+  WRITE_STR(fd, cmd);
+  WRITE_MSG(fd,
+           " [--show] [--secure] [--flag <flag>] [--cap <capability>] [--] <cmd> <args>*\n  ");
+  WRITE_STR(fd, cmd);
+  WRITE_MSG(fd,
+           " --show [--pid <pid>]\n\n"
+           "Please report bugs to " PACKAGE_BUGREPORT "\n");
+
+  exit(res);
 }
 
-static void reducecap_print(struct __user_cap_data_struct *user)
+static void
+showVersion()
 {
-       int i;
-       printf ("%22s %9s %9s %9s\n","Capability","Effective","Permitted"
-               ,"Inheritable");
-       for (i=0;; ++i) {
-               char const *    text = vc_cap2text(i);
-               int             bit  = 1<<i;
-               if (text==0) break;
-               
-               printf ("%-22s %9s %9s %9s\n"
-                       ,text
-                       ,(user->effective   & bit) ? "X    " : " "
-                       ,(user->permitted   & bit) ? "X    " : " "
-                       ,(user->inheritable & bit) ? "X    " : " ");
-       }
+  WRITE_MSG(1,
+           "reducecap " VERSION " -- starts programs with reduced capabilities\n"
+           "This program is part of " PACKAGE_STRING "\n\n"
+           "Copyright (C) 2003,2004 Enrico Scholz\n"
+           VERSION_COPYRIGHT_DISCLAIMER);
+  exit(0);
 }
 
-static void reducecap_show()
+static void
+printReducecap(struct __user_cap_data_struct *user)
 {
-       struct __user_cap_header_struct header;
-       struct __user_cap_data_struct user;
-       header.version = _LINUX_CAPABILITY_VERSION;
-       header.pid = getpid();
-       if (capget(&header,&user)==-1){
-               perror ("capget");
-       }else{
-               reducecap_print (&user);
-       }
+  int i;
+  WRITE_MSG(1, "            Capability Effective  Permitted  Inheritable\n");
+
+  for (i=0;; ++i) {
+    size_t const       len  = 23 + 10*2 + 4+2;
+    char const *       text = vc_cap2text(i);
+    int                        bit  = 1<<i;
+    size_t             l;
+    char               buf[len];
+    if (text==0) break;
+
+    memset(buf, ' ', sizeof buf);
+    buf[len-1] = '\n';
+    l = MIN(strlen(text), 22);
+    memcpy(buf, text, l);
+    buf[23 + 10*0 + 4] = (user->effective   & bit) ? 'X' : ' ';
+    buf[23 + 10*1 + 4] = (user->permitted   & bit) ? 'X' : ' ';
+    buf[23 + 10*2 + 4] = (user->inheritable & bit) ? 'X' : ' ';
+    write(1, buf, len);
+  }
+}
+
+static void
+show(pid_t pid)
+{
+  struct __user_cap_header_struct header;
+  struct __user_cap_data_struct user;
+  header.version = _LINUX_CAPABILITY_VERSION;
+  header.pid     = pid;
+  if (capget(&header,&user)==-1){
+    perror ("capget");
+    exit(wrapper_exit_code);
+  }
+  
+  printReducecap(&user);
 }
 
+static uint32_t
+getCap(char const *cap)
+{
+  int          bit = vc_text2cap(cap);
+  if (bit!=0) {
+    WRITE_MSG(2, "Unknown capability '");
+    WRITE_STR(2, optarg);
+    WRITE_MSG(2, "'; try '--help' for more information\n");
+    exit(wrapper_exit_code);
+  }
 
+  return (1<<bit);
+}
 
 int main (int argc, char *argv[])
 {
-       int ret = -1;
-       unsigned long remove = 0;
-       int show = 0;
-       int flags = 0;
-       unsigned long secure = (1<<CAP_LINUX_IMMUTABLE)
-               |(1<<CAP_NET_BROADCAST)
-               |(1<<CAP_NET_ADMIN)
-               |(1<<CAP_NET_RAW)
-               |(1<<CAP_IPC_LOCK)
-               |(1<<CAP_IPC_OWNER)
-               |(1<<CAP_SYS_MODULE)
-               |(1<<CAP_SYS_RAWIO)
-               |(1<<CAP_SYS_PACCT)
-               |(1<<CAP_SYS_ADMIN)
-               |(1<<CAP_SYS_BOOT)
-               |(1<<CAP_SYS_NICE)
-               |(1<<CAP_SYS_RESOURCE)
-               |(1<<CAP_SYS_TIME)
-               |(1<<CAP_MKNOD)
-               |(1<<CAP_QUOTACTL);
-       int i;
-       for (i=1; i<argc; i++){
-               const char *arg = argv[i];
-               const char *opt = argv[i+1];
-               if (strcmp(arg,"--secure")==0){
-                       remove = secure;
-               }else if (strcmp(arg,"--show")==0){
-                       show = 1;
-               }else if (strcmp(arg,"--flag")==0){
-                       if (strcmp(opt,"lock")==0){
-                               flags |= 1;
-                       }else if (strcmp(opt,"sched")==0){
-                               flags |= 2;
-                       }else if (strcmp(opt,"nproc")==0){
-                               flags |= 4;
-                       }else if (strcmp(opt,"private")==0){
-                               flags |= 8;
-                       }else if (strcmp(opt,"hideinfo")==0){
-                               flags |= 32;
-                       }else{
-                               fprintf (stderr,"Unknown flag %s\n",opt);
-                       }
-                       i++;
-               }else if (arg[0] == '-' && arg[1] == '-'){
-                       static struct {
-                               const char *option;
-                               int bit;
-                       }tbcap[]={
-                               // The following capabilities are normally available
-                               // to vservers administrator, but are place for
-                               // completeness
-                               {"CAP_CHOWN",CAP_CHOWN},
-                               {"CAP_DAC_OVERRIDE",CAP_DAC_OVERRIDE},
-                               {"CAP_DAC_READ_SEARCH",CAP_DAC_READ_SEARCH},
-                               {"CAP_FOWNER",CAP_FOWNER},
-                               {"CAP_FSETID",CAP_FSETID},
-                               {"CAP_KILL",CAP_KILL},
-                               {"CAP_SETGID",CAP_SETGID},
-                               {"CAP_SETUID",CAP_SETUID},
-                               {"CAP_SETPCAP",CAP_SETPCAP},
-                               {"CAP_SYS_TTY_CONFIG",CAP_SYS_TTY_CONFIG},
-                               {"CAP_LEASE",CAP_LEASE},
-                               {"CAP_SYS_CHROOT",CAP_SYS_CHROOT},
-
-                               // Those capabilities are not normally available
-                               // to vservers because they are not needed and
-                               // may represent a security risk
-                               {"--LINUX_IMMUTABLE",CAP_LINUX_IMMUTABLE},
-                               {"--NET_BIND_SERVICE",CAP_NET_BIND_SERVICE},
-                               {"--NET_BROADCAST",CAP_NET_BROADCAST},
-                               {"--NET_ADMIN", CAP_NET_ADMIN},
-                               {"--NET_RAW",   CAP_NET_RAW},
-                               {"--IPC_LOCK",  CAP_IPC_LOCK},
-                               {"--IPC_OWNER", CAP_IPC_OWNER},
-                               {"--SYS_MODULE",CAP_SYS_MODULE},
-                               {"--SYS_RAWIO", CAP_SYS_RAWIO},
-                               {"--SYS_PACCT", CAP_SYS_PACCT},
-                               {"--SYS_ADMIN", CAP_SYS_ADMIN},
-                               {"--SYS_BOOT",  CAP_SYS_BOOT},
-                               {"--SYS_NICE",  CAP_SYS_NICE},
-                               {"--SYS_RESOURCE",CAP_SYS_RESOURCE},
-                               {"--SYS_TIME",  CAP_SYS_TIME},
-                               {"--MKNOD",             CAP_MKNOD},
-                               {"--QUOTACTL",          CAP_QUOTACTL},
-                               {NULL,0}
-                       };
-                       int j;
-                       for (j=0; tbcap[j].option != NULL; j++){
-                               if (strcasecmp(tbcap[j].option,arg)==0){
-                                       remove |= (1<<tbcap[j].bit);
-                                       break;
-                               }
-                       }
-                       if (tbcap[j].option != NULL){
-                               usage();
-                       }
-               }else{
-                       break;
-               }
-       }
-       if (i == argc){
-               if (show){
-                       reducecap_show();
-               }else{
-                       usage();
-               }
-       }else if (argv[i][0] == '-'){
-               usage();
-       }else{
-               struct __user_cap_header_struct header;
-               struct __user_cap_data_struct user;
-               header.version = _LINUX_CAPABILITY_VERSION;
-               header.pid = 0;
-               if (capget(&header,&user)==-1){
-                       perror ("capget");
-               }else{
-                       if (show){
-                               reducecap_print (&user);
-                       }
-                       if (vc_new_s_context(VC_SAMECTX,remove,flags)==VC_NOCTX){
-                               perror ("new_s_context -2");
-                       }else{
-                               fprintf (stderr,"Executing\n");
-                               execvp (argv[i],argv+i);
-                               fprintf (stderr,"Can't execute command %s\n",argv[i]);
-                       }
-               }
+  uint32_t             remove  = 0;
+  bool                 do_show = false;
+  uint32_t             flags   = 0;
+  pid_t                        pid     = 0;
+  bool                 show_obsolete_warning = true;
+
+  while (1) {
+    int                c = getopt_long(argc, argv, "+", CMDLINE_OPTIONS, 0);
+    if (c==-1) break;
+
+#ifdef VC_ENABLE_API_LEGACY
+    if (c>=CMD_OBSOLETE_CHOWN && c<=CMD_OBSOLETE_X_QUOTACTL) {
+      if (show_obsolete_warning) {
+       WRITE_MSG(2, "reducecap: warning, obsolete CLI used\n");
+       show_obsolete_warning = false;
+      }
+
+      remove = getCap(OBSOLETE_MAPPING[c-CMD_OBSOLETE_CHOWN]);
+      continue;
+    }
+#endif    
+    switch (c) {
+      case CMD_HELP            :  showHelp(1, argv[0], 0);
+      case CMD_VERSION         :  showVersion();
+      case CMD_SECURE          :  remove  = vc_get_securecaps(); break;
+      case CMD_SHOW            :  do_show = true;  break; 
+      case CMD_PID             :  pid     = atoi(optarg);   break;
+      case CMD_CAP             :  remove  = getCap(optarg); break;
+      case CMD_FLAG            : {
+       char const      *err_ptr;
+       size_t          err_len;
+       
+       flags = vc_textlist2flag(optarg, 0, &err_ptr, &err_len);
+       if (err_ptr!=0) {
+         WRITE_MSG(2, "Unknown flag '");
+         write(2, err_ptr, err_len);
+         WRITE_MSG(2, "'\n");
+         exit(wrapper_exit_code);
        }
-       return ret;
-}
+       break;
+      }
+    }
+  }
+
+  if (!do_show && optind==argc) {
+    WRITE_MSG(2, "No command given; use '--help' for more information\n");
+    exit(wrapper_exit_code);
+  }
 
+  if (!do_show && pid!=0) {
+    WRITE_MSG(2, "A pid can be specified in '--show' mode only; use '--help' for more information\n");
+    exit(wrapper_exit_code);
+  }  
+
+  if (do_show && optind==argc)
+    show(pid);
+  else {
+    Evc_new_s_context(VC_SAMECTX, remove, flags);
+    if (do_show) show(pid);
+
+    WRITE_MSG(2, "Executing\n");
+    Eexecvp(argv[optind], argv+optind);
+  }
+
+  return EXIT_SUCCESS;
+}