From 9f52547ae6ad8bde3d17856480453498e4bd0ab1 Mon Sep 17 00:00:00 2001 From: Enrico Scholz Date: Wed, 18 Feb 2004 04:42:38 +0000 Subject: [PATCH] initial checkin git-svn-id: http://svn.linux-vserver.org/svn/util-vserver/trunk@934 94cd875c-1c1d-0410-91d2-eb244daf1a30 --- util-vserver/lib/createskeleton-full.hc | 130 +++++++++++++ util-vserver/lib/createskeleton-short.hc | 31 +++ util-vserver/lib/createskeleton.c | 49 +++++ util-vserver/lib_internal/matchlist-printid.c | 39 ++++ util-vserver/lib_internal/unify-copy.c | 130 +++++++++++++ util-vserver/lib_internal/unify-settime.c | 36 ++++ util-vserver/lib_internal/util-dotfile.h | 30 +++ util-vserver/lib_internal/util-safechdir.c | 49 +++++ util-vserver/lib_internal/util-safechdir.h | 28 +++ util-vserver/src/vcopy-init.hc | 90 +++++++++ util-vserver/src/vcopy.c | 268 ++++++++++++++++++++++++++ util-vserver/src/vserver-visitdir.hc | 56 ++++++ 12 files changed, 936 insertions(+) create mode 100644 util-vserver/lib/createskeleton-full.hc create mode 100644 util-vserver/lib/createskeleton-short.hc create mode 100644 util-vserver/lib/createskeleton.c create mode 100644 util-vserver/lib_internal/matchlist-printid.c create mode 100644 util-vserver/lib_internal/unify-copy.c create mode 100644 util-vserver/lib_internal/unify-settime.c create mode 100644 util-vserver/lib_internal/util-dotfile.h create mode 100644 util-vserver/lib_internal/util-safechdir.c create mode 100644 util-vserver/lib_internal/util-safechdir.h create mode 100644 util-vserver/src/vcopy-init.hc create mode 100644 util-vserver/src/vcopy.c create mode 100644 util-vserver/src/vserver-visitdir.hc diff --git a/util-vserver/lib/createskeleton-full.hc b/util-vserver/lib/createskeleton-full.hc new file mode 100644 index 0000000..0b46186 --- /dev/null +++ b/util-vserver/lib/createskeleton-full.hc @@ -0,0 +1,130 @@ +// $Id$ --*- c -*-- + +// Copyright (C) 2004 Enrico Scholz +// +// 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 +#include +#include +#include +#include + +#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 index 0000000..0397913 --- /dev/null +++ b/util-vserver/lib/createskeleton-short.hc @@ -0,0 +1,31 @@ +// $Id$ --*- c -*-- + +// Copyright (C) 2004 Enrico Scholz +// +// 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 +#include + +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 index 0000000..528f2e7 --- /dev/null +++ b/util-vserver/lib/createskeleton.c @@ -0,0 +1,49 @@ +// $Id$ --*- c -*-- + +// Copyright (C) 2004 Enrico Scholz +// +// 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 +#endif + +#include "vserver.h" +#include "internal.h" + +#include "pathconfig.h" + +#include "createskeleton-full.hc" +#include "createskeleton-short.hc" + +#include + +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 index 0000000..36b0742 --- /dev/null +++ b/util-vserver/lib_internal/matchlist-printid.c @@ -0,0 +1,39 @@ +// $Id$ --*- c -*-- + +// Copyright (C) 2004 Enrico Scholz +// +// 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 +#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 index 0000000..c67b48e --- /dev/null +++ b/util-vserver/lib_internal/unify-copy.c @@ -0,0 +1,130 @@ +// $Id$ --*- c -*-- + +// Copyright (C) 2004 Enrico Scholz +// +// 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 +#endif + +#include "unify.h" +#include +#include +#include +#include + +#define ENSC_WRAPPERS_IO 1 +#include + +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 index 0000000..9494dbd --- /dev/null +++ b/util-vserver/lib_internal/unify-settime.c @@ -0,0 +1,36 @@ +// $Id$ --*- c -*-- + +// Copyright (C) 2004 Enrico Scholz +// +// 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 +#endif + +#include "unify.h" +#include +#include + +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 index 0000000..41ed67d --- /dev/null +++ b/util-vserver/lib_internal/util-dotfile.h @@ -0,0 +1,30 @@ +// $Id$ --*- c -*-- + +// Copyright (C) 2004 Enrico Scholz +// +// 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 + +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 index 0000000..1abbb45 --- /dev/null +++ b/util-vserver/lib_internal/util-safechdir.c @@ -0,0 +1,49 @@ +// $Id$ --*- c -*-- + +// Copyright (C) 2003 Enrico Scholz +// +// 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 +#endif + +#include +#include +#include +#include + +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 index 0000000..656953d --- /dev/null +++ b/util-vserver/lib_internal/util-safechdir.h @@ -0,0 +1,28 @@ +// $Id$ --*- c -*-- + +// Copyright (C) 2004 Enrico Scholz +// +// 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 index 0000000..ace737e --- /dev/null +++ b/util-vserver/src/vcopy-init.hc @@ -0,0 +1,90 @@ +// $Id$ --*- c -*-- + +// Copyright (C) 2004 Enrico Scholz +// +// 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 index 0000000..295e94b --- /dev/null +++ b/util-vserver/src/vcopy.c @@ -0,0 +1,268 @@ +// $Id$ --*- c -*-- + +// Copyright (C) 2004 Enrico Scholz +// +// 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 +#endif + +#include "util.h" +#include "vserver.h" + +#include "lib_internal/matchlist.h" +#include "lib_internal/unify.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define ENSC_WRAPPERS_UNISTD 1 +#define ENSC_WRAPPERS_FCNTL 1 +#define ENSC_WRAPPERS_DIRENT 1 +#include + +#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] \n or\n "); + WRITE_STR(fd, cmd); + WRITE_MSG(fd, + " --manually [-nvx] [--] \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 index 0000000..3046bb9 --- /dev/null +++ b/util-vserver/src/vserver-visitdir.hc @@ -0,0 +1,56 @@ +// $Id$ --*- c -*-- + +// Copyright (C) 2004 Enrico Scholz +// +// 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; +} -- 1.8.1.5