📄 interest.c++
字号:
// Copyright (C) 1999 Silicon Graphics, Inc. All Rights Reserved.// // This program is free software; you can redistribute it and/or modify it// under the terms of version 2 of the GNU General Public License as// published by the Free Software Foundation.//// This program is distributed in the hope that it would be useful, but// WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Further, any// license provided herein, whether implied or otherwise, is limited to// this program in accordance with the express provisions of the GNU// General Public License. Patent licenses, if any, provided herein do not// apply to combinations of this program with other product or programs, or// any other product whatsoever. This program is distributed without any// warranty that the program is delivered free of the rightful claim of any// third person by way of infringement or the like. 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 the Free Software Foundation, Inc., 59// Temple Place - Suite 330, Boston MA 02111-1307, USA.#include "Interest.h"#include <string.h>#include <errno.h>#include <sys/param.h>#if !defined(__FreeBSD__)# include <sys/sysmacros.h>#endif#ifdef HAVE_IRIX_XTAB_VERIFICATION#include <stdio.h>#include <exportent.h>#include <netdb.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#endif // HAVE_IRIX_XTAB_VERIFICATION#include "Boolean.h"#include "Event.h"#include "FileSystem.h"#include "IMon.h"#include "Log.h"#include "Pollster.h"#include "timeval.h"Interest *Interest::hashtable[];IMon Interest::imon(imon_handler);bool Interest::xtab_verification = true;Interest::Interest(const char *name, FileSystem *fs, in_addr host, ExportVerification ev) : hashlink(NULL), myname(strcpy(new char[strlen(name) + 1], name)), scan_state(OK), cur_exec_state(NOT_EXECUTING), old_exec_state(NOT_EXECUTING), myhost(host), mypath_exported_to_host(ev == NO_VERIFY_EXPORTED){ memset(&old_stat, 0, sizeof(old_stat)); IMon::Status s = IMon::BAD; s = imon.express(name, &old_stat); if (s != IMon::OK) { int rc = lstat(name, &old_stat); if (rc < 0) { Log::info("can't lstat %s", name); memset(&old_stat, 0, sizeof old_stat); } } dev = old_stat.st_dev; ino = old_stat.st_ino; if (ev == VERIFY_EXPORTED) verify_exported_to_host(); if (s == IMon::OK) { if ((exported_to_host()) && (dev || ino)) { // Insert on new chain. Interest **ipp = hashchain(); hashlink = *ipp; *ipp = this; } else revoke(); } #if HAVE_STAT_ST_FSTYPE_STRING // Enable low-level monitoring. // The NetWare filesystem is too slow to monitor, so // don't even try. if ( !strcmp( (char *) &old_stat.st_fstype, "nwfs")) { return; }#endif if (exported_to_host()) fs->ll_monitor(this, s == IMon::OK);}Interest::~Interest(){ Pollster::forget(this); revoke(); delete[] myname;}voidInterest::revoke(){ // Traverse our hash chain. Delete this entry when we find it. // Also check for other entries with same dev/ino. if (dev || ino) { bool found_same = false; for (Interest *p, **pp = hashchain(); ((p = *pp) != NULL); ) if (p == this) *pp = p->hashlink; // remove this from list else { if (p->ino == ino && p->dev == dev) found_same = true; pp = &p->hashlink; // move to next element } if (!found_same) (void) imon.revoke(name(), dev, ino); }}boolInterest::dev_ino(dev_t newdev, ino_t newino){ // Remove from hash chain and revoke imon's interest. revoke(); dev = newdev; ino = newino; if (newdev || newino) { // Express interest. IMon::Status s = IMon::BAD; s = imon.express(name(), NULL); if (s != IMon::OK) { return true; } // Insert on new chain. Interest **ipp = hashchain(); hashlink = *ipp; *ipp = this; } else { hashlink = NULL; } return false;}/* Returns true if file changed since last stat */boolInterest::do_stat(){ // Consider the case of a Directory changing into a file to be a // simple change, and send only a Changed event. struct stat status; int rc = lstat(name(), &status); if (rc < 0) { if (errno == ETIMEDOUT) { return false; } memset(&status, 0, sizeof status); } bool exists = status.st_mode != 0; bool did_exist = old_stat.st_mode != 0;#ifdef HAVE_STAT_ST_CTIM_TV_NSEC bool stat_changed = (old_stat.st_ctim.tv_sec != status.st_ctim.tv_sec) || (old_stat.st_ctim.tv_nsec != status.st_ctim.tv_nsec) || (old_stat.st_mtim.tv_sec != status.st_mtim.tv_sec) || (old_stat.st_mtim.tv_nsec != status.st_mtim.tv_nsec) ||#else bool stat_changed = (old_stat.st_ctime != status.st_ctime) || (old_stat.st_mtime != status.st_mtime) ||#endif (old_stat.st_mode != status.st_mode) || (old_stat.st_uid != status.st_uid) || (old_stat.st_gid != status.st_gid) || (old_stat.st_size != status.st_size) || (old_stat.st_ino != status.st_ino); old_stat = status; // If dev/ino changed, move this interest to the right hash chain. bool keep_polling = false; if (status.st_dev != dev || status.st_ino != ino) { keep_polling = dev_ino(status.st_dev, status.st_ino); } if (exists && !did_exist) { post_event(Event::Created); if (!keep_polling) { notify_created(this); } } else if (did_exist && !exists) { post_event(Event::Deleted); notify_deleted(this); } return stat_changed;}boolInterest::do_scan(){ bool stat_changed = false; if (needs_scan() && active()) { needs_scan(false); bool did_exist = exists(); stat_changed = do_stat(); if (stat_changed && did_exist && exists()) post_event(Event::Changed); report_exec_state(); } return stat_changed;}voidInterest::report_exec_state(){ if (old_exec_state != cur_exec_state && active()) { post_event(cur_exec_state == EXECUTING ? Event::Executing : Event::Exited); old_exec_state = cur_exec_state; }}voidInterest::imon_handler(dev_t device, ino_t inumber, int event){ assert(device || inumber); for (Interest *p = *hashchain(device, inumber), *next = p; p; p = next) { next = p->hashlink; if (p->ino == inumber && p->dev == device) { if (event == IMon::EXEC) { p->cur_exec_state = EXECUTING; (void) p->report_exec_state(); } else if (event == IMon::EXIT) { p->cur_exec_state = NOT_EXECUTING; (void) p->report_exec_state(); } else { assert(event == IMon::CHANGE); p->scan(); } } }}voidInterest::enable_xtab_verification(bool enable){#ifdef HAVE_IRIX_XTAB_VERIFICATION xtab_verification = enable; Log::info("%s xtab verification of remote requests", enable ? "Enabling" : "Disabling");#endif}// This determines whether this Interest falls on a filesystem which is// exported to the host from which the request originated, and sets// mypath_exported_to_host accordingly.voidInterest::verify_exported_to_host(){#ifdef HAVE_IRIX_XTAB_VERIFICATION // This sets mypath_exported_to_host by checking /etc/xtab and seeing // whether the export entry has an access list; if it does, we see // whether each entry in the list is a netgroup-containing-the- // requesting-host or the-requesting-host-itself. if ((!xtab_verification) || (myhost.s_addr == htonl(INADDR_LOOPBACK))) { mypath_exported_to_host = true; return; } mypath_exported_to_host = false; // Check the xtab for the list of exported filesystems. If this // Interest is located on a filesystem which has been exported to the // Interest's host, set mypath_exported_to_host to true. Log::debug("XTAB: checking requested interest %s, dev/ino %d/%d, " "from host %s", name(), dev, ino, inet_ntoa(myhost)); // This is a little bogus... if we don't have a dev or ino, we're not // going to find a matching exported filesystem, so let's bail. if (!dev && !ino) { Log::debug("XTAB: returning false for dev/ino %d/%d", dev, ino); return; } Cred::SuperUser.become_user(); // setexportent fails if you're not root?? exportent *xent; FILE *xtab = setexportent(); if (xtab == NULL) { Log::perror("setexportent"); return; } while ((xent = getexportent(xtab)) != NULL) { // See if the Interest falls under this export entry. char *xent_path = xent->xent_dirname; int xent_pathlen = strlen(xent_path); if (xent_path[xent_pathlen - 1] == '/') --xent_pathlen; if ((xent_pathlen == 0) || // xent_path was "/" ((strncmp(xent_path, name(), xent_pathlen) == 0) && ((name()[xent_pathlen] == '/') || // so /usr doesn't (name()[xent_pathlen] == '\0')))) // match /usrbooboo { // This export entry is somewhere above the requested directory. // If it has the same device number, this is the entry we want. struct stat sb;//need to set cred here? if (stat(xent_path, &sb) == -1) {//only log if errno != EACCES or ENOENT? Log::perror("stat(%s)", name()); continue; } if (sb.st_dev == dev) break; // yippee // Are there other cases we need to handle? Child filesystems // exported -nohide still need to be exported, and we'll keep // going until we find them. } } endexportent(xtab); // Note that we're still using memory returned by // getexportent(). if (xent == NULL) { // no matching xtab entry. Log::info("Found no matching xtab entry for remote request from %s " "for %s", inet_ntoa(myhost), name()); return; } Log::debug("XTAB: %s is on xent %s", name(), xent->xent_dirname); char *xopt; if ((xopt = getexportopt(xent, ACCESS_OPT)) == NULL) { // This is exported to all clients, so we're OK. Log::debug("XTAB: no access list for %s, so remote request was " "granted", xent->xent_dirname); mypath_exported_to_host = true; return; } hostent *hent = gethostbyaddr(&myhost, sizeof(in_addr), AF_INET); if (hent == NULL) { Log::perror("gethostbyaddr(%s)", inet_ntoa(myhost)); return; } // This export entry has a list of netgroups and/or hosts which are // allowed access. Run through the list & see if our host is there. char *cs = xopt, *ce; while ((!mypath_exported_to_host) && (cs != NULL) && (*cs != '\0')) { ce = strchr(cs, ':'); if (ce != NULL) *ce = '\0'; // See if this client is a netgroup containing myhost. Log::debug("XTAB: seeing if %s is a netgroup containing host %s", cs, hent->h_name); if (innetgr(cs, hent->h_name, NULL, NULL)) { mypath_exported_to_host = true; break; } // See if this client is a netgroup containing one of myhost's aliases. for (int ai = 0; hent->h_aliases[ai] != NULL; ++ai) { Log::debug("XTAB: seeing if %s is a netgroup containing host " "alias %s", cs, hent->h_aliases[ai]); if (innetgr(cs, hent->h_aliases[ai], NULL, NULL)) { mypath_exported_to_host = true; break; } } if (mypath_exported_to_host) break; // See if this client is a host. Log::debug("XTAB: seeing if %s is a host with the address %s", cs, inet_ntoa(myhost)); hostent *chent = gethostbyname(cs); if ((chent != NULL) && (chent->h_addrtype == AF_INET) && chent->h_length == sizeof(in_addr)) { for (int i = 0; chent->h_addr_list[i] != NULL; ++i) { if (((in_addr *)(chent->h_addr_list[i]))->s_addr == myhost.s_addr) { // whew. what a pain. mypath_exported_to_host = true; break; } } } if(ce != NULL) cs = ce + 1; else break; } Log::info("XTAB: %s request from %s to monitor %s", mypath_exported_to_host ? "Granted" : "Denied", inet_ntoa(myhost), name()); return;#else // We don't have xtab verification, so this just says we're OK. mypath_exported_to_host = true;#endif // HAVE_IRIX_XTAB_VERIFICATION}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -