summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillem Jover <guillem@debian.org>2009-07-03 02:21:43 +0200
committerGuillem Jover <guillem@debian.org>2009-09-30 21:48:57 +0200
commit12a61afc463c74a40ac65ccc0cb6f75dee532f16 (patch)
tree782ffa288029cb052dd1c955331e40e6d82de323
parentd96bee65e139db050bd981a42e29c3763847ee77 (diff)
downloaddpkg-12a61afc463c74a40ac65ccc0cb6f75dee532f16.tar.gz
dpkg-statoverride: Rewrite in C
-rw-r--r--debian/changelog1
-rw-r--r--po/POTFILES.in2
-rw-r--r--scripts/Makefile.am2
-rwxr-xr-xscripts/dpkg-statoverride.pl247
-rw-r--r--src/.gitignore1
-rw-r--r--src/Makefile.am16
-rw-r--r--src/statcmd.c437
7 files changed, 455 insertions, 251 deletions
diff --git a/debian/changelog b/debian/changelog
index b48d89e99..fa8b5eb96 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -19,6 +19,7 @@ dpkg (1.15.5) UNRELEASED; urgency=low
* Add C coding style document.
* Make dpkg as strict as dpkg-statoverride on input when validating the
parsed data from the statdb.
+ * Rewrite dpkg-statoverride in C.
[ Raphaël Hertzog ]
* Add versioned dependency on base-files (>= 5.0.0) to dpkg-dev to ensure
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 1a63c5c17..259f14466 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -42,6 +42,7 @@ src/processarc.c
src/query.c
src/remove.c
src/select.c
+src/statcmd.c
src/statdb.c
src/trigcmd.c
src/trigproc.c
@@ -61,5 +62,4 @@ dpkg-split/split.c
utils/start-stop-daemon.c
scripts/dpkg-divert.pl
-scripts/dpkg-statoverride.pl
scripts/update-alternatives.pl
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
index a1150aa80..9b287a0f1 100644
--- a/scripts/Makefile.am
+++ b/scripts/Makefile.am
@@ -16,7 +16,6 @@ bin_SCRIPTS = \
dpkg-scanpackages \
dpkg-scansources \
dpkg-shlibdeps \
- dpkg-statoverride \
dpkg-source \
dpkg-vendor \
update-alternatives
@@ -41,7 +40,6 @@ EXTRA_DIST = \
dpkg-shlibdeps.pl \
dpkg-source.pl \
dpkg-divert.pl \
- dpkg-statoverride.pl \
dpkg-vendor.pl \
update-alternatives.pl \
changelog/debian.pl \
diff --git a/scripts/dpkg-statoverride.pl b/scripts/dpkg-statoverride.pl
deleted file mode 100755
index 09b07b1d1..000000000
--- a/scripts/dpkg-statoverride.pl
+++ /dev/null
@@ -1,247 +0,0 @@
-#! /usr/bin/perl
-
-BEGIN { # Work-around for bug #479711 in perl
- $ENV{PERL_DL_NONLAZY} = 1;
-}
-
-use strict;
-use warnings;
-
-use POSIX;
-use POSIX qw(:errno_h :signal_h);
-use Dpkg;
-use Dpkg::Gettext;
-
-textdomain("dpkg");
-
-my $verbose = 1;
-my $doforce = 0;
-my $doupdate = 0;
-my $mode = "";
-
-my %owner;
-my %group;
-my %mode;
-
-sub version {
- printf _g("Debian %s version %s.\n"), $progname, $version;
-
- printf _g("
-Copyright (C) 2000 Wichert Akkerman.");
-
- printf _g("
-This is free software; see the GNU General Public Licence version 2 or
-later for copying conditions. There is NO warranty.
-");
-}
-
-sub usage {
- printf _g(
-"Usage: %s [<option> ...] <command>
-
-Commands:
- --add <owner> <group> <mode> <file>
- add a new entry into the database.
- --remove <file> remove file from the database.
- --list [<glob-pattern>] list current overrides in the database.
-
-Options:
- --admindir <directory> set the directory with the statoverride file.
- --update immediately update file permissions.
- --force force an action even if a sanity check fails.
- --quiet quiet operation, minimal output.
- --help show this help message.
- --version show the version.
-"), $progname;
-}
-
-sub CheckModeConflict {
- return unless $mode;
- badusage(sprintf(_g("two commands specified: %s and --%s"), $_, $mode));
-}
-
-while (@ARGV) {
- $_=shift(@ARGV);
- last if m/^--$/;
- if (!m/^-/) {
- unshift(@ARGV,$_); last;
- } elsif (m/^--help$/) {
- usage();
- exit(0);
- } elsif (m/^--version$/) {
- version();
- exit(0);
- } elsif (m/^--update$/) {
- $doupdate=1;
- } elsif (m/^--quiet$/) {
- $verbose=0;
- } elsif (m/^--force$/) {
- $doforce=1;
- } elsif (m/^--admindir$/) {
- @ARGV || badusage(sprintf(_g("--%s needs a <directory> argument"), "admindir"));
- $admindir= shift(@ARGV);
- } elsif (m/^--add$/) {
- CheckModeConflict();
- $mode= 'add';
- } elsif (m/^--remove$/) {
- CheckModeConflict();
- $mode= 'remove';
- } elsif (m/^--list$/) {
- CheckModeConflict();
- $mode= 'list';
- } else {
- badusage(sprintf(_g("unknown option \`%s'"), $_));
- }
-}
-
-my $dowrite = 0;
-my $exitcode = 0;
-
-badusage(_g("no mode specified")) unless $mode;
-ReadOverrides();
-
-if ($mode eq "add") {
- @ARGV == 4 || badusage(_g("--add needs four arguments"));
-
- my $user = $ARGV[0];
- my $uid = 0;
- my $gid = 0;
-
- if ($user =~ m/^#([0-9]+)$/) {
- $uid=$1;
- badusage(sprintf(_g("illegal user %s"), $user)) if ($uid < 0);
- } else {
- my ($name, $pw);
- (($name, $pw, $uid) = getpwnam($user)) ||
- badusage(sprintf(_g("non-existing user %s"), $user));
- }
-
- my $group = $ARGV[1];
- if ($group =~ m/^#([0-9]+)$/) {
- $gid=$1;
- badusage(sprintf(_g("illegal group %s"), $group)) if ($gid < 0);
- } else {
- my ($name, $pw);
- (($name, $pw, $gid) = getgrnam($group)) ||
- badusage(sprintf(_g("non-existing group %s"), $group));
- }
-
- my $mode = $ARGV[2];
- (($mode < 0) or (oct($mode) > 07777) or ($mode !~ m/\d+/)) &&
- badusage(sprintf(_g("illegal mode %s"), $mode));
- my $file = $ARGV[3];
- $file =~ m/\n/ && badusage(_g("file may not contain newlines"));
- $file =~ s,/+$,, && print STDERR _g("stripping trailing /")."\n";
-
- if (defined $owner{$file}) {
- printf STDERR _g("An override for \"%s\" already exists, "), $file;
- if ($doforce) {
- print STDERR _g("but --force specified so will be ignored.")."\n";
- } else {
- print STDERR _g("aborting")."\n";
- exit(3);
- }
- }
- $owner{$file}=$user;
- $group{$file}=$group;
- $mode{$file}=$mode;
- $dowrite=1;
-
- if ($doupdate) {
- if (not -e $file) {
- printf STDERR _g("warning: --update given but %s does not exist")."\n", $file;
- } else {
- chown ($uid,$gid,$file) || warn sprintf(_g("failed to chown %s: %s"), $file, $!)."\n";
- chmod (oct($mode),$file) || warn sprintf(_g("failed to chmod %s: %s"), $file, $!)."\n";
- }
- }
-} elsif ($mode eq "remove") {
- @ARGV == 1 || badusage(sprintf(_g("--%s needs a single argument"), "remove"));
- my $file = $ARGV[0];
- $file =~ s,/+$,, && print STDERR _g("stripping trailing /")."\n";
- if (not defined $owner{$file}) {
- print STDERR _g("No override present.")."\n";
- exit(0) if ($doforce);
- exit(2);
- }
- delete $owner{$file};
- delete $group{$file};
- delete $mode{$file};
- $dowrite=1;
- print(STDERR _g("warning: --update is useless for --remove")."\n") if ($doupdate);
-} elsif ($mode eq "list") {
- my (@list, @ilist);
-
- @ilist= @ARGV ? @ARGV : ('*');
- while (defined($_=shift(@ilist))) {
- s/\W/\\$&/g;
- s/\\\?/./g;
- s/\\\*/.*/g;
- s,/+$,, && print STDERR _g("stripping trailing /")."\n";
- push(@list,"^$_\$");
- }
-
- my $pattern = join('|', @list);
- $exitcode=1;
- for my $file (keys %owner) {
- next unless ($file =~ m/$pattern/o);
- $exitcode=0;
- print "$owner{$file} $group{$file} $mode{$file} $file\n";
- }
-}
-
-WriteOverrides() if ($dowrite);
-
-exit($exitcode);
-
-sub ReadOverrides {
- open(SO, "$admindir/statoverride") ||
- quit(sprintf(_g("cannot open statoverride: %s"), $!));
- while (<SO>) {
- my ($owner,$group,$mode,$file);
- chomp;
-
- ($owner,$group,$mode,$file)=split(' ', $_, 4);
- die sprintf(_g("Multiple overrides for \"%s\", aborting"), $file)
- if defined $owner{$file};
- $owner{$file}=$owner;
- $group{$file}=$group;
- $mode{$file}=$mode;
- }
- close(SO);
-}
-
-
-sub WriteOverrides {
- my ($file);
-
- open(SO, ">$admindir/statoverride-new") ||
- quit(sprintf(_g("cannot open new statoverride file: %s"), $!));
- foreach $file (keys %owner) {
- print SO "$owner{$file} $group{$file} $mode{$file} $file\n";
- }
- close(SO);
- chmod(0644, "$admindir/statoverride-new");
- unlink("$admindir/statoverride-old") ||
- $! == ENOENT || quit(sprintf(_g("error removing statoverride-old: %s"), $!));
- link("$admindir/statoverride","$admindir/statoverride-old") ||
- $! == ENOENT || quit(sprintf(_g("error creating new statoverride-old: %s"), $!));
- rename("$admindir/statoverride-new","$admindir/statoverride")
- || quit(sprintf(_g("error installing new statoverride: %s"), $!));
-}
-
-
-sub quit
-{
- printf STDERR "%s: %s\n", $0, "@_";
- exit(2);
-}
-
-sub badusage
-{
- printf STDERR "%s: %s\n\n", $0, "@_";
- usage();
- exit(2);
-}
-
-# vi: ts=8 sw=8 ai si cindent
diff --git a/src/.gitignore b/src/.gitignore
index 9b61029aa..10f60e91b 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -1,3 +1,4 @@
dpkg
dpkg-query
+dpkg-statoverride
dpkg-trigger
diff --git a/src/Makefile.am b/src/Makefile.am
index 820cf1c59..a29b62910 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -11,7 +11,11 @@ AM_CPPFLAGS = \
-I$(top_srcdir)/lib
-bin_PROGRAMS = dpkg dpkg-query dpkg-trigger
+bin_PROGRAMS = \
+ dpkg \
+ dpkg-query \
+ dpkg-statoverride \
+ dpkg-trigger
dpkg_SOURCES = \
archives.c archives.h \
@@ -52,6 +56,16 @@ dpkg_query_LDADD = \
../lib/compat/libcompat.a \
$(LIBINTL)
+dpkg_statoverride_SOURCES = \
+ filesdb.c filesdb.h \
+ statdb.c \
+ statcmd.c
+
+dpkg_statoverride_LDADD = \
+ ../lib/dpkg/libdpkg.a \
+ ../lib/compat/libcompat.a \
+ $(LIBINTL)
+
dpkg_trigger_SOURCES = \
trigcmd.c
diff --git a/src/statcmd.c b/src/statcmd.c
new file mode 100644
index 000000000..2241302c2
--- /dev/null
+++ b/src/statcmd.c
@@ -0,0 +1,437 @@
+/*
+ * dpkg-statoverrides - override ownership and mode of files
+ *
+ * Copyright © 2000, 2001 Wichert Akkerman <wakkerma@debian.org>
+ * Copyright © 2006-2009 Guillem Jover <guillem@debian.org>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2,
+ * or (at your option) any later version.
+ *
+ * This is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <config.h>
+#include <compat.h>
+
+#include <dpkg/i18n.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <signal.h>
+#include <grp.h>
+#include <pwd.h>
+#include <fnmatch.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#if HAVE_LOCALE_H
+#include <locale.h>
+#endif
+
+#include <dpkg/dpkg.h>
+#include <dpkg/dpkg-db.h>
+#include <dpkg/path.h>
+#include <dpkg/myopt.h>
+
+#include "main.h"
+#include "filesdb.h"
+
+const char thisname[] = "dpkg-statoverrides";
+const char printforhelp[] = N_(
+"Use --help for help about querying packages;\n"
+"Use --license for copyright license and lack of warranty (GNU GPL).");
+
+static void
+printversion(const struct cmdinfo *cip, const char *value)
+{
+ printf(_("Debian %s version %s.\n"), thisname, DPKG_VERSION_ARCH);
+
+ printf(_(
+"Copyright (C) 2000, 2001 Wichert Akkerman.\n"
+"Copyright (C) 2006-2009 Guillem Jover."));
+
+ printf(_(
+"This is free software; see the GNU General Public Licence version 2 or\n"
+"later for copying conditions. There is NO warranty.\n"));
+
+ m_output(stdout, _("<standard output"));
+
+ exit(0);
+}
+
+static void
+usage(const struct cmdinfo *cip, const char *value)
+{
+ printf(_(
+"Usage: %s [<option> ...] <command>\n"
+"\n"), thisname);
+
+ printf(_(
+"Commands:\n"
+" --add <owner> <group> <mode> <file>\n"
+" add a new entry into the database.\n"
+" --remove <file> remove file from the database.\n"
+" --list [<glob-pattern>] list current overrides in the database.\n"
+"\n"));
+
+ printf(_(
+"Options:\n"
+" --admindir <directory> set the directory with the statoverride file.\n"
+" --update immediately update file permissions.\n"
+" --force force an action even if a sanity check fails.\n"
+" --quiet quiet operation, minimal output.\n"
+" --help show this help message.\n"
+" --version show the version.\n"
+"\n"));
+
+ m_output(stdout, _("<standard output"));
+
+ exit(0);
+}
+
+const struct cmdinfo *cipaction = NULL;
+const char *admindir = ADMINDIR;
+
+static int opt_verbose = 1;
+static int opt_force = 0;
+static int opt_update = 0;
+
+static void
+setaction(const struct cmdinfo *cip, const char *value)
+{
+ if (cipaction)
+ badusage(_("conflicting actions -%c (--%s) and -%c (--%s)"),
+ cip->oshort, cip->olong,
+ cipaction->oshort, cipaction->olong);
+ cipaction = cip;
+}
+
+static char *
+path_cleanup(const char *path)
+{
+ char *new_path = m_strdup(path);
+
+ path_rtrim_slash_slashdot(new_path);
+ if (strcmp(path, new_path) != 0)
+ warning(_("stripping trailing /"));
+
+ return new_path;
+}
+
+static struct filestatoverride *
+statdb_node_new(const char *user, const char *group, const char *mode)
+{
+ struct filestatoverride *filestat;
+
+ filestat = nfmalloc(sizeof(*filestat));
+
+ filestat->uid = statdb_parse_uid(user);
+ filestat->gid = statdb_parse_gid(group);
+ filestat->mode = statdb_parse_mode(mode);
+
+ return filestat;
+}
+
+static struct filestatoverride **
+statdb_node_find(const char *filename)
+{
+ struct filenamenode *file;
+
+ file = findnamenode(filename, 0);
+
+ return &file->statoverride;
+}
+
+static int
+statdb_node_remove(const char *filename)
+{
+ struct filenamenode *file;
+
+ file = findnamenode(filename, fnn_nonew);
+ if (!file || (file && !file->statoverride))
+ return 0;
+
+ file->statoverride = NULL;
+
+ return 1;
+}
+
+static void
+statdb_node_apply(const char *filename, struct filestatoverride *filestat)
+{
+ if (access(filename, F_OK) != 0) {
+ warning(_("--update given but %s does not exist"), filename);
+ } else {
+ if (chown(filename, filestat->uid, filestat->gid) < 0)
+ warning(_("failed to chown %s: %s"), filename,
+ strerror(errno));
+ if (chmod(filename, filestat->mode))
+ warning(_("failed to chmod %s: %s"), filename,
+ strerror(errno));
+ }
+}
+
+static void
+statdb_node_print(FILE *out, struct filenamenode *file)
+{
+ struct filestatoverride *filestat = file->statoverride;
+ struct passwd *pw;
+ struct group *gr;
+
+ if (!filestat)
+ return;
+
+ pw = getpwuid(filestat->uid);
+ if (pw == NULL)
+ ohshite(_("error getting user name for uid %d"), filestat->uid);
+ gr = getgrgid(filestat->gid);
+ if (gr == NULL)
+ ohshite(_("error getting group name for gid %d"), filestat->gid);
+
+ fprintf(out, "%s %s %o %s\n", pw->pw_name, gr->gr_name, filestat->mode,
+ file->name);
+}
+
+static void
+statdb_write(void)
+{
+ FILE *dbfile;
+ struct fileiterator *i;
+ struct filenamenode *file;
+ struct varbuf dbname = VARBUF_INIT;
+ struct varbuf dbname_new = VARBUF_INIT;
+ struct varbuf dbname_old = VARBUF_INIT;
+
+ varbufaddstr(&dbname, admindir);
+ varbufaddstr(&dbname, "/" STATOVERRIDEFILE);
+ varbufaddc(&dbname, '\0');
+
+ varbufaddstr(&dbname_new, dbname.buf);
+ varbufaddstr(&dbname_new, NEWDBEXT);
+ varbufaddc(&dbname_new, '\0');
+
+ varbufaddstr(&dbname_old, dbname.buf);
+ varbufaddstr(&dbname_old, OLDDBEXT);
+ varbufaddc(&dbname_old, '\0');
+
+ dbfile = fopen(dbname_new.buf, "w");
+ if (!dbfile)
+ ohshite(_("cannot open new statoverride file"));
+
+ i = iterfilestart();
+ while ((file = iterfilenext(i)))
+ statdb_node_print(dbfile, file);
+ iterfileend(i);
+
+ fclose(dbfile);
+
+ chmod(dbname_new.buf, 0644);
+ if (unlink(dbname_old.buf) && errno != ENOENT)
+ ohshite(_("error removing statoverride-old"));
+ if (link(dbname.buf, dbname_old.buf) && errno != ENOENT)
+ ohshite(_("error creating new statoverride-old"));
+ if (rename(dbname_new.buf, dbname.buf))
+ ohshite(_("error installing new statoverride"));
+
+ varbuffree(&dbname);
+ varbuffree(&dbname_new);
+ varbuffree(&dbname_old);
+}
+
+static int
+statoverride_add(const char *const *argv)
+{
+ const char *user = argv[0];
+ const char *group = argv[1];
+ const char *mode = argv[2];
+ const char *path = argv[3];
+ char *filename;
+ struct filestatoverride **filestat;
+
+ if (!user || !group || !mode || !path || argv[4])
+ badusage(_("--add needs four arguments"));
+
+ if (strchr(path, '\n'))
+ badusage(_("file may not contain newlines"));
+
+ filename = path_cleanup(path);
+
+ filestat = statdb_node_find(filename);
+ if (*filestat == NULL) {
+ if (opt_force)
+ warning(_("An override for '%s' already exists, "
+ "but --force specified so will be ignored."),
+ filename);
+ else
+ ohshit(_("An override for '%s' already exists, "
+ "aborting."), filename);
+ }
+
+ *filestat = statdb_node_new(user, group, mode);
+
+ if (opt_update)
+ statdb_node_apply(filename, *filestat);
+
+ statdb_write();
+
+ free(filename);
+
+ return 0;
+}
+
+static int
+statoverride_remove(const char *const *argv)
+{
+ const char *path = argv[0];
+ char *filename;
+
+ if (!path || argv[1])
+ badusage(_("--%s needs a single argument"), "remove");
+
+ filename = path_cleanup(path);
+
+ if (!statdb_node_remove(filename)) {
+ warning(_("No override present."));
+ if (opt_force)
+ exit(0);
+ else
+ exit(2);
+ }
+
+ if (opt_update)
+ warning(_("--update is useless for --remove"));
+
+ statdb_write();
+
+ free(filename);
+
+ return 0;
+}
+
+struct glob_node {
+ struct glob_node *next;
+ char *pattern;
+};
+
+static void
+glob_list_prepend(struct glob_node **list, char *pattern)
+{
+ struct glob_node *node;
+
+ node = m_malloc(sizeof(*node));
+ node->pattern = pattern;
+ node->next = *list;
+ *list = node;
+}
+
+static void
+glob_list_free(struct glob_node *head)
+{
+ while (head) {
+ struct glob_node *node = head;
+
+ head = head->next;
+ free(node->pattern);
+ free(node);
+ }
+}
+
+static int
+statoverride_list(const char *const *argv)
+{
+ struct fileiterator *i;
+ struct filenamenode *file;
+ const char *thisarg;
+ struct glob_node *glob_list = NULL;
+ int ret = 1;
+
+ while ((thisarg = *argv++)) {
+ char *pattern = path_cleanup(thisarg);
+
+ glob_list_prepend(&glob_list, pattern);
+ }
+ if (glob_list == NULL)
+ glob_list_prepend(&glob_list, m_strdup("*"));
+
+ i = iterfilestart();
+ while ((file = iterfilenext(i))) {
+ struct glob_node *g;
+
+ for (g = glob_list; g; g = g->next) {
+ if (fnmatch(g->pattern, file->name, 0) == 0) {
+ statdb_node_print(stdout, file);
+ ret = 0;
+ break;
+ }
+ }
+ }
+ iterfileend(i);
+
+ glob_list_free(glob_list);
+
+ return ret;
+}
+
+#define ACTION(longopt, shortopt, code, function) \
+ { longopt, shortopt, 0, 0, 0, setaction, code, 0, (voidfnp)function }
+
+static const struct cmdinfo cmdinfos[] = {
+ ACTION("add", 'L', act_listfiles, statoverride_add),
+ ACTION("remove", 's', act_status, statoverride_remove),
+ ACTION("list", 'p', act_printavail, statoverride_list),
+
+ { "admindir", 0, 1, NULL, &admindir, NULL },
+ { "quiet", 0, 0, &opt_verbose, NULL, NULL },
+ { "force", 0, 0, &opt_force, NULL, NULL },
+ { "update", 0, 0, &opt_update, NULL, NULL },
+ { "help", 'h', 0, NULL, NULL, usage },
+ { "version", 0, 0, NULL, NULL, printversion },
+ /* UK spelling */
+ { "licence", 0, 0, NULL, NULL, showcopyright },
+ /* US spelling */
+ { "license", 0, 0, NULL, NULL, showcopyright },
+ { NULL, 0 }
+};
+
+int
+main(int argc, const char *const *argv)
+{
+ jmp_buf ejbuf;
+ static int (*actionfunction)(const char *const *argv);
+ int ret;
+
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+
+ standard_startup(&ejbuf);
+ myopt(&argv, cmdinfos);
+
+ if (!cipaction)
+ badusage(_("need an action option"));
+
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ filesdbinit();
+ ensure_statoverrides();
+
+ actionfunction = (int (*)(const char *const *))cipaction->farg;
+ ret = actionfunction(argv);
+
+ standard_shutdown();
+
+ return ret;
+}
+