initial checkin
authorEnrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
Wed, 18 Feb 2004 04:42:38 +0000 (04:42 +0000)
committerEnrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
Wed, 18 Feb 2004 04:42:38 +0000 (04:42 +0000)
git-svn-id: http://svn.linux-vserver.org/svn/util-vserver/trunk@934 94cd875c-1c1d-0410-91d2-eb244daf1a30

12 files changed:
util-vserver/lib/createskeleton-full.hc [new file with mode: 0644]
util-vserver/lib/createskeleton-short.hc [new file with mode: 0644]
util-vserver/lib/createskeleton.c [new file with mode: 0644]
util-vserver/lib_internal/matchlist-printid.c [new file with mode: 0644]
util-vserver/lib_internal/unify-copy.c [new file with mode: 0644]
util-vserver/lib_internal/unify-settime.c [new file with mode: 0644]
util-vserver/lib_internal/util-dotfile.h [new file with mode: 0644]
util-vserver/lib_internal/util-safechdir.c [new file with mode: 0644]
util-vserver/lib_internal/util-safechdir.h [new file with mode: 0644]
util-vserver/src/vcopy-init.hc [new file with mode: 0644]
util-vserver/src/vcopy.c [new file with mode: 0644]
util-vserver/src/vserver-visitdir.hc [new file with mode: 0644]

diff --git a/util-vserver/lib/createskeleton-full.hc b/util-vserver/lib/createskeleton-full.hc
new file mode 100644 (file)
index 0000000..0b46186
--- /dev/null
@@ -0,0 +1,130 @@
+// $Id$    --*- c -*--
+
+// Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// This program 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; version 2 of the License.
+//  
+// This program 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 this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#define CONCAT_TWO_ARGS(BUF, LHS,RHS)                  \
+  size_t               BUF ## l1 = strlen(LHS);        \
+  size_t               BUF ## l2 = strlen(RHS);        \
+  char                 BUF[BUF ## l1 + BUF ## l2 + 2]; \
+                                                       \
+  memcpy(BUF,      LHS, BUF ## l1 + 1);                        \
+  if (BUF ## l2>0) {                                   \
+    memcpy(BUF+BUF ## l1,   "/", BUF ## l1);           \
+    memcpy(BUF+BUF ## l1+1, RHS, BUF ## l2+1);         \
+  }
+
+static inline int
+mkdir2(char const *lhs, char const *rhs, int mode)
+{
+  CONCAT_TWO_ARGS(buf, lhs, rhs);
+  return mkdir(buf, mode);
+}
+
+static inline int
+setIAttr2(char const *lhs, char const *rhs, int flags)
+{
+  struct stat          st;
+  CONCAT_TWO_ARGS(buf, lhs, rhs);
+
+  if (stat(buf, &st)==-1) return -1;
+  return vc_set_iattr_compat(buf, st.st_dev, st.st_ino,
+                            0, flags, VC_IMMUTABLE_ALL, 0);
+}
+
+static inline int
+symlink2(char const *old_lhs, char const *old_rhs,
+        char const *new_lhs, char const *new_rhs)
+{
+  CONCAT_TWO_ARGS(old_buf, old_lhs, old_rhs);
+
+  {
+    CONCAT_TWO_ARGS(new_buf, new_lhs, new_rhs);
+    return symlink(old_buf, new_buf);
+  }
+}
+
+#undef CONCAT_TWO_ARGS
+
+static inline int
+vc_createSkeleton_full(char const *id, char const *name, int flags)
+{
+  if (mkdir(id, 0755)==-1) return -1;
+
+  if (mkdir2(id, "apps", 0755)==-1 ||
+      ((flags&vcSKEL_INTERFACES) && mkdir2(id, "interfaces", 755)==-1) ||
+      ((flags&vcSKEL_PKGMGMT) && (
+       mkdir2(id, "apps/pkgmgmt", 0755)==-1)))
+    return -1;
+
+  for (;;) {
+    char const *basedir = CONFDIR "/.defaults/run.rev";
+
+    if (!utilvserver_isDirectory(basedir, true)) basedir = DEFAULT_PKGSTATEREVDIR;
+    if (!utilvserver_isDirectory(basedir, true)) break;
+
+    if (symlink2(basedir, "", id, "run.rev")==-1)
+      return -1;
+
+    break;
+  }
+
+  for (;;) {
+    char const *basedir = CONFDIR "/.defaults/run";
+
+    if (!utilvserver_isDirectory(basedir, true)) basedir = DEFAULT_PKGSTATEDIR;
+    if (!utilvserver_isDirectory(basedir, true)) break;
+
+    if (symlink2(basedir, name, id, "run")==-1)
+      return -1;
+
+    break;
+  }
+  
+  while (flags&vcSKEL_PKGMGMT) {
+    char const *basedir = CONFDIR "/.defaults/apps/pkgmgmt/base";
+
+    if (!utilvserver_isDirectory(basedir, true)) basedir = DEFAULT_VSERVERPKGDIR;
+    if (!utilvserver_isDirectory(basedir, true)) break;
+
+    if (mkdir2(basedir, name, 0755)==-1 ||
+       symlink2(basedir, name, id, "apps/pkgmgmt/base")==-1)
+      return -1;
+
+    break;
+  }
+
+  while (flags&vcSKEL_FILESYSTEM) {
+    char const *basedir = CONFDIR "/.defaults/vdirbase";
+
+    if (!utilvserver_isDirectory(basedir, true)) basedir = DEFAULT_VSERVERDIR;
+    if (!utilvserver_isDirectory(basedir, true)) break;
+
+    if (mkdir2(basedir, name, 0755)==-1 ||
+       setIAttr2(basedir, name, 0)==-1 ||
+       symlink2(basedir, name, id, "vdir")==-1)
+      return -1;
+
+    break;
+  }
+
+  return 0;
+}
diff --git a/util-vserver/lib/createskeleton-short.hc b/util-vserver/lib/createskeleton-short.hc
new file mode 100644 (file)
index 0000000..0397913
--- /dev/null
@@ -0,0 +1,31 @@
+// $Id$    --*- c -*--
+
+// Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// This program 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; version 2 of the License.
+//  
+// This program 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 this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include <stdlib.h>
+#include <string.h>
+
+static inline int
+vc_createSkeleton_short(char const *id, int flags)
+{
+  size_t       l = strlen(id);
+  char         buf[sizeof(CONFDIR "/") + l];
+
+  memcpy(buf, CONFDIR "/", sizeof(CONFDIR "/")-1);
+  memcpy(buf+sizeof(CONFDIR "/")-1, id, l+1);
+  
+  return vc_createSkeleton_full(buf, id, flags);
+}
diff --git a/util-vserver/lib/createskeleton.c b/util-vserver/lib/createskeleton.c
new file mode 100644 (file)
index 0000000..528f2e7
--- /dev/null
@@ -0,0 +1,49 @@
+// $Id$    --*- c -*--
+
+// Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// This program 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; version 2 of the License.
+//  
+// This program 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 this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "vserver.h"
+#include "internal.h"
+
+#include "pathconfig.h"
+
+#include "createskeleton-full.hc"
+#include "createskeleton-short.hc"
+
+#include <errno.h>
+
+int
+vc_createSkeleton(char const *id, vcCfgStyle style, int flags)
+{
+  if (style==vcCFG_NONE || style==vcCFG_AUTO) {
+    if (strchr(id, '/')!=0) style = vcCFG_RECENT_FULL;
+    else                    style = vcCFG_RECENT_SHORT;
+  }
+  
+  switch (style) {
+    case vcCFG_RECENT_SHORT    :  return vc_createSkeleton_short(id, flags);
+    case vcCFG_RECENT_FULL     :  return vc_createSkeleton_full(id, 0, flags);
+    default                    :  ;
+  }
+  
+  errno = EINVAL;
+  return -1;
+}
diff --git a/util-vserver/lib_internal/matchlist-printid.c b/util-vserver/lib_internal/matchlist-printid.c
new file mode 100644 (file)
index 0000000..36b0742
--- /dev/null
@@ -0,0 +1,39 @@
+// $Id$    --*- c -*--
+
+// Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// This program 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; version 2 of the License.
+//  
+// This program 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 this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "matchlist.h"
+#include "util-io.h"
+
+void
+MatchList_printId(struct MatchList const *l, int fd)
+{
+  if (l->id.l>0) {
+    WRITE_MSG(fd, "'");
+    (void)write(fd, l->id.d, l->id.l);
+    WRITE_MSG(1, "'");
+  }
+  else if (l->root.l>0) {
+    write(fd, l->root.d, l->root.l);
+  }
+  else
+    WRITE_MSG(fd, "???");
+}
diff --git a/util-vserver/lib_internal/unify-copy.c b/util-vserver/lib_internal/unify-copy.c
new file mode 100644 (file)
index 0000000..c67b48e
--- /dev/null
@@ -0,0 +1,130 @@
+// $Id$    --*- c -*--
+
+// Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// This program 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; version 2 of the License.
+//  
+// This program 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 this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "unify.h"
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#define ENSC_WRAPPERS_IO       1
+#include <wrappers.h>
+
+static inline bool
+verifySource(int fd, struct stat const *exp_stat)
+{
+  struct stat          st;
+  
+  return (fstat(fd, &st)!=-1 &&
+         st.st_dev==exp_stat->st_dev &&
+         st.st_ino==exp_stat->st_ino);
+}
+
+static inline bool
+copyLnk(char const *src, char const *dst)
+{
+  ssize_t      len = 1024;
+  for (;;) {
+    char       buf[len];
+    ssize_t    l;
+    l = readlink(src, buf, len-1);
+    if (l==-1) return false;
+    if (l>=len-1) {
+      len *= 2;
+      continue;
+    }
+    buf[l] = '\0';
+
+    return (symlink(buf, dst)!=-1);
+  }
+}
+
+static inline bool
+copyReg(char const *src, struct stat const *src_stat,
+       char const *dst)
+{
+  int          in_fd  = open(src, O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_LARGEFILE);
+  int          out_fd = in_fd==-1 ? -1 : open(dst, O_CREAT|O_EXCL, 0200);
+  bool         res    = false;
+  
+  if (in_fd==-1 || out_fd==-1 ||
+      !verifySource(in_fd, src_stat)) goto err;
+
+  for (;;) {
+    char       buf[2048];
+    ssize_t    l = read(in_fd, buf, sizeof buf);
+    if (l==-1) goto err;
+    if (l==0)  break;
+    if (!WwriteAll(out_fd, buf, l, 0)) return false;
+  }
+
+  res = true;
+  
+  err:
+  if (out_fd!=-1 && close(out_fd)==-1) res=false;
+  if (in_fd!=-1  && close(in_fd)==-1)  res=false;
+  return res;
+}
+
+static inline bool
+copyNode(char const UNUSED *src, struct stat const *src_stat,
+        char const *dst)
+{
+  return mknod(dst, src_stat->st_mode & (S_IFMT|S_IWUSR),
+              src_stat->st_rdev)!=-1;
+}
+
+static inline bool
+copyDir(char const UNUSED *src, struct stat const UNUSED *src_stat,
+       char const *dst)
+{
+  return mkdir(dst, 0700)!=-1;
+}
+
+static inline bool
+setModes(char const *path, struct stat const *st)
+{
+  return (lchown(path, st->st_uid, st->st_gid)!=-1 &&
+         (S_ISLNK(st->st_mode) || chmod(path, st->st_mode)!=-1));
+}
+
+
+bool
+Unify_copy(char const *src, struct stat const *src_stat,
+          char const *dst)
+{
+  // skip sockets
+  // TODO: message
+  if (S_ISSOCK(src_stat->st_mode))
+    return true;
+  
+  return
+    (((S_ISLNK (src_stat->st_mode) && copyLnk (src, dst)) ||
+      (S_ISREG (src_stat->st_mode) && copyReg (src, src_stat, dst)) ||
+      (S_ISDIR (src_stat->st_mode) && copyDir (src, src_stat, dst)) ||
+      ((S_ISBLK (src_stat->st_mode) ||
+       S_ISCHR (src_stat->st_mode) || 
+       S_ISFIFO(src_stat->st_mode)) && copyNode(src, src_stat, dst))
+      ) &&
+     setModes(dst, src_stat) &&
+     Unify_setTime(dst, src_stat));
+}
diff --git a/util-vserver/lib_internal/unify-settime.c b/util-vserver/lib_internal/unify-settime.c
new file mode 100644 (file)
index 0000000..9494dbd
--- /dev/null
@@ -0,0 +1,36 @@
+// $Id$    --*- c -*--
+
+// Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// This program 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; version 2 of the License.
+//  
+// This program 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 this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "unify.h"
+#include <utime.h>
+#include <sys/stat.h>
+
+bool
+Unify_setTime(char const *dst, struct stat const *st)
+{
+  struct utimbuf       utm;
+
+  utm.actime  = st->st_atime;
+  utm.modtime = st->st_mtime;
+  return utime(dst, &utm)!=-1;
+}
+
diff --git a/util-vserver/lib_internal/util-dotfile.h b/util-vserver/lib_internal/util-dotfile.h
new file mode 100644 (file)
index 0000000..41ed67d
--- /dev/null
@@ -0,0 +1,30 @@
+// $Id$    --*- c -*--
+
+// Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// This program 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; version 2 of the License.
+//  
+// This program 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 this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+#ifndef H_UTIL_VSERVER_LIB_INTERNAL_UTIL_DOTFILE_H
+#define H_UTIL_VSERVER_LIB_INTERNAL_UTIL_DOTFILE_H
+
+#include <stdbool.h>
+
+static inline UNUSED ALWAYSINLINE bool
+isDotfile(char const *d) PURE
+{
+  return d[0]=='.' && (d[1]=='\0' || (d[1]=='.' && d[2]=='\0'));
+}
+
+#endif //  H_UTIL_VSERVER_LIB_INTERNAL_UTIL_DOTFILE_H
diff --git a/util-vserver/lib_internal/util-safechdir.c b/util-vserver/lib_internal/util-safechdir.c
new file mode 100644 (file)
index 0000000..1abbb45
--- /dev/null
@@ -0,0 +1,49 @@
+// $Id$    --*- c -*--
+
+// Copyright (C) 2003 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// This program 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; version 2 of the License.
+//  
+// This program 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 this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+int
+safeChdir(char const *path, struct stat const *exp_stat)
+{
+  if (strchr(path, '/')!=0) {
+    errno = EINVAL;
+    return -1;
+  }
+
+  {
+    struct stat                now_stat;
+    if (chdir(path)==-1 ||
+       stat(".", &now_stat)==-1) return -1;
+    if (exp_stat->st_dev != now_stat.st_dev ||
+       exp_stat->st_ino != now_stat.st_ino) {
+      // TODO: warning/logging
+      errno = EINVAL;
+      return -1;
+    }
+  }
+
+  return 0;
+}
diff --git a/util-vserver/lib_internal/util-safechdir.h b/util-vserver/lib_internal/util-safechdir.h
new file mode 100644 (file)
index 0000000..656953d
--- /dev/null
@@ -0,0 +1,28 @@
+// $Id$    --*- c -*--
+
+// Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// This program 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; version 2 of the License.
+//  
+// This program 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 this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+#ifndef H_UTIL_VSERVER_LIB_INTERNAL_UTIL_SAFECHDIR_H
+#define H_UTIL_VSERVER_LIB_INTERNAL_UTIL_SAFECHDIR_H
+
+struct stat;
+int    safeChdir(char const *, struct stat const *exp_stat) NONNULL((1,2));
+
+#define EsafeChdir(PATH,EXP_STAT) \
+  FatalErrnoError(safeChdir(PATH,EXP_STAT)==-1, "safeChdir()")
+
+#endif //  H_UTIL_VSERVER_LIB_INTERNAL_UTIL_SAFECHDIR_H
diff --git a/util-vserver/src/vcopy-init.hc b/util-vserver/src/vcopy-init.hc
new file mode 100644 (file)
index 0000000..ace737e
--- /dev/null
@@ -0,0 +1,90 @@
+// $Id$    --*- c -*--
+
+// Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// This program 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; version 2 of the License.
+//  
+// This program 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 this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+static void
+createSkeleton(char const *name)
+{
+  char const * app_dir;
+
+  app_dir = vc_getVserverAppDir(name, vcCFG_AUTO, "vunify");
+  if (app_dir==0 &&
+      vc_createSkeleton(name, vcCFG_AUTO, vcSKEL_FILESYSTEM|vcSKEL_PKGMGMT)==-1) {
+    perror("vc_createSkeleton()");
+    exit(1);
+  }
+
+  if (app_dir==0) {
+    app_dir = vc_getVserverAppDir(name, vcCFG_AUTO, "");
+      
+    PathInfo           path = {
+      .d = app_dir,
+      .l = strlen(app_dir),
+    };
+    PathInfo           rhs_path = {
+      .d = "vunify",
+      .l = sizeof("vunify")-1
+    };
+      
+    char               p_buf[ENSC_PI_APPSZ(path, rhs_path)];
+    PathInfo_append(&path, &rhs_path, p_buf);
+
+    Emkdir(path.d, 0755);
+  }
+
+  free(const_cast(char *)(app_dir));
+}
+
+
+static void
+initModeManually(int argc, char *argv[])
+{
+  int          count=argc/2;
+
+  if (count!=2) {
+    WRITE_MSG(2, "Bad arguments; try '--help' for more information\n");
+    exit(1);
+  }
+
+  MatchList_initManually(&global_info.dst_list, 0, strdup(argv[0]), argv[1]);
+  MatchList_initManually(&global_info.src_list, 0, strdup(argv[2]), argv[3]);
+}
+
+
+static void
+initModeVserver(int argc, char *argv[])
+{
+  int          count=argc;
+
+  if (count!=2) {
+    WRITE_MSG(2, "Bad arguments; try '--help' for more information\n");
+    exit(1);
+  }
+
+  if (!MatchList_initByVserver(&global_info.src_list, argv[1], 0)) {
+    WRITE_MSG(2, "unification not configured for source vserver\n");
+    exit(1);
+  }
+
+  if (!global_args->is_strict)
+    createSkeleton(argv[0]);
+
+  if (!MatchList_initByVserver(&global_info.dst_list, argv[0], 0)) {
+    WRITE_MSG(2, "unification not configured for destination vserver\n");
+    exit(1);
+  }
+}
diff --git a/util-vserver/src/vcopy.c b/util-vserver/src/vcopy.c
new file mode 100644 (file)
index 0000000..295e94b
--- /dev/null
@@ -0,0 +1,268 @@
+// $Id$    --*- c -*--
+
+// Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// This program 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; version 2 of the License.
+//  
+// This program 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 this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include "util.h"
+#include "vserver.h"
+
+#include "lib_internal/matchlist.h"
+#include "lib_internal/unify.h"
+
+#include <unistd.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <assert.h>
+#include <utime.h>
+#include <libgen.h>
+
+#define ENSC_WRAPPERS_UNISTD   1
+#define ENSC_WRAPPERS_FCNTL    1
+#define ENSC_WRAPPERS_DIRENT   1
+#include <wrappers.h>
+
+#define CMD_HELP               0x8000
+#define CMD_VERSION            0x8001
+#define CMD_MANUALLY           0x8002
+#define CMD_STRICT             0x8003
+
+struct WalkdownInfo
+{
+    PathInfo                           state;
+    struct MatchList                   dst_list;
+    struct MatchList                   src_list;
+};
+
+struct Arguments {
+    enum {mdMANUALLY, mdVSERVER}       mode;
+    bool                               do_dry_run;
+    unsigned int                       verbosity;
+    bool                               local_fs;
+    bool                               is_strict;
+};
+
+static struct WalkdownInfo             global_info;
+static struct Arguments const *                global_args;
+
+int wrapper_exit_code = 1;
+
+struct option const
+CMDLINE_OPTIONS[] = {
+  { "help",     no_argument,  0, CMD_HELP },
+  { "version",  no_argument,  0, CMD_VERSION },
+  { "manually", no_argument,  0, CMD_MANUALLY },
+  { "strict",   no_argument,  0, CMD_STRICT },
+  { 0,0,0,0 }
+};
+
+typedef enum { opUNIFY, opCOPY, opDIR, opSKIP }        Operation;
+
+static void
+showHelp(int fd, char const *cmd, int res)
+{
+  VSERVER_DECLARE_CMD(cmd);
+  
+  WRITE_MSG(fd, "Usage:\n  ");
+  WRITE_STR(fd, cmd);
+  WRITE_MSG(fd,
+           " [-nv] [--strict] <dst-vserver> <src-vserver>\n    or\n  ");
+  WRITE_STR(fd, cmd);
+  WRITE_MSG(fd,
+           " --manually [-nvx] [--] <dst-path> <dst-excludelist> <src-path> <src-excludelist>\n\n"
+           "  --manually      ...  unify generic paths; excludelists must be generated\n"
+           "                       manually\n"
+           "  --strict        ...  require an existing vserver configuration for dst-vserver;\n"
+           "                       by default, a base skeleton will be created but manual\n"
+           "                       configuration wil be still needed to make the new vserver work\n"
+           "  -n              ...  do not modify anything; just show what there will be\n"
+           "                       done (in combination with '-v')\n"
+           "  -v              ...  verbose mode\n"
+           "  -x              ...  do not cross filesystems; this is valid in manual\n"
+           "                       mode only and will be ignored for vserver unification\n\n"
+           "Please report bugs to " PACKAGE_BUGREPORT "\n");
+  exit(res);
+}
+
+static void
+showVersion()
+{
+  WRITE_MSG(1,
+           "vcopy " VERSION " -- copies directories and vserver files\n"
+           "This program is part of " PACKAGE_STRING "\n\n"
+           "Copyright (C) 2003,2004 Enrico Scholz\n"
+           VERSION_COPYRIGHT_DISCLAIMER);
+  exit(0);
+}
+
+int Global_getVerbosity() {
+  return global_args->verbosity;
+}
+
+bool Global_doRenew() {
+  return true;
+}
+
+#include "vserver-visitdir.hc"
+
+static Operation
+checkDirEntry(PathInfo const *path, struct stat const *st)
+{
+  struct WalkdownInfo const * const    info     = &global_info;
+
+  if (S_ISDIR(st->st_mode)) return opDIR;
+  if (S_ISLNK(st->st_mode) ||
+      !S_ISREG(st->st_mode)) return opSKIP;
+  
+    // Check if it is in the exclude/include list of the destination vserver and
+    // abort when it is not matching an allowed entry
+  if (!MatchList_compare(&info->dst_list, path->d) ||
+      !MatchList_compare(&info->src_list, path->d)) return opCOPY;
+
+  return opUNIFY;
+}
+
+static bool
+doit(Operation op,
+     PathInfo const *dst_path,
+     PathInfo const *src_path, struct stat const *exp_stat,
+     PathInfo const *show_path)
+{
+  if (global_args->do_dry_run || global_args->verbosity>0) {
+    if      (op==opUNIFY)   WRITE_MSG(1, "linking  '");
+    else if (op==opCOPY)    WRITE_MSG(1, "copying  '");
+    else if (op==opDIR)     WRITE_MSG(1, "creating '");
+    else if (op==opSKIP)    WRITE_MSG(1, "skipping '");
+    else { assert(false); abort(); }
+
+    write(1, show_path->d, show_path->l);
+    WRITE_MSG(1, "'\n");
+  }
+
+  return (global_args->do_dry_run ||
+         ( op==opSKIP) ||
+         ( op==opUNIFY && Unify_unify(src_path->d, exp_stat, dst_path->d)) ||
+         ((op==opCOPY  ||
+           op==opDIR)  && Unify_copy (src_path->d, exp_stat, dst_path->d)));
+}
+     
+static uint64_t
+visitDirEntry(struct dirent const *ent)
+{
+  char const *                 dirname  = ent->d_name;
+  if (isDotfile(dirname)) return 0;
+
+  uint64_t                     res      = 1;
+  PathInfo                     src_path = global_info.state;
+  PathInfo                     src_d_path = {
+    .d = dirname,
+    .l = strlen(dirname)
+  };
+  char                         path_buf[ENSC_PI_APPSZ(src_path, src_d_path)];
+  struct stat                  f_stat = { .st_dev = 0 };
+
+  PathInfo_append(&src_path, &src_d_path, path_buf);
+
+  
+  if (lstat(dirname, &f_stat)==-1)
+    perror("lstat()");
+  else {
+    Operation          op       = checkDirEntry(&src_path, &f_stat);
+    PathInfo           dst_path = global_info.src_list.root;
+    char               dst_path_buf[ENSC_PI_APPSZ(dst_path, src_path)];
+
+    PathInfo_append(&dst_path, &src_path, dst_path_buf);
+    if (!doit(op, &dst_path, &src_d_path, &f_stat, &src_path))
+      perror(src_path.d);
+    else if (op==opDIR) {
+      res = visitDir(dirname, &f_stat);
+      if (!global_args->do_dry_run &&
+         !Unify_setTime(dst_path.d, &f_stat))
+       perror("utime()");
+    }
+    else
+      res = 0;
+  }
+
+  return res;
+}
+
+#include "vcopy-init.hc"
+
+int main(int argc, char *argv[])
+{
+  struct Arguments     args = {
+    .mode              =  mdVSERVER,
+    .do_dry_run                =  false,
+    .verbosity         =  0,
+    .local_fs          =  false,
+  };
+  uint64_t             res;
+
+  global_args = &args;
+  while (1) {
+    int                c = getopt_long(argc, argv, "nvcx",
+                               CMDLINE_OPTIONS, 0);
+    if (c==-1) break;
+
+    switch (c) {
+      case CMD_HELP            :  showHelp(1, argv[0], 0);
+      case CMD_VERSION         :  showVersion();
+      case CMD_MANUALLY                :  args.mode       = mdMANUALLY; break;
+      case CMD_STRICT          :  args.is_strict  = true; break;
+      case 'n'                 :  args.do_dry_run = true; break;
+      case 'x'                 :  args.local_fs   = true; break;
+      case 'v'                 :  ++args.verbosity;       break;
+      default          :
+       WRITE_MSG(2, "Try '");
+       WRITE_STR(2, argv[0]);
+       WRITE_MSG(2, " --help\" for more information.\n");
+       return EXIT_FAILURE;
+       break;
+    }
+  }
+
+  if (argc==optind) {
+    WRITE_MSG(2, "No directory/vserver given\n");
+    return EXIT_FAILURE;
+  }
+
+  switch (args.mode) {
+    case mdMANUALLY    :  initModeManually(argc-optind, argv+optind); break;
+    case mdVSERVER     :  initModeVserver (argc-optind, argv+optind); break;
+    default            :  assert(false); return EXIT_FAILURE;
+  }
+
+  if (global_args->verbosity>3)
+    WRITE_MSG(1, "Starting to traverse directories...\n");
+
+  Echdir(global_info.src_list.root.d);
+  res = visitDir("/", 0);
+  
+#ifndef NDEBUG
+  {
+    MatchList_destroy(&global_info.dst_list);
+    MatchList_destroy(&global_info.src_list);
+  }
+#endif
+
+  return res>0 ? 1 : 0;
+}
diff --git a/util-vserver/src/vserver-visitdir.hc b/util-vserver/src/vserver-visitdir.hc
new file mode 100644 (file)
index 0000000..3046bb9
--- /dev/null
@@ -0,0 +1,56 @@
+// $Id$    --*- c -*--
+
+// Copyright (C) 2004 Enrico Scholz <enrico.scholz@informatik.tu-chemnitz.de>
+//  
+// This program 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; version 2 of the License.
+//  
+// This program 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 this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+static uint64_t
+visitDirEntry(struct dirent const *ent);
+
+static uint64_t
+visitDir(char const *name, struct stat const *expected_stat)
+{
+  int          fd = Eopen(".", O_RDONLY, 0);
+  PathInfo     old_state = global_info.state;
+  PathInfo     rhs_path = {
+    .d = name,
+    .l = strlen(name)
+  };
+  char         new_path[ENSC_PI_APPSZ(global_info.state, rhs_path)];
+  DIR *                dir;
+  uint64_t     res = 0;
+
+  PathInfo_append(&global_info.state, &rhs_path, new_path);
+
+  if (expected_stat!=0)
+    EsafeChdir(name, expected_stat);
+  
+  dir = Eopendir(".");
+
+  for (;;) {
+    struct dirent              *ent = Ereaddir(dir);
+    if (ent==0) break;
+
+    res += visitDirEntry(ent);
+  }
+
+  Eclosedir(dir);
+
+  Efchdir(fd);
+  Eclose(fd);
+
+  global_info.state = old_state;
+  return res;
+}