From: Enrico Scholz Date: Fri, 26 Dec 2003 00:42:10 +0000 (+0000) Subject: initial checkin X-Git-Tag: VERSION_0_10~1027 X-Git-Url: http://git.linux-vserver.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c3fec66a494a6b744a706700859b826da2f8bc4d;p=util-vserver.git initial checkin git-svn-id: http://svn.linux-vserver.org/svn/util-vserver/trunk@488 94cd875c-1c1d-0410-91d2-eb244daf1a30 --- diff --git a/util-vserver/src/exec-cd.c b/util-vserver/src/exec-cd.c new file mode 100644 index 0000000..2222d69 --- /dev/null +++ b/util-vserver/src/exec-cd.c @@ -0,0 +1,81 @@ +// $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 "util.h" +#include "wrappers.h" + +int wrapper_exit_code = 255; + +static void +showHelp(int fd, char const *cmd, int res) +{ + WRITE_MSG(fd, "Usage: "); + WRITE_STR(fd, cmd); + WRITE_MSG(fd, + "[--] *\n\n" + "Please report bugs to " PACKAGE_BUGREPORT "\n"); + exit(res); +} + +static void +showVersion() +{ + WRITE_MSG(1, + "exec-cd " VERSION " -- executes commands within a safely changed cwd\n" + "This program is part of " PACKAGE_STRING "\n\n" + "Copyright (C) 2003 Enrico Scholz\n" + VERSION_COPYRIGHT_DISCLAIMER); + exit(0); +} + +int main(int argc, char *argv[]) +{ + int dirfd_root = Eopen("/", O_RDONLY, 0); + int idx = 1; + + if (argc>=2) { + if (strcmp(argv[1], "--help") ==0) showHelp(1, argv[0], 0); + if (strcmp(argv[1], "--version")==0) showVersion(); + if (strcmp(argv[1], "--") ==0) ++idx; + } + + if (argc +// +// 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 "internal.h" +#include "vserver.h" +#include "util.h" +#include "wrappers.h" +#include "wrappers-vserver.h" + +#include +#include +#include +#include +#include + +#define MAX_RQSIZE 0x1000 + +int wrapper_exit_code = 1; + +struct ArgInfo { + ctx_t ctx; + uid_t uid; + gid_t gid; + bool do_fork; + char const * pid_file; + char const * chroot; +}; + +static struct option const +CMDLINE_OPTIONS[] = { + { "help", no_argument, 0, 'h' }, + { "version", no_argument, 0, 'v' }, + { 0,0,0,0 } +}; + +static void +showHelp(int fd, char const *cmd, int res) +{ + WRITE_MSG(fd, "Usage: "); + WRITE_STR(fd, cmd); + WRITE_MSG(fd, + " [-c ] [-u ] [-g ] [-r ] [-n]\n" + "Please report bugs to " PACKAGE_BUGREPORT "\n"); + exit(res); +} + +static void +showVersion() +{ + WRITE_MSG(1, + "rpm-fake-resolver " VERSION " -- NSS resovler for rpm-fake\n" + "This program is part of " PACKAGE_STRING "\n\n" + "Copyright (C) 2003 Enrico Scholz\n" + VERSION_COPYRIGHT_DISCLAIMER); + exit(0); +} + + +inline static void +parseArgs(struct ArgInfo *args, int argc, char *argv[]) +{ + while (1) { + int c = getopt_long(argc, argv, "c:u:g:r:n", CMDLINE_OPTIONS, 0); + if (c==-1) break; + + switch (c) { + case 'h' : showHelp(1, argv[0], 0); + case 'v' : showVersion(); + + case 'c' : args->ctx = atoi(optarg); break; + case 'u' : args->uid = atoi(optarg); break; + case 'g' : args->gid = atoi(optarg); break; + case 'r' : args->chroot = optarg; break; + case 'n' : args->do_fork = false; break; + default : + WRITE_MSG(2, "Try '"); + WRITE_STR(2, argv[0]); + WRITE_MSG(2, " --help\" for more information.\n"); + exit(1); + break; + } + } + + if (optind!=argc) { + WRITE_MSG(2, "No further options allowed; aborting ...\n"); + exit(1); + } + + if (args->chroot==0) { + WRITE_MSG(2, "No chroot specified; aborting...\n"); + exit(1); + } +} + +static void +sendResult(bool state, uint32_t res) +{ + if (state) { + static uint8_t ONE = 1; + Ewrite(1, &ONE, sizeof ONE); + } + else { + static uint8_t ZERO = 0; + Ewrite(1, &ZERO, sizeof ZERO); + } + + Ewrite(1, &res, sizeof res); +} + +static void +do_getpwnam() +{ + uint32_t len; + Eread(0, &len, sizeof len); + + if (lenpw_uid); + else sendResult(false, -1); + } + // TODO: logging +} + +static void +do_getgrnam() +{ + uint32_t len; + Eread(0, &len, sizeof len); + + if (lengr_gid); + else sendResult(false, -1); + } + // TODO: logging +} + +static void +do_closenss() +{ + uint8_t what; + Eread(0, &what, sizeof what); + switch (what) { + case 'p' : endpwent(); break; + case 'g' : endgrent(); break; + default : break; + } +} + +static void +run() +{ + uint8_t c; + + while (true) { + Ewrite(2, ".", 1); + Eread (0, &c, sizeof c); + switch (c) { + case 'P' : do_getpwnam(); break; + case 'G' : do_getgrnam(); break; + case 'Q' : exit(0); + case 'C' : do_closenss(); break; + case '.' : Ewrite(1, ".", 1); break; + default : Ewrite(1, "?", 1); break; + } + } +} + +static void +daemonize(struct ArgInfo const UNUSED * args, int pid_fd) +{ + pid_t pid = Efork(); + if (pid!=0) { + if (pid_fd!=-1) { + char buf[sizeof(id_t)*3 + 2]; + size_t l; + + l = utilvserver_fmt_uint(buf, pid); + Ewrite(pid_fd, buf, l); + Ewrite(pid_fd, "\n", 1); + } + _exit(0); + } +} + +int main(int argc, char * argv[]) +{ + struct ArgInfo args = { + .ctx = VC_RANDCTX, + .uid = 99, + .gid = 99, + .do_fork = false, + .pid_file = 0, + .chroot = 0 + }; + int pid_fd = -1; + + parseArgs(&args, argc, argv); + if (args.pid_file && args.do_fork) + pid_fd = Eopen(args.pid_file, O_CREAT|O_WRONLY, 0644); + + if (args.chroot) Echroot(args.chroot); + Echdir("/"); + + //Evc_new_s_context(args.ctx, ~(VC_CAP_SETGID|VC_CAP_SETUID), S_CTX_INFO_LOCK); + Evc_new_s_context(args.ctx, 0, S_CTX_INFO_LOCK); + Esetgroups(0, &args.gid); + Esetgid(args.gid); + Esetuid(args.uid); + + if (args.do_fork) daemonize(&args, pid_fd); + if (pid_fd!=-1) close(pid_fd); + run(); +} diff --git a/util-vserver/src/util-safechdir.c b/util-vserver/src/util-safechdir.c new file mode 100644 index 0000000..802bb83 --- /dev/null +++ b/util-vserver/src/util-safechdir.c @@ -0,0 +1,50 @@ +// $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 "util.h" +#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/src/vunify-matchlist.c b/util-vserver/src/vunify-matchlist.c new file mode 100644 index 0000000..9945442 --- /dev/null +++ b/util-vserver/src/vunify-matchlist.c @@ -0,0 +1,122 @@ +// $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 "vunify-matchlist.h" +#include + +bool +MatchList_compare(struct MatchList const *list, char const *path) +{ + bool res = true; + struct MatchItem const * ptr = list->data; + struct MatchItem const * const end_ptr = list->data + list->count; + + //write(1, path, strlen(path)); + //write(1, "\n", 1); + for (; ptrcmp!=0); + if ((ptr->cmp)(ptr->name, path)==0) { + switch (ptr->type) { + case stINCLUDE : res = true; break; + case stEXCLUDE : res = false; break; + default : abort(); + } + break; + } + } + + return res; +} + +void +MatchList_init(struct MatchList *list, char const *root, size_t count) +{ + list->skip_depth = 0; + list->root.d = root; + list->root.l = strlen(root); + list->data = malloc(sizeof(struct MatchItem) * count); + list->count = count; +} + + +void +PathInfo_append(PathInfo * restrict lhs, + PathInfo const * restrict rhs, + char *buf) +{ + char * ptr = buf; + char const * rhs_ptr = rhs->d; + size_t rhs_len = rhs->l; + + while (lhs->l>1 && lhs->d[lhs->l-1]=='/') --lhs->l; + + if (lhs->l>0) { + while (rhs->l>0 && *rhs_ptr=='/') { + ++rhs_ptr; + --rhs_len; + } + + ptr = Xmemcpy(ptr, lhs->d, lhs->l); + if (ptr[-1]!='/') + ptr = Xmemcpy(ptr, "/", 1); + } +// else if (*rhs_ptr!='/') +// ptr = Xmemcpy(ptr, "/", 1); + + ptr = Xmemcpy(ptr, rhs_ptr, rhs_len+1); + + lhs->d = buf; + lhs->l = ptr-buf-1; +} + + +#ifdef ENSC_TESTSUITE +#define CHECK(LHS,RHS, EXP) \ + do { \ + PathInfo lhs = { LHS, sizeof(LHS)-1 }; \ + PathInfo rhs = { RHS, sizeof(RHS)-1 }; \ + char *buf = malloc(ENSC_PI_APPSZ(lhs,rhs)); \ + assert(ENSC_PI_APPSZ(lhs,rhs)>=sizeof(EXP)); \ + PathInfo_append(&lhs, &rhs, buf); \ + assert(memcmp(lhs.d, EXP, sizeof(EXP))==0); \ + assert(lhs.l == sizeof(EXP)-1); \ + free(buf); \ + } while (0) + + +void +PathInfo_test() +{ + CHECK("/var", "/tmp", "/var/tmp"); + CHECK("/var", "tmp", "/var/tmp"); + CHECK("/var/", "/tmp", "/var/tmp"); + CHECK("/var/", "tmp", "/var/tmp"); + + CHECK("/", "tmp", "/tmp"); + CHECK("/", "/tmp", "/tmp"); + + CHECK("", "/tmp", "/tmp"); + + CHECK("", "tmp", "tmp"); + CHECK("", "", ""); +} +#endif diff --git a/util-vserver/src/vunify-matchlist.h b/util-vserver/src/vunify-matchlist.h new file mode 100644 index 0000000..eb6359b --- /dev/null +++ b/util-vserver/src/vunify-matchlist.h @@ -0,0 +1,65 @@ +// $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. + + +#ifndef H_UTIL_VSERVER_SRC_VUNIFY_MATCHLIST_H +#define H_UTIL_VSERVER_SRC_VUNIFY_MATCHLIST_H + +#include "util.h" + +#include +#include +#include + +struct MatchItem +{ + enum { stINCLUDE, stEXCLUDE } type; + char const * name; + int (*cmp)(char const *, char const *); +}; + +typedef struct +{ + char const * d; + size_t l; +} String; + +typedef String PathInfo; + +struct MatchList +{ + size_t skip_depth; + PathInfo root; + struct MatchItem *data; + size_t count; +}; + + +void MatchList_init(struct MatchList *, char const *root, size_t count) NONNULL((1,2)); +void MatchList_destroy(struct MatchList *) NONNULL((1)); + +bool MatchList_compare(struct MatchList const *, char const *path) NONNULL((1,2)); +struct MatchItem +const * MatchList_find(struct MatchList const *, char const *path) NONNULL((1,2)); + +void PathInfo_append(PathInfo * restrict, + PathInfo const * restrict, + char *buf) NONNULL((1,2,3)); + +#define ENSC_PI_APPSZ(P1,P2) ((P1).l + sizeof("/") + (P2).l) + +#endif // H_UTIL_VSERVER_SRC_VUNIFY_MATCHLIST_H diff --git a/util-vserver/src/vunify-operations.c b/util-vserver/src/vunify-operations.c new file mode 100644 index 0000000..cda31ee --- /dev/null +++ b/util-vserver/src/vunify-operations.c @@ -0,0 +1,110 @@ +// $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 "vunify-operations.h" +#include "util.h" + +#include +#include +#include + + +// ====== The compare functions ========= + +// return 'true' iff both files are different and unifyable +static bool +compareUnify(struct stat const *lhs, struct stat const *rhs) +{ + return (lhs->st_dev ==rhs->st_dev && + lhs->st_ino !=rhs->st_ino && + lhs->st_mode==rhs->st_mode && + lhs->st_uid ==rhs->st_uid && + lhs->st_gid ==rhs->st_gid && + lhs->st_size==rhs->st_size); + + // TODO: acl? time? +} + +// return 'true' iff both files are the same one +static bool +compareDeUnify(struct stat const *lhs, struct stat const *rhs) +{ + return (lhs->st_dev ==rhs->st_dev && + lhs->st_ino ==rhs->st_ino); +} + +// ===== The 'doit' functions =========== + + +static bool +unifyTest(char const *src, char const *dst) +{ + WRITE_MSG(1, "unifying '"); + WRITE_STR(1, src); + WRITE_MSG(1, "' -> '"); + WRITE_STR(1, dst); + WRITE_STR(1, "'\n"); + + return true; +} + + +static struct Operations op_unify_test = { + .compare = compareUnify, + .doit = unifyTest +}; + +static struct Operations op_deunify_test = { + .compare = compareDeUnify, + .doit = unifyTest +}; + +static struct Operations op_unify_notest = { + .compare = compareUnify, + .doit = unifyTest +}; + +static struct Operations op_deunify_notest = { + .compare = compareDeUnify, + .doit = unifyTest +}; + +// ====== + +void +Operations_init(struct Operations *op, OperationType type, bool is_test) +{ + switch (type) { + case opUNIFY : + if (is_test) *op = op_unify_test; + else *op = op_unify_notest; + break; + + case opDEUNIFY : + if (is_test) *op = op_deunify_test; + else *op = op_deunify_notest; + break; + + default : + abort(); + } +} diff --git a/util-vserver/src/vunify-operations.h b/util-vserver/src/vunify-operations.h new file mode 100644 index 0000000..07437c5 --- /dev/null +++ b/util-vserver/src/vunify-operations.h @@ -0,0 +1,38 @@ +// $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. + + +#ifndef H_UTIL_VSERVER_SRC_VUNIFY_OPERATIONS_H +#define H_UTIL_VSERVER_SRC_VUNIFY_OPERATIONS_H + +#include + +typedef enum { opUNIFY, opDEUNIFY } OperationType; + +struct stat; +struct MatchList; + +struct Operations { + bool (*compare)(struct stat const *lhs, + struct stat const *rhs); + bool (*doit)(char const *, char const *path); +}; + + +void Operations_init(struct Operations *, OperationType type, bool is_test); + +#endif // H_UTIL_VSERVER_SRC_VUNIFY_OPERATIONS_H diff --git a/util-vserver/src/vunify.c b/util-vserver/src/vunify.c new file mode 100644 index 0000000..e0e3a62 --- /dev/null +++ b/util-vserver/src/vunify.c @@ -0,0 +1,274 @@ +// $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 "vunify-matchlist.h" +#include "wrappers-dirent.h" +#include "vunify-operations.h" +#include "util.h" + +#include +#include +#include +#include +#include + +int wrapper_exit_code = 1; + +struct WalkdownInfo +{ + PathInfo state; + struct MatchList dst_list; + struct { + struct MatchList * v; + size_t l; + } src_lists; +}; + + +static struct WalkdownInfo global_info; +static struct Operations operations; + +static void visitDirEntry(struct dirent const *) NONNULL((1)); +static void visitDir(char const *, struct stat const *) NONNULL((1)); +static bool checkFstat(struct MatchList const * const, + PathInfo const * const, + PathInfo const * const, + struct stat const ** const, + struct stat * const) NONNULL((1,2,3,4,5)); + +static struct MatchList const * +checkDirEntry(PathInfo const *, + PathInfo const *, + bool *, struct stat *) NONNULL((1,2,3,4)); + +static bool updateSkipDepth(PathInfo const *, bool) NONNULL((1)); +static void EsafeChdir(char const *, struct stat const *) NONNULL((1,2)); +static bool doit(struct MatchList const *, PathInfo const *, + char const *dst_path) NONNULL((1,2,3)); + + + +// Returns 'false' iff one of the files is not existing, or of the files are different/not unifyable +static bool +checkFstat(struct MatchList const * const mlist, + PathInfo const * const basename, + PathInfo const * const path, + struct stat const ** const result, struct stat * const result_buf) +{ + assert(basename->d[0] != '/'); + + if (*result==0) { + // local file does not exist... strange + // TODO: message + if (lstat(basename->d, result_buf)==-1) return false; + *result = result_buf; + } + + assert(*result!=0); + + { + struct stat src_fstat; + PathInfo src_path = mlist->root; + char src_path_buf[ENSC_PI_APPSZ(src_path, *path)]; + + PathInfo_append(&src_path, path, src_path_buf); + + // source file does not exist + if (lstat(src_path.d, &src_fstat)==-1) return false; + + // both files are different, so return false + if (!(operations.compare)(*result, &src_fstat)) return false; + } + + // these are the same files + return true; +} + +static struct MatchList const * +checkDirEntry(PathInfo const *path, + PathInfo const *d_path, bool *is_dir, struct stat *f_stat) +{ + struct WalkdownInfo const * const info = &global_info; + struct MatchList const * mlist; + struct stat const * cache_stat = 0; + + // 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)) return 0; + + // Now, go through the reference vservers and do the lightweigt list-check + // first and compare then the fstat's. + for (mlist=info->src_lists.v; mlistsrc_lists.v+info->src_lists.l; ++mlist) { + if (MatchList_compare(mlist, path->d) && + checkFstat(mlist, d_path, path, &cache_stat, f_stat)) { + + // Failed the check or is it a symlink which can not be handled + if (cache_stat==0 || S_ISLNK(f_stat->st_mode)) return 0; + + *is_dir = S_ISDIR(f_stat->st_mode); + return mlist; + } + } + + // No luck... + return 0; +} + +static bool +updateSkipDepth(PathInfo const *path, bool walk_down) +{ + struct WalkdownInfo const * const info = &global_info; + struct MatchList * mlist; + bool result = false; + + for (mlist=info->src_lists.v; mlistsrc_lists.v+info->src_lists.l; ++mlist) { + // The easy way... this path is being skipped already + if (mlist->skip_depth>0) { + if (walk_down) ++mlist->skip_depth; + else --mlist->skip_depth; + continue; + } + else if (walk_down) { + PathInfo src_path = mlist->root; + char src_path_buf[ENSC_PI_APPSZ(src_path, *path)]; + struct stat src_fstat; + + PathInfo_append(&src_path, path, src_path_buf); + + // when the file/dir exist, we have do go deeper. + // else skip it in deeper runs for *this* matchlist + if (lstat(src_path.d, &src_fstat)!=-1) result = true; + else ++mlist->skip_depth; + } + else { + // TODO: warning + } + } + + return result; +} + +inline static void +EsafeChdir(char const *path, struct stat const *exp_stat) +{ + FatalErrnoError(safeChdir(path, exp_stat)==-1, "safeChdir()"); +} + +static bool +doit(struct MatchList const *mlist, PathInfo const *src_path, + char const *dst_path) +{ + PathInfo path = mlist->root; + char path_buf[ENSC_PI_APPSZ(path, *src_path)]; + + PathInfo_append(&path, src_path, path_buf); + return (operations.doit)(path.d, dst_path); +} + + +static void +visitDirEntry(struct dirent const *ent) +{ + bool is_dir; + struct MatchList const * match; + struct stat f_stat; + char const * dirname = ent->d_name; + size_t path_len = strlen(ent->d_name); + PathInfo path = global_info.state; + PathInfo d_path = { + .d = dirname, + .l = path_len + }; + char path_buf[ENSC_PI_APPSZ(path, d_path)]; + + PathInfo_append(&path, &d_path, path_buf); + + if ((dirname[0]=='.' && + (dirname[1]=='\0' || (dirname[1]=='.' && dirname[2]=='\0'))) || + (match=checkDirEntry(&path, &d_path, &is_dir, &f_stat))==0) { + WRITE_MSG(1, "skipping '"); + WRITE_STR(1, dirname); + WRITE_MSG(1, "'\n"); + return; + } + + if (is_dir) { + if (updateSkipDepth(&path, true)) { + visitDir(dirname, &f_stat); + updateSkipDepth(&path, false); + } + } + else if (!doit(match, &path, dirname)) { + // TODO: message + } +} + +static void +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; + + 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; + + visitDirEntry(ent); + } + + Eclosedir(dir); + + Efchdir(fd); + Eclose(fd); + + global_info.state = old_state; +} + + +int main(int argc, char *argv[]) +{ + global_info.state.d = ""; + global_info.state.l = 0; + + Operations_init(&operations, opUNIFY, false); + MatchList_init(&global_info.dst_list, argv[1], 0); + + global_info.src_lists.v = malloc(sizeof(struct MatchList)); + global_info.src_lists.l = 1; + MatchList_init(global_info.src_lists.v+0, argv[2], 0); + + Echdir(global_info.dst_list.root.d); + visitDir("/", 0); +} diff --git a/util-vserver/src/wrappers-dirent.h b/util-vserver/src/wrappers-dirent.h new file mode 100644 index 0000000..3d53702 --- /dev/null +++ b/util-vserver/src/wrappers-dirent.h @@ -0,0 +1,65 @@ +// $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. + + +#ifndef H_UTIL_VSERVER_SRC_WRAPPERS_DIRENT_H +#define H_UTIL_VSERVER_SRC_WRAPPERS_DIRENT_H + +#include "wrappers.h" +#include + +#define WRAPPER_DECL UNUSED ALWAYSINLINE + +inline static WRAPPER_DECL DIR * +Eopendir(const char *name) +{ + DIR * res = opendir(name); + + FatalErrnoError(res==0, "opendir()"); + return res; +} + +inline static WRAPPER_DECL struct dirent * +Ereaddir(DIR *dir) +{ + struct dirent *res; + + errno = 0; + res = readdir(dir); + + FatalErrnoError(res==0 && errno!=0, "readdir()"); + return res; +} + +#ifndef __dietlibc__ +inline static WRAPPER_DECL void +Ereaddir_r(DIR *dir, struct dirent *entry, struct dirent **result) +{ + errno = 0; + FatalErrnoError(readdir_r(dir, entry, result)==0 && errno!=0, "readdir_r()"); +} +#endif + +inline static WRAPPER_DECL void +Eclosedir(DIR *dir) +{ + FatalErrnoError(closedir(dir)==-1, "closedir()"); +} + +#undef WRAPPER_DECL + +#endif // H_UTIL_VSERVER_SRC_WRAPPERS_DIRENT_H