diff --git a/AUTHORS b/AUTHORS index 291539d83ced3eae7f352e6523abe35f2488a4e3..3ee49bb78b51002fc1251795a1a2145dd24a14cc 100644 --- a/AUTHORS +++ b/AUTHORS @@ -4,14 +4,13 @@ design, Ethernet switch elements, user-level pcap/BPF elements Eddie Kohler eddietwo@lcs.mit.edu -design, core, Linux /proc interface, standard elements, optimizer, -documentation, other elements +design, core, Linux /proc interface, standard elements, tools, documentation, +distribution, other elements Robert Morris rtm@lcs.mit.edu -design, Ethernet elements, IP elements, Linux kernel module elements, radio -elements, Linux kernel patches, IP router configuration, element -documentation, other elements +design, Ethernet, IP, Linux kernel module, and radio elements, Linux kernel +patches, IP router configuration, element documentation, other elements Alex Snoeren snoeren@lcs.mit.edu diff --git a/NEWS b/NEWS index e8a4107611ffc770d5f0cc2d47fe6947c695181d..8229fd7f5caf0b029abdff78136dd0ac2cfd0323 100644 --- a/NEWS +++ b/NEWS @@ -2,7 +2,14 @@ Click NEWS Version 0.52 -* Added `--help', `--version', etc. options to tools. +* Added `--help', `--version', etc. options to tools + +* Added "dynamic linking" support to kernel module + +* More options for user-level Click, and support for hander invocations on the + command line + +* Fixed dynamic reconfiguration bug: no more doubled characters Version 0.51 12.Nov.1999 diff --git a/configure.in b/configure.in index 54fab97d75d50b15d33cff00a96bcf7d438aa794..96e618a0fc25b131e87cb3fd4e0f1bcef879a215 100644 --- a/configure.in +++ b/configure.in @@ -15,6 +15,13 @@ AC_PROG_CPP AC_PROG_RANLIB AC_PROG_INSTALL +dnl +dnl packagedir +dnl + +packagesdir='$(localstatedir)/packages' +AC_SUBST(packagesdir) + dnl dnl check for C++ dnl @@ -203,6 +210,8 @@ dnl TARGETS= AC_SUBST(TARGETS) +TOOL_TARGETS="click-align click-xform" +AC_SUBST(TOOL_TARGETS) dnl check userlevel for pcap library @@ -272,6 +281,7 @@ int main(int c, char **v) { ac_cv_cxx_aware_system=no)) if test $ac_cv_cxx_aware_system = yes; then TARGETS="$TARGETS linuxmodule" + TOOL_TARGETS="$TOOL_TARGETS click-install" else AC_MSG_WARN(Your header files must be patched before a C++ program can include them. Apply the patch that came with this distribution @@ -305,7 +315,7 @@ dnl dnl Output dnl -config_files="Makefile mkelemlist.sh tools/Makefile tools/click-xform/Makefile tools/click-align/Makefile doc/Makefile" +config_files="Makefile mkelemlist.sh tools/Makefile tools/click-align/Makefile tools/click-install/Makefile tools/click-xform/Makefile doc/Makefile" for dir in $POSSIBLE_TARGETS; do config_files="$config_files $dir/Makefile" done diff --git a/elements/aqm/red.cc b/elements/aqm/red.cc index d2d39ed1c4a3a3bde9c6006a1bd08f3c4227ebbb..560ba05e11e572ae1a273f8cfd6a7404a1e1abc3 100644 --- a/elements/aqm/red.cc +++ b/elements/aqm/red.cc @@ -232,11 +232,26 @@ RED::read_stats(Element *f, void *) ; } +String +RED::read_queues(Element *f, void *) +{ + RED *r = (RED *)f; + if (r->_queue1) + return r->_queue1->id() + "\n"; + else { + String s; + for (int i = 0; i < r->_queues.size(); i++) + s += r->_queues[i]->id() + "\n"; + return s; + } +} + void RED::add_handlers(HandlerRegistry *fcr) { fcr->add_read("drops", red_read_drops, 0); fcr->add_read("stats", read_stats, 0); + fcr->add_read("queues", read_queues, 0); fcr->add_read_write("min_thresh", read_parameter, (void *)0, reconfigure_write_handler, (void *)0); fcr->add_read_write("max_thresh", read_parameter, (void *)1, diff --git a/elements/aqm/red.hh b/elements/aqm/red.hh index ab2fe2c5566013ecdb6b65c1275ea0d69c7315d4..d626918917df99311b276f5e2fc2ade6a1bae732 100644 --- a/elements/aqm/red.hh +++ b/elements/aqm/red.hh @@ -46,6 +46,7 @@ class RED : public Element { void set_C1_and_C2(); static String read_stats(Element *, void *); + static String read_queues(Element *, void *); static String read_parameter(Element *, void *); public: diff --git a/elements/standard/classifier.cc b/elements/standard/classifier.cc index 389cd3697837308efcd0c8074b29377ba00a5ece..db887191b76e3b66ef60beea5b0bc5cc45f9bc6f 100644 --- a/elements/standard/classifier.cc +++ b/elements/standard/classifier.cc @@ -710,22 +710,11 @@ Classifier::decompile_string(Element *element, void *) char buf[20]; int offset = e.offset - f->_align_offset; sa << i << (offset < 10 ? " " : " ") << offset << "/"; - bool need_mask = 0; - for (int j = 0; j < 4; j++) { - int m = e.mask.c[j], v = e.value.c[j]; - for (int k = 0; k < 2; k++, m <<= 4, v <<= 4) - if ((m & 0xF0) == 0x00) - sprintf(buf + 2*j + k, "?"); - else { - sprintf(buf + 2*j + k, "%x", (v >> 4) & 0xF); - if ((m & 0xF0) != 0xF0) need_mask = 1; - } - } - if (need_mask) { - sprintf(buf + 8, "%%"); - for (int j = 0; j < 4; j++) - sprintf(buf + 9 + 2*j, "%02x", e.mask.c[j]); - } + for (int j = 0; j < 4; j++) + sprintf(buf + 2*j, "%02x", e.value.c[j]); + sprintf(buf + 8, "%%"); + for (int j = 0; j < 4; j++) + sprintf(buf + 9 + 2*j, "%02x", e.mask.c[j]); sa << buf << " yes->"; if (e.yes <= 0) sa << "[" << -e.yes << "]"; diff --git a/elements/standard/red.cc b/elements/standard/red.cc index d2d39ed1c4a3a3bde9c6006a1bd08f3c4227ebbb..560ba05e11e572ae1a273f8cfd6a7404a1e1abc3 100644 --- a/elements/standard/red.cc +++ b/elements/standard/red.cc @@ -232,11 +232,26 @@ RED::read_stats(Element *f, void *) ; } +String +RED::read_queues(Element *f, void *) +{ + RED *r = (RED *)f; + if (r->_queue1) + return r->_queue1->id() + "\n"; + else { + String s; + for (int i = 0; i < r->_queues.size(); i++) + s += r->_queues[i]->id() + "\n"; + return s; + } +} + void RED::add_handlers(HandlerRegistry *fcr) { fcr->add_read("drops", red_read_drops, 0); fcr->add_read("stats", read_stats, 0); + fcr->add_read("queues", read_queues, 0); fcr->add_read_write("min_thresh", read_parameter, (void *)0, reconfigure_write_handler, (void *)0); fcr->add_read_write("max_thresh", read_parameter, (void *)1, diff --git a/elements/standard/red.hh b/elements/standard/red.hh index ab2fe2c5566013ecdb6b65c1275ea0d69c7315d4..d626918917df99311b276f5e2fc2ade6a1bae732 100644 --- a/elements/standard/red.hh +++ b/elements/standard/red.hh @@ -46,6 +46,7 @@ class RED : public Element { void set_C1_and_C2(); static String read_stats(Element *, void *); + static String read_queues(Element *, void *); static String read_parameter(Element *, void *); public: diff --git a/lib/error.cc b/lib/error.cc index 248e7d132fa4c7f21ed3d0c90b71f1c97a4c3ba5..69e15e17511c29dd3de7bff9957f4f279b2078d1 100644 --- a/lib/error.cc +++ b/lib/error.cc @@ -540,3 +540,33 @@ ContextErrorHandler::vmessage(Seriousness seriousness, const String &message) } _errh->vmessage(seriousness, _indent + message); } + + +// +// PREFIX ERROR HANDLER +// + +PrefixErrorHandler::PrefixErrorHandler(ErrorHandler *errh, + const String &prefix) + : _prefix(prefix), _errh(errh) +{ +} + +void +PrefixErrorHandler::reset_counts() +{ + _errh->reset_counts(); +} + +int +PrefixErrorHandler::verror(Seriousness seriousness, const String &where, + const char *format, va_list val) +{ + return _errh->verror(seriousness, _prefix + where, format, val); +} + +void +PrefixErrorHandler::vmessage(Seriousness seriousness, const String &message) +{ + _errh->vmessage(seriousness, _prefix + message); +} diff --git a/lib/error.hh b/lib/error.hh index fe5f619f0334ca24f4b0334f084f799ddf3c91e1..9b7069fdda8ee19e153dd9a87bffba38f18df555 100644 --- a/lib/error.hh +++ b/lib/error.hh @@ -82,4 +82,22 @@ class ContextErrorHandler : public ErrorHandler { }; +class PrefixErrorHandler : public ErrorHandler { + + String _prefix; + ErrorHandler *_errh; + + public: + + PrefixErrorHandler(ErrorHandler *, const String &prefix); + + int nwarnings() const { return _errh->nwarnings(); } + int nerrors() const { return _errh->nerrors(); } + void reset_counts(); + + int verror(Seriousness, const String &, const char *, va_list); + void vmessage(Seriousness, const String &); + +}; + #endif diff --git a/lib/lexer.cc b/lib/lexer.cc index 1b9951574164943e85af28d00de2252e7498532d..a34c6cd94a60edd4b007d05995e68cc5d3409b6d 100644 --- a/lib/lexer.cc +++ b/lib/lexer.cc @@ -513,6 +513,8 @@ Lexer::remove_element_type(int j) if (_element_types[i]) return; _element_types.resize(j); + _element_type_names.resize(j); + _prev_element_type.resize(j); } } @@ -522,6 +524,18 @@ Lexer::remove_element_type(const String &name) remove_element_type(_element_type_map[name]); } +void +Lexer::element_type_names(Vector<String> &v) const +{ + for (int i = FIRST_REAL_TYPE; i < _reset_element_types; i++) + if (_element_types[i] && _element_type_map[_element_type_names[i]] == i) + v.push_back(_element_type_names[i]); + /* int thunk = 0, value; String key; + while (_element_type_map.each(thunk, key, value)) + if (value >= 0 && value < _reset_element_types && key[0] != '<') + v.push_back(key);*/ +} + // PORT TUNNELS diff --git a/lib/lexer.hh b/lib/lexer.hh index 02e24d1bdc6c661d43be5828a748aa0fafd9753d..b52e3d5a71dee320741fbe1759be7793b1885538 100644 --- a/lib/lexer.hh +++ b/lib/lexer.hh @@ -126,9 +126,7 @@ class Lexer { int force_element_type(String); void save_element_types(); - int first_element_type() const { return FIRST_REAL_TYPE; } - int permanent_element_types() const { return _reset_element_types; } - Element *element_type(int i) const { return _element_types[i]; } + void element_type_names(Vector<String> &) const; void remove_element_type(int); void remove_element_type(const String &); diff --git a/linuxmodule/module.cc b/linuxmodule/module.cc index 688f1522e75bd87080ed4695ed89b8f538b7320d..00ca7e9c550f32eb55d5b35cf400c9b6c265aaad 100644 --- a/linuxmodule/module.cc +++ b/linuxmodule/module.cc @@ -38,7 +38,7 @@ ErrorHandler *kernel_errh = 0; static Lexer *lexer = 0; Router *current_router = 0; -static Vector<String> provisions; +static Vector<String> packages; class LinuxModuleLexerSource : public MemoryLexerSource { @@ -51,8 +51,8 @@ class LinuxModuleLexerSource : public MemoryLexerSource { void LinuxModuleLexerSource::require(const String &r, ErrorHandler *errh) { - for (int i = 0; i < provisions.size(); i++) - if (provisions[i] == r) + for (int i = 0; i < packages.size(); i++) + if (packages[i] == r) return; errh->error("unsatisfied requirement `%s'", String(r).cc()); } @@ -73,8 +73,8 @@ initialize_router(const char *data, unsigned len) lexer->clear(); if (current_router) { - if (current_router->initialize(kernel_errh) >= 0) - current_router->print_structure(kernel_errh); + current_router->initialize(kernel_errh); + // current_router->print_structure(kernel_errh); init_router_element_procs(); } } @@ -268,10 +268,20 @@ read_list(Element *, void *) static String read_classes(Element *, void *) { - int nft = lexer->permanent_element_types(); + Vector<String> v; + lexer->element_type_names(v); StringAccum sa; - for (int i = lexer->first_element_type(); i < nft; i++) - sa << lexer->element_type(i)->class_name() << "\n"; + for (int i = 0; i < v.size(); i++) + sa << v[i] << "\n"; + return sa.take_string(); +} + +static String +read_packages(Element *, void *) +{ + StringAccum sa; + for (int i = 0; i < packages.size(); i++) + sa << packages[i] << "\n"; return sa.take_string(); } @@ -314,18 +324,18 @@ extern "C" void click_provide(const char *name) { MOD_INC_USE_COUNT; - provisions.push_back(String(name)); + packages.push_back(String(name)); } extern "C" void click_unprovide(const char *name) { String n = name; - for (int i = 0; i < provisions.size(); i++) - if (provisions[i] == n) { + for (int i = 0; i < packages.size(); i++) + if (packages[i] == n) { MOD_DEC_USE_COUNT; - provisions[i] = provisions.back(); - provisions.pop_back(); + packages[i] = packages.back(); + packages.pop_back(); break; } } @@ -334,6 +344,7 @@ extern "C" void click_add_element_type(const char *name, Element *e) { lexer->add_element_type(name, e); + lexer->save_element_types(); } extern "C" void @@ -379,6 +390,7 @@ init_module() kfr.add_read("flatconfig", read_flatconfig, 0); kfr.add_read("list", read_list, 0); kfr.add_read("classes", read_classes, 0); + kfr.add_read("packages", read_packages, 0); kfr.add_read("requirements", read_requirements, 0); kfr.add_write("driver", write_driver, 0); diff --git a/tools/Makefile.in b/tools/Makefile.in index 9fe6768d455dfb74f536b8ce8efdd3d671a2e583..32ac17cae601dd46185fe59b3199a4c08d0584ee 100644 --- a/tools/Makefile.in +++ b/tools/Makefile.in @@ -9,29 +9,32 @@ srcdir = @srcdir@ top_builddir = .. subdir = tools -TOOLS = click-xform click-align +TOOLS = click-align click-install click-xform +TARGETS = @TOOL_TARGETS@ -all: $(TOOLS) +all: $(TARGETS) -click-xform: Makefile - @cd click-xform; $(MAKE) all click-align: Makefile @cd click-align; $(MAKE) all +click-install: Makefile + @cd click-install; $(MAKE) all +click-xform: Makefile + @cd click-xform; $(MAKE) all Makefile: $(srcdir)/Makefile.in cd $(top_builddir) \ && CONFIG_FILES=$(subdir)/$@ CONFIG_ELEMLISTS=no CONFIG_HEADERS= $(SHELL) ./config.status clean: - @-for d in $(TOOLS); do cd $$d; $(MAKE) clean; done + @-for d in $(TOOLS); do (cd $$d; $(MAKE) clean); done distclean: - @-for d in $(TOOLS); do cd $$d; $(MAKE) distclean; done + @-for d in $(TOOLS); do (cd $$d; $(MAKE) distclean); done -rm -f Makefile install: - @for d in $(TOOLS); do cd $$d; $(MAKE) install; done + @for d in $(TARGETS); do (cd $$d; $(MAKE) install); done install-man: - @for d in $(TOOLS); do cd $$d; $(MAKE) install-man; done + @for d in $(TARGETS); do (cd $$d; $(MAKE) install-man); done DISTFILES = Makefile.in \ lib/elementt.cc lib/elementt.hh \ @@ -41,8 +44,8 @@ DISTFILES = Makefile.in \ lib/vectori.cc \ click-xform/Makefile.in \ click-xform/click-xform.cc \ - click-flatten/Makefile.in \ - click-flatten/click-flatten.cc \ + click-install/Makefile.in \ + click-install/click-install.cc \ click-align/Makefile.in \ click-align/click-align.cc \ click-align/alignment.cc click-align/alignment.hh \ diff --git a/tools/click-install/.cvsignore b/tools/click-install/.cvsignore new file mode 100644 index 0000000000000000000000000000000000000000..fc6272aa50b2f6c994336e0581ca6298de760252 --- /dev/null +++ b/tools/click-install/.cvsignore @@ -0,0 +1,2 @@ +Makefile *.d +click-install diff --git a/tools/click-install/Makefile.in b/tools/click-install/Makefile.in new file mode 100644 index 0000000000000000000000000000000000000000..710e1cf69ee6096981f1f39fd5eb2cd09c94c1ff --- /dev/null +++ b/tools/click-install/Makefile.in @@ -0,0 +1,86 @@ +SHELL = @SHELL@ + +srcdir := @srcdir@ +top_srcdir := @top_srcdir@ +top_builddir := ../.. +subdir := tools/click-install + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +bindir = @bindir@ +sbindir = @sbindir@ +libdir = @libdir@ +mandir = @mandir@ +localstatedir = @localstatedir@ +packagesdir = @packagesdir@ + +VPATH = .:$(top_srcdir)/$(subdir):$(top_srcdir)/tools/lib:$(top_srcdir)/lib + +CC = @CC@ +CPP = @CPP@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ +INSTALL = @INSTALL@ +mkinstalldirs = @top_srcdir@/mkinstalldirs + +.SUFFIXES: +.SUFFIXES: .S .c .cc .o .s + +.c.o: + $(COMPILE) -c $< +.s.o: + $(COMPILE) -c $< +.S.o: + $(COMPILE) -c $< +.cc.o: + $(CXXCOMPILE) -c $< + + +OBJS = vectori.o vectorv.o bitvector.o hashmapi.o straccum.o string.o error.o \ + elementt.o routert.o lexert.o confparse.o clp.o @LIBOBJS@ \ + click-install.o + +CPPFLAGS = @CPPFLAGS@ -MMD -DCLICK_TOOL +CFLAGS = @CFLAGS@ +CXXFLAGS = @CXXFLAGS@ -fno-exceptions -fno-rtti + +DEFS = @DEFS@ -DCLICK_LIBDIR='"$(libdir)"' -DCLICK_PACKAGESDIR='"$(packagesdir)"' \ + -I. -I$(top_builddir) -I$(srcdir) \ + -I$(top_srcdir)/tools/lib -I$(top_srcdir)/lib +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ + +CXXCOMPILE = $(CXX) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(CXXFLAGS) $(LDFLAGS) -o $@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(CFLAGS) $(LDFLAGS) -o $@ + +all: click-install + +click-install: Makefile $(OBJS) + $(CXXLINK) $(OBJS) + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_ELEMLISTS=no CONFIG_HEADERS= $(SHELL) ./config.status + +DEPFILES := $(wildcard *.d) +ifneq ($(DEPFILES),) +include $(DEPFILES) +endif + +install: click-install + $(mkinstalldirs) $(sbindir) + $(INSTALL) click-install $(sbindir)/click-install +install-man: + +clean: + rm -f *.d *.o click-install +distclean: clean + -rm -f Makefile + +.PHONY: all clean distclean install install-bin install-man diff --git a/tools/click-install/click-install.cc b/tools/click-install/click-install.cc new file mode 100644 index 0000000000000000000000000000000000000000..767049dcac1c3e0aae8331962ee3ade2537eef72 --- /dev/null +++ b/tools/click-install/click-install.cc @@ -0,0 +1,284 @@ +/* + * click-install.cc -- configuration installer for Click kernel module + * Eddie Kohler + * + * Copyright (c) 1999 Massachusetts Institute of Technology. + * + * This software is being provided by the copyright holders under the GNU + * General Public License, either version 2 or, at your discretion, any later + * version. For more information, see the `COPYRIGHT' file in the source + * distribution. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include "routert.hh" +#include "lexert.hh" +#include "error.hh" +#include "confparse.hh" +#include "clp.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <sys/stat.h> +#include <unistd.h> + +#define HELP_OPT 300 +#define VERSION_OPT 301 +#define ROUTER_OPT 302 + +static Clp_Option options[] = { + { "file", 'f', ROUTER_OPT, Clp_ArgString, 0 }, + { "help", 'h', HELP_OPT, 0, 0 }, + { "version", 'v', VERSION_OPT, 0, 0 }, +}; + +static const char *program_name; + +void +short_usage() +{ + fprintf(stderr, "Usage: %s [OPTION]... [ROUTERFILE]\n\ +Try `%s --help' for more information.\n", + program_name, program_name); +} + +void +usage() +{ + printf("\ +`Click-install' installs a Click configuration into the current Linux kernel.\n\ +\n\ +Usage: %s [OPTION]... [ROUTERFILE]\n\ +\n\ +Options:\n\ + -f, --file FILE Read router configuration from FILE.\n\ + -h, --help Print this message and exit.\n\ + -v, --version Print version number and exit.\n\ +\n\ +Report bugs to <click@pdos.lcs.mit.edu>.\n", program_name); +} + +static String +path_find_file_2(const String &filename, String path, + String default_path) +{ + while (1) { + int colon = path.find_left(':'); + String dir = (colon < 0 ? path : path.substring(0, colon)); + if (!dir && default_path) { + String s = path_find_file_2(filename, default_path, String()); + if (s) return s; + default_path = String(); // don't search default path twice + } else if (dir) { + String name = (dir[dir.length()-1] == '/' ? dir + filename : dir + "/" + filename); + struct stat s; + if (stat(name.cc(), &s) >= 0) + return name; + } + if (colon < 0) return String(); + path = path.substring(colon + 1); + } +} + +static String +path_find_file(const String &filename, const char *path_variable, + const String &default_path) +{ + const char *path = getenv(path_variable); + if (!path) + return path_find_file_2(filename, default_path, ""); + else + return path_find_file_2(filename, path, default_path); +} + + +static void +read_packages(HashMap<String, int> &packages, ErrorHandler *errh) +{ + packages.clear(); + FILE *f = fopen("/proc/click/packages", "r"); + if (!f) + errh->warning("cannot read /proc/click/packages: %s", strerror(errno)); + else { + char buf[1024]; + while (fgets(buf, 1024, f)) { + String p = buf; + if (p[p.length()-1] != '\n') + errh->warning("/proc/click/packages: line too long"); + else + packages.insert(p.substring(0, -1), 0); + } + fclose(f); + } +} + +RouterT * +read_router_file(const char *filename, ErrorHandler *errh) +{ + FILE *f; + if (filename && strcmp(filename, "-") != 0) { + f = fopen(filename, "r"); + if (!f) { + errh->error("%s: %s", filename, strerror(errno)); + return 0; + } + } else { + f = stdin; + filename = "<stdin>"; + } + + FileLexerTSource lex_source(filename, f); + LexerT lexer(errh); + lexer.reset(&lex_source); + while (lexer.ystatement()) ; + RouterT *r = lexer.take_router(); + + if (f != stdin) fclose(f); + return r; +} + +int +main(int argc, char **argv) +{ + String::static_initialize(); + ErrorHandler::static_initialize(new FileErrorHandler(stderr)); + ErrorHandler *errh = new PrefixErrorHandler + (ErrorHandler::default_handler(), "click-install: "); + + // read command line arguments + Clp_Parser *clp = + Clp_NewParser(argc, argv, sizeof(options) / sizeof(options[0]), options); + program_name = Clp_ProgramName(clp); + + const char *router_file = 0; + + while (1) { + int opt = Clp_Next(clp); + switch (opt) { + + case HELP_OPT: + usage(); + exit(0); + break; + + case VERSION_OPT: + printf("click-install (Click) %s\n", VERSION); + printf("Copyright (C) 1999 Massachusetts Institute of Technology\n\ +This is free software; see the source for copying conditions.\n\ +There is NO warranty, not even for merchantability or fitness for a\n\ +particular purpose.\n"); + exit(0); + break; + + case ROUTER_OPT: + case Clp_NotOption: + if (router_file) { + errh->error("router file specified twice"); + goto bad_option; + } + router_file = clp->arg; + break; + + bad_option: + case Clp_BadOption: + short_usage(); + exit(1); + break; + + case Clp_Done: + goto done; + + } + } + + done: + RouterT *r = read_router_file(router_file, errh); + if (!r || errh->nerrors() > 0) + exit(1); + + r->flatten(errh); + + // check for Click module; install it if not available + { + struct stat s; + if (stat("/proc/click", &s) < 0) { + // try to install module + String click_o = path_find_file("click.o", "CLICK_LIB", CLICK_LIBDIR); + if (!click_o) { + errh->message("cannot find Click module `click.o'"); + errh->fatal("in CLICK_LIB or `%s'", CLICK_LIBDIR); + } + String cmdline = "/sbin/insmod " + click_o; + (void) system(cmdline); + if (stat("/proc/click", &s) < 0) + errh->fatal("cannot install Click module"); + } + } + + // find current packages + HashMap<String, int> packages(-1); + read_packages(packages, errh); + + // install missing requirements + { + const HashMap<String, int> &requirements = r->requirement_map(); + int thunk = 0, value; String key; + while (requirements.each(thunk, key, value)) + if (value >= 0 && packages[key] < 0) { + String package = path_find_file + (key + ".o", "CLICK_PACKAGES", CLICK_PACKAGESDIR); + if (!package) { + errh->message("cannot find required package `%s.o'", key.cc()); + errh->fatal("in CLICK_PACKAGES or `%s'", CLICK_PACKAGESDIR); + } + String cmdline = "/sbin/insmod " + package; + int retval = system(cmdline); + if (retval != 0) + errh->fatal("`insmod %s' failed: %s", package.cc(), strerror(errno)); + } + } + + // write flattened configuration to /proc/click/config + FILE *f = fopen("/proc/click/config", "w"); + if (!f) + errh->fatal("cannot install configuration: %s", strerror(errno)); + String s = r->configuration_string(); + fputs(s.cc(), f); + fclose(f); + + // report errors + { + char buf[1024]; + FILE *f = fopen("/proc/click/errors", "r"); + if (!f) + errh->warning("cannot read /proc/click/errors: %s", strerror(errno)); + else { + while (!feof(f)) { + size_t s = fread(buf, 1, 1024, f); + fwrite(buf, 1, s, stderr); + } + fclose(f); + } + } + + // remove unused packages + { + read_packages(packages, errh); + const HashMap<String, int> &requirements = r->requirement_map(); + int thunk = 0, value; String key; + String to_remove; + while (packages.each(thunk, key, value)) + if (value >= 0 && requirements[key] < 0) + to_remove += " " + key; + if (to_remove) { + String cmdline = "/sbin/rmmod " + to_remove + " 2>/dev/null"; + (void) system(cmdline); + } + } + + return 0; +} diff --git a/tools/lib/routert.cc b/tools/lib/routert.cc index f5935a3152c09c15e99718c2372eea526ced45f1..c24a6b0375bc960872fc31ff811c741cad290c55 100644 --- a/tools/lib/routert.cc +++ b/tools/lib/routert.cc @@ -175,13 +175,6 @@ RouterT::remove_connection(int i) } -void -RouterT::add_requirement(const String &s) -{ - _require_map.insert(s, 0); -} - - bool RouterT::has_connection(const Hookup &hfrom, const Hookup &hto) const { @@ -276,6 +269,13 @@ RouterT::add_tunnel(String in, String out, const String &landmark, } +void +RouterT::add_requirement(const String &s) +{ + _require_map.insert(s, 0); +} + + void RouterT::remove_bad_connections() { diff --git a/tools/lib/routert.hh b/tools/lib/routert.hh index 9dca7f1d04d6bcb5044dc435e100a45e56b6488a..ce3dba3c92ee68a53e5e8f9822c24792d74310ca 100644 --- a/tools/lib/routert.hh +++ b/tools/lib/routert.hh @@ -75,6 +75,7 @@ class RouterT : public ElementClassT { void remove_connection(int); void add_requirement(const String &); + const HashMap<String, int> &requirement_map() const { return _require_map; } bool has_connection(const Hookup &, const Hookup &) const; void find_connections_from(const Hookup &, Vector<Hookup> &) const;