📄 sfsuclnt.c
字号:
/* $Id: sfsuclnt.C,v 1.10 2003/02/26 07:13:49 dm Exp $ *//* * * Copyright (C) 2001 David Mazieres (dm@uun.org) * * 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; either version 2, or (at * your option) any later version. * * 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 "classfscli.h"#include "nfstrans.h"#include "nfs3_nonnul.h"#include "getfh3.h"#include "rxx.h"#include "sfs_prot.h"#include "sfsagent.h"#include "parseopt.h"static list<sfsuclnt, &sfsuclnt::link> clist;static rxx devdbrx ("(0x[0-9a-f]+)\\s+(@[\\w\\.,%\\-]+)\\s+([\\w\\-]+)");static voiddevdbcat (int out){ if (!sfsdevdb) { if (char *p = getenv ("SFS_ROOT")) sfsdevdb = strbuf () << p << "/.devdb"; else sfsdevdb = "/sfs/.devdb"; } str devdb; do { devdb = file2str (sfsdevdb); } while (!devdb && errno == ESTALE); if (devdb) write (out, devdb, devdb.len ()); else warn << sfsdevdb << ": " << strerror (errno) << "\n";}sfsuclnt::sfsuclnt () : authlock (false), seqno (0), authno (0), auth (NULL){ clist.insert_head (this);}sfsuclnt::~sfsuclnt (){ clist.remove (this); setauth (0); if (nfsc) nfsc->seteofcb (NULL);}voidsfsuclnt::eof (){ str srvname = sc->path; sc = NULL; nfsc = NULL; sfsc = NULL; nfscbs = NULL; seqno = 0; setauth (0); warn << "EOF from " << srvname << "\n"; delaycb (10, wrap (mkref (this), &sfsuclnt::connect, srvname));}voidsfsuclnt::nfscbdispatch (svccb *sbp){ if (!sbp) { eof (); return; } switch (sbp->proc ()) { case ex_NFSCBPROC3_NULL: case ex_NFSCBPROC3_INVALIDATE: sbp->reply (NULL); break; default: sbp->reject (PROC_UNAVAIL); break; }}voidsfsuclnt::setauth (u_int32_t an){ if (auth) { auth_destroy (auth); if (sfsc) sfsc->call (SFSPROC_LOGOUT, &authno, NULL, aclnt_cb_null); } authno = an; if (authno) auth = authuint_create (authno); else auth = NULL; authlock = false;}voidsfsuclnt::setattrs (u_int32_t proc, void *resp, ref<ex_getattr3res> ap, ex_post_op_attr *poap, aclnt_cb cb, clnt_stat stat){ if (stat) { (*cb) (stat); return; } if (ap->status) {#define seterr(proc, arg, res) \ case proc: \ static_cast<res *> (resp)->set_status (ap->status); switch (proc) { NFS_PROGRAM_3_APPLY_NONULL (seterr); default: panic ("sfsuclnt::setattrs: invalid proc %d\n", proc); }#undef seterr } else { poap->set_present (true); *poap->attributes = *ap->attributes; } getreply (proc, NULL, resp, cb, stat);}voidsfsuclnt::getreply (u_int32_t proc, ptr<nfs_fh3> fhp, void *resp, aclnt_cb cb, clnt_stat stat){ if (stat) { (*cb) (stat); return; } if (proc && !*static_cast<nfsstat3 *> (resp) && fhp) switch (proc) { case NFSPROC3_READ: { ex_read3res *rr = static_cast<ex_read3res *> (resp); //rr->resok->file_attributes.set_present (false); if (!rr->resok->file_attributes.present) { ref<ex_getattr3res> ap (New refcounted<ex_getattr3res>); nfsc->call (NFSPROC3_GETATTR, fhp, ap, wrap (this, &sfsuclnt::setattrs, proc, resp, ap, &rr->resok->file_attributes, cb), auth); return; } } break; case NFSPROC3_WRITE: { ex_write3res *wr = static_cast<ex_write3res *> (resp); //wr->resok->file_wcc.after.set_present (false); if (!wr->resok->file_wcc.after.present) { ref<ex_getattr3res> ap (New refcounted<ex_getattr3res>); nfsc->call (NFSPROC3_GETATTR, fhp, ap, wrap (this, &sfsuclnt::setattrs, proc, resp, ap, &wr->resok->file_wcc.after, cb), auth); return; } } break; default: break; } nfs3_exp_disable (proc, resp); (*cb) (stat);}voidsfsuclnt::call (u_int32_t proc, const void *argp, void *resp, aclnt_cb cb){ nfs3_exp_enable (proc, resp); if (!nfsc) (*cb) (RPC_CANTSEND); else if (proc != NFSPROC3_NULL) nfsc->call (proc, argp, resp, wrap (this, &sfsuclnt::getreply, proc, New refcounted<nfs_fh3> (*static_cast<nfs_fh3 *> (argp)), resp, cb), auth); else nfsc->call (proc, argp, resp, cb, auth);}static ptr<aclnt> agentclnt;static ptr<asrv> agentserv;inline voidreauth (){ for (sfsuclnt *c = clist.first; c; c = clist.next (c)) c->doauth (NULL);}inline stragentname (){ if (progname) return progname; return "classfs-client";}static voidsagent_dispatch (svccb *sbp){ if (!sbp) { agentclnt = NULL; agentserv = NULL; reauth (); return; } switch (sbp->proc ()) { case AGENT_START: reauth (); break; default: sbp->reject (PROC_UNAVAIL); break; }}static ptr<aclnt>cagent (){ if (agentclnt) return agentclnt; str agentsock = getenv ("SFS_AGENTSOCK"); static rxx sockfdre ("^-(\\d+)?$"); int fd; if (agentsock && sockfdre.search (agentsock)) { if (sockfdre[1]) fd = atoi (sockfdre[1]); else fd = 0; if (!isunixsocket (fd)) { warn << "fd specified with '-S' not unix domain socket\n"; return NULL; } } else if (agentsock) { fd = unixsocket_connect (agentsock); if (fd < 0) { warn ("%s: %m\n", agentsock.cstr ()); return NULL; } } else { int sfscdfd = suidgetfd_required ("agent"); ref<axprt_unix> sfscdxprt = axprt_unix::alloc (sfscdfd); ref<aclnt> sfscdclnt = aclnt::alloc (sfscdxprt, agent_prog_1); int32_t res; if (clnt_stat err = sfscdclnt->scall (AGENT_GETAGENT, NULL, &res)) { warn << "sfscd: " << err << "\n"; return NULL; } if (res) { warn << "connecting to agent via sfscd: " << strerror (res) << "\n"; return NULL; } if ((fd = sfscdxprt->recvfd ()) < 0) { warn << "connecting to agent via sfscd: could not get file desriptor\n"; return NULL; } } ref<axprt> x = axprt_stream::alloc (fd); sfs_hostname prog = agentname (); ref<aclnt> c = aclnt::alloc (x, agentctl_prog_1); c->call (AGENTCTL_FORWARD, &prog, NULL, aclnt_cb_null, NULL, NULL, xdr_void); agentclnt = aclnt::alloc (x, agentcb_prog_1); agentserv = asrv::alloc (x, agent_prog_1, wrap (sagent_dispatch)); return agentclnt;}struct authrelay { ref<sfsuclnt> sci; const sfsuclnt::alloccb_t::ptr cb; sfsagent_authinit_arg aiarg; sfsagent_authmore_arg amarg; sfsagent_auth_res ares; sfs_loginarg sarg; sfs_loginres sres; authrelay (ref<sfsuclnt> sci, sfsuclnt::alloccb_t::ptr cb, u_int64_t seqno) : sci (sci), cb (cb) { aiarg.ntries = 0; aiarg.requestor = agentname (); aiarg.authinfo.type = SFS_AUTHINFO; aiarg.authinfo.service = SFS_SFS; sfs_parsepath (sci->sc->path, &aiarg.authinfo.name, &aiarg.authinfo.hostid); aiarg.authinfo.hostid = sci->sc->hostid; aiarg.authinfo.sessid = sci->sc->sessid; aiarg.seqno = seqno; amarg.authinfo = aiarg.authinfo; cagent ()->call (AGENTCB_AUTHINIT, &aiarg, &ares, wrap (this, &authrelay::acb)); } void done (bool ok = false) { if (ok) sci->setauth (*sres.authno); else sci->setauth (0); if (cb) (*cb) (sci, NULL); delete this; } void acb (clnt_stat stat) { if (stat) { warn << "agent: " << stat << "\n"; done (); } else if (!ares.authenticate) { done (); return; } else { sarg.seqno = aiarg.seqno; sarg.certificate = *ares.certificate; sci->sfsc->call (SFSPROC_LOGIN, &sarg, &sres, wrap (this, &authrelay::scb)); } } void scb (clnt_stat stat) { if (stat) { warn << "SFS server: " << stat << "\n"; done (); } else switch (sres.status) { case SFSLOGIN_OK: done (true); break; case SFSLOGIN_MORE: amarg.seqno = aiarg.seqno; amarg.challenge = *sres.resmore; cagent ()->call (AGENTCB_AUTHMORE, &amarg, &ares, wrap (this, &authrelay::acb)); break; case SFSLOGIN_BAD: aiarg.ntries++; aiarg.seqno++; /* cascade */ case SFSLOGIN_AGAIN: cagent ()->call (AGENTCB_AUTHINIT, &aiarg, &ares, wrap (this, &authrelay::acb)); break; default: done (); break; } }};voidsfsuclnt::doauth (sfsuclnt::alloccb_t::ptr cb){ if (authlock) return; if (!cagent ()) return; authlock = true; vNew authrelay (mkref (this), cb, seqno++);}voidsfsuclnt::connect_1 (sfsuclnt::alloccb_t::ptr cb, ptr<sfscon> c, str err){ if (!c) { (*cb) (NULL, err); return; } sc = c; nfsc = aclnt::alloc (sc->x, ex_nfs_program_3); sfsc = aclnt::alloc (sc->x, sfs_program_1); nfscbs = asrv::alloc (sc->x, ex_nfscb_program_3, wrap (this, &sfsuclnt::nfscbdispatch)); if (!cb) warn << "reconnected to " << sc->path << "\n"; doauth (cb);}voidsfsuclnt::connect (str srvname){ sfs_connect_path (srvname, SFS_SFS, wrap (mkref (this), &sfsuclnt::connect_1, alloccb_t::ptr (NULL)));}voidsfsuclnt::alloc_2 (u_int64_t devno, sfsuclnt::alloccb_t cb, str devdb) { if (!devdb) { (*cb) (NULL, "could not read " << sfsdevdb); return; } u_int64_t d2; strbuf sb; sb << devdb; while (str line = suio_getline (sb.tosuio ())) if (devdbrx.match (line) && convertint (devdbrx[1], &d2) && d2 == devno) { sfs_connect_path (devdbrx[2], SFS_SFS, wrap (mkref (this), &sfsuclnt::connect_1, cb)); return; } (*cb) (NULL, "could not find device in " << sfsdevdb);}voidsfsuclnt::alloc_1 (str path, sfsuclnt::alloccb_t cb, u_int64_t devno, str srvname, str rpath){ if (!srvname) { (*cb) (NULL, path << ": pathinfo failed"); return; } chldrun (wrap (devdbcat), wrap (mkref (this), &sfsuclnt::alloc_2, devno, cb));}inline boolhexconv (int &out, const char in){ if (in >= '0' && in <= '9') out = in - '0'; else if (in >= 'a' && in <= 'f') out = in - ('a' - 10); else if (in >= 'A' && in <= 'F') out = in - ('A' - 10); else return false; return true;}template<size_t max> inline boola2bytes (rpc_bytes<max> &b, str a){ int i = 0; b.setsize (a.len () / 2); for (const char *p = a.cstr (), *e = p + a.len (); p < e; p += 2) { int h, l; if (!hexconv (h, p[0]) || !hexconv (l, p[1])) return false; b[i++] = h << 4 | l; } return true;} voidsfsuclnt::alloc (str path, sfsuclnt::alloccb_t cb){ ref<sfsuclnt> sci (New refcounted<sfsuclnt>); char buf[65]; str fhpath = path << "/.SFS \177FH"; int n = readlink (fhpath, buf, sizeof (buf) - 1); if (n < 0 || n & 1 || !a2bytes (sci->rootfh.data, str (buf, n))) { (*cb) (NULL, path << ": not an SFS file system"); return; } pathinfofetch (NULL, path, wrap (sci, &sfsuclnt::alloc_1, path, cb));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -