str trunc_at_first_null (const str &s) { assert (s); const char *cp; size_t len = s.len (); size_t l; const char nullc = '\0'; // Figure out if a '\0' or the end-of-string comes first. for (cp = s.cstr (), l = 0; *cp != nullc && l < len; cp++, l++); str ret; if (*cp == nullc) { // The most likely outcome if (l == len) ret = s; // There was a '\0' inside the string else ret = s.cstr (); } else { // String is not null terminated! mstr m (len + 1); memcpy (m.cstr (), s.cstr (), len); m[len] = nullc; ret = m; } return ret; }
void dhblock_keyhash_srv::real_store (chordID key, str od, str nd, u_int32_t exp, cb_dhstat cb) { u_int32_t v1 = dhblock_keyhash::version (nd.cstr (), nd.len ()); if (od.len ()) { u_int32_t v0 = dhblock_keyhash::version (od.cstr (), od.len ()); if (v0 > v1) { chordID p = node->my_pred ()->id (); chordID m = node->my_ID (); if (betweenrightincl (p, m, key)) cb (DHASH_STALE); else cb (DHASH_RETRY); } else { info << "db delete: " << key << "\n"; db->remove (key, v0, wrap (this, &dhblock_keyhash_srv::delete_cb, key, nd, v1, exp, cb)); } } else { info << "db write: " << node->my_ID () << " N " << key << " " << nd.len () << "\n"; db_store (key, nd, v1, exp, cb); } }
wide_str_t::wide_str_t (str utf8_in) { if (utf8_in) { _init (utf8_in.len ()); mbstate_t state; memset (&state, 0, sizeof (state)); const char *src = utf8_in.cstr (); setlocale (LC_CTYPE, "en_US.UTF-8"); ssize_t ret = mbstowcs (_buf->base (), src, _buf->size ()); if (ret < 0) { _err = true; _buf = NULL; _len = 0; } else { _len = ret; if (0 && src) { warn << "XX failed to completely convert string ('" << utf8_in << "'): " << "expected " << _len << " bytes, but only converted " << (src - utf8_in.cstr ()) << "\n"; _err = true; } else { _err = false; } } } }
bool can_read (const str &f) { struct stat sb; return (f && stat(f.cstr (), &sb) == 0 && S_ISREG (sb.st_mode) && access (f.cstr(), R_OK) == 0); }
/* If the directory specified by path does not exist, create it with * the given mode. If we fail for any reason, terminate with error. */ void mksfsdir (str path, mode_t mode, struct stat *sbp, uid_t uid) { assert (path[0] == '/'); mode_t m = umask (0); struct stat sb; if (stat (path, &sb) < 0) { if (errno != ENOENT || (mkdir (path, mode) < 0 && errno != EEXIST)) fatal ("%s: %m\n", path.cstr ()); if (chown (path, uid, sfs_gid) < 0) { int saved_errno = errno; rmdir (path); fatal ("chown (%s): %s\n", path.cstr (), strerror (saved_errno)); } if (stat (path, &sb) < 0) fatal ("stat (%s): %m\n", path.cstr ()); } umask (m); if (!S_ISDIR (sb.st_mode)) fatal ("%s: not a directory\n", path.cstr ()); if (sb.st_uid != uid) fwarn << path << ": owned by uid " << sb.st_uid << ", should be uid " << uid << "\n"; if (sb.st_gid != sfs_gid) fwarn << path << ": has gid " << sb.st_gid << ", should be gid " << sfs_gid << "\n"; if (sb.st_mode & 07777 & ~mode) fwarn ("%s: mode 0%o, should be 0%o\n", path.cstr (), int (sb.st_mode & 07777), int (mode)); if (sbp) *sbp = sb; }
int suidgetfd_required (str prog) { int fds[2]; if (socketpair (AF_UNIX, SOCK_STREAM, 0, fds) < 0) fatal ("socketpair: %m\n"); close_on_exec (fds[0]); str path = fix_exec_path ("suidconnect"); char *av[] = { "suidconnect", const_cast<char *> (prog.cstr ()), NULL }; if (spawn (path, av, fds[1]) == -1) fatal << path << ": " << strerror (errno) << "\n"; close (fds[1]); int fd = recvfd (fds[0]); if (fd < 0) { struct stat sb; if (!runinplace && !stat (path, &sb) && (sb.st_gid != sfs_gid || !(sb.st_mode & 02000))) { if (struct group *gr = getgrgid (sfs_gid)) warn << path << " should be setgid to group " << gr->gr_name << "\n"; else warn << path << " should be setgid to group " << sfs_gid << "\n"; } else { warn << "have you launched the appropriate daemon (sfscd or sfssd)?\n"; warn << "have subsidiary daemons died (check your system logs)?\n"; } fatal ("could not suidconnect for %s\n", prog.cstr ()); } close (fds[0]); return fd; }
static void idlookup (str uid, str gid) { if (!uid) uid = "sfs"; if (!gid) gid = uid; bool uidok = convertint (uid, &sfs_uid); struct passwd *pw = uidok ? getpwuid (sfs_uid) : getpwnam (uid.cstr ()); bool gidok = convertint (gid, &sfs_gid); struct group *gr = gidok ? getgrgid (sfs_gid) : getgrnam (gid.cstr ()); if (!uidok) { if (!pw) fatal << "Could not find user " << uid << "\n"; sfs_uid = pw->pw_uid; } if (!gidok) { if (!gr) fatal << "Could not find group " << gid << "\n"; sfs_gid = gr->gr_gid; } if (gr && gr->gr_mem[0]) fwarn << "Group " << gid << " must not have any members\n"; if (pw && gr && (gid_t) pw->pw_gid != (gid_t) gr->gr_gid) fwarn << "User " << uid << " must have login group " << gid << ".\n"; endpwent (); endgrent (); }
bool isdir (const str &d) { struct stat sb; return (!stat (d.cstr(), &sb) && (sb.st_mode & S_IFDIR) && !access (d.cstr(), X_OK|R_OK)); }
inline str group_prefix (str s, str prefix) { if (s.len () <= prefix.len () || s[prefix.len ()] != '.' || memcmp (s.cstr (), prefix.cstr (), prefix.len ())) return NULL; return substr (s, prefix.len () + 1); }
str can_exec (const str &p) { if (access (p.cstr (), R_OK)) return ("cannot read executable"); else if (access (p.cstr (), X_OK)) return ("cannot execute"); return NULL; }
u_int count_newlines (str s) { const char *end = s.cstr () + s.len (); u_int c = 0; for (const char *cp = s.cstr (); cp < end; cp++) { if (*cp == '\n') c++; } return c; }
void suio_print (suio *uio, const str &s) { if (s.len () <= suio::smallbufsize) uio->copy (s.cstr (), s.len ()); else { uio->print (s.cstr (), s.len ()); uio->iovcb (wrap (&s.b.Xplug, s.b.Xleak ())); } }
str trunc_after_null_byte (str s) { str ret; size_t l; if (!s) { ret = s; } else if ((l = strlen (s.cstr())) == s.len ()) { ret = s; } else { ret = str (s.cstr (), l); } return ret; }
void random_set_seedfile (str path) { if (!path) { if (seed) { munmap (reinterpret_cast<char *> (seed), mapsize); seed = NULL; } return; } if (path[0] == '~' && path[1] == '/') { const char *home = getenv ("HOME"); if (!home) { warn ("$HOME not set in environment\n"); return; } path = strbuf () << home << (path.cstr () + 1); } int fd = open (path, O_CREAT|O_RDWR, 0600); if (fd < 0) { warn ("%s: %m\n", path.cstr ()); return; } struct stat sb; char c; if (read (fd, &c, 1) < 0 || fstat (fd, &sb) < 0 || lseek (fd, mapsize - 1, SEEK_SET) == -1 || write (fd, "", 1) < 0) { /* The read call avoids a segfault on NFS 2. Specifically, if we * are root and the random_seed file is over NFS 2, the open will * succeed even though read returns EACCES. If we map the file * when we can't read it--bingo, segfault. (In fact, on some OSes * it also seems to cause a kernel panic when you examine the * mmapped memory from the debugger.) */ close (fd); warn ("%s: %m\n", path.cstr ()); return; } if ((sb.st_mode & 07777) != 0600) warn ("%s: mode 0%o should be 0600\n", path.cstr (), sb.st_mode & 07777); if (seed) munmap (reinterpret_cast<char *> (seed), mapsize); seed = mmap (NULL, (size_t) mapsize, PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, fd, 0); if (seed == reinterpret_cast<void *> (MAP_FAILED)) { warn ("mmap: %s: %m\n", path.cstr ()); seed = NULL; } else rnd_input.update (seed, seedsize); close (fd); }
int open_file (const str &nm, int flags) { char *s = strdup (nm.cstr ()); int rc = 0; rc = mkdir_p (s); if (rc == 0) rc = ::open (nm.cstr (), flags, 0666); if (s) free (s); return rc; }
int start_logger (const str &priority, const str &tag, const str &line, const str &logfile, int flags, mode_t mode) { str logger; #ifdef PATH_LOGGER logger = PATH_LOGGER; #endif if (logger) { const char *av[] = { NULL, "-p", NULL, "-t", NULL, NULL, NULL }; av[0] = const_cast<char *> (logger.cstr ()); av[2] = const_cast<char *> (priority.cstr ()); if (line) av[5] = const_cast<char *> (line.cstr ()); else av[5] = "log started"; if (tag) av[4] = const_cast<char *> (tag.cstr ()); else av[4] = ""; pid_t pid; int status; if ((pid = spawn (av[0], av, 0, 0, errfd)) < 0) { warn ("%s: %m\n", logger.cstr ()); return start_log_to_file (line, logfile, flags, mode); } if (waitpid (pid, &status, 0) <= 0 || !WIFEXITED (status) || WEXITSTATUS (status)) return start_log_to_file (line, logfile, flags, mode); int fds[2]; if (socketpair (AF_UNIX, SOCK_STREAM, 0, fds) < 0) fatal ("socketpair: %m\n"); close_on_exec (fds[0]); if (fds[1] != 0) close_on_exec (fds[1]); av[5] = NULL; if (spawn (av[0], av, fds[1], 0, 0) >= 0) { close (fds[1]); return fds[0]; } else { warn ("%s: %m\n", logger.cstr ()); } } return start_log_to_file (line, logfile, flags, mode); }
static str makehdrname (str fname) { strbuf hdr; const char *p; if ((p = strrchr (fname.cstr(), '/'))) p++; else p = fname.cstr(); hdr.buf (p, strlen (p) - 1); hdr.cat ("h"); return hdr; }
void dhashclient::retrieve (bigint key, dhash_ctype ct, cb_cret cb, str& data, ptr<option_block> options) { ref<dhash_retrieve_res> res = New refcounted<dhash_retrieve_res> (DHASH_OK); dhash_retrieve_arg arg; arg.blockID = key; arg.ctype = ct; arg.options = 0; if (options) { arg.options = options->flags; if (options->flags & DHASHCLIENT_GUESS_SUPPLIED) { arg.guess = options->guess; //warn << "starting with guess: " << arg.guess << "\n"; //warn << "using guess\n"; } } // Praveen if (data.len()) { arg.data.setsize (data.len()); memcpy (arg.data.base (), data.cstr(), data.len()); } gwclnt->call (DHASHPROC_RETRIEVE, &arg, res, wrap (this, &dhashclient::retrievecb, cb, key, res)); }
bool basename_dirname (const str &in, str *d, str *b) { size_t l = in.len (); if (l == 0) { *d = *b = NULL; return false; } bool ret = (in[0] == '/'); const char *bp = in.cstr (); const char *ep = bp + l - 1; const char *p; for ( p = ep; p >= bp && *p != '/'; p--) ; // Set the basename if possible if (p == ep) { *b = NULL; } else { *b = str (p + 1); } // if there were multiple slashes keep backing up for ( ; p >= bp && *p == '/' ; p-- ); if (p >= bp) { assert (*p != '/'); *d = str (bp, p - bp + 1); } else { *d = NULL; } return ret; }
bool repl_t::parse (str in) { const char *bp = in.cstr (); const char *ep = bp + in.len (); const char *last = bp; size_t inc = 1; for (const char *p = bp; p < ep; p += inc) { bool is_dig = false; inc = 1; if (p == ep - 1 || *p != '$') { /* noop */ } else if (p[1] == '$' || (is_dig = (isdigit (p[1])))) { add_str (bp, last, p, ep); inc = 2; if (is_dig) { add_capture (p[1] - '0'); last = p + 2; } else { last = p + 1; } } } add_str (bp, last, ep, ep); return true; }
void json_XDR_t::error_wrong_type (str s, ptr<const pub3::expr_t> x) { str got = x->type_to_str (); strbuf msg ("got type %s; expected %s", got.cstr (), s.cstr ()); error_generic (msg); }
str html_wss (str in) { if (!in) return in; mstr out (in.len ()); char *op = out.cstr (); const char *ip = in.cstr (); const char *ep = ip + in.len (); bool eat_ws_state = false; for ( ; ip < ep; ip++) { if (isspace (*ip)) { if (!eat_ws_state) { eat_ws_state = true; } } else { if (eat_ws_state) { *op++ = ' '; eat_ws_state = false; } *op++ = *ip; } } if (eat_ws_state) { *op++ = ' '; } out.setlen (op - out.cstr ()); return out; }
static str pathexpand (str lookup, str *sch, int recdepth = 0) { char readlinkbuf [PATH_MAX + 1]; str s; struct stat sb; while (1) { // warn << print_indent (recdepth) << "looking up " << lookup << "\n"; stat (lookup.cstr (), &sb); errno = 0; if ((s = slashsfs2sch (lookup))) { // warn << print_indent (recdepth) << "--------FOUND-----: " // << s << "\n"; *sch = s; return lookup; } else { int len = readlink (lookup, readlinkbuf, PATH_MAX); if (len < 0) { // warn << print_indent (recdepth) << "readlink of " // << lookup << " returned error: " << strerror (errno) << "\n"; return lookup; } readlinkbuf[len] = 0; // warn << print_indent (recdepth) << "readlink of " << lookup // << " returned " << readlinkbuf << "\n"; lookup = mk_readlinkres_abs (readlinkbuf, lookup); } } }
str fix_exec_path (str path, str dir) { const char *prog = strrchr (path, '/'); if (prog) return path; if (!dir) dir = execdir; path = dir << "/" << path; prog = strrchr (path, '/'); if (!prog) panic ("No EXECDIR for unqualified path %s.\n", path.cstr ()); #ifdef MAINTAINER if (builddir && dir == execdir) { str np; np = builddir << prog; if (execok (np)) return np; np = builddir << prog << prog; if (execok (np)) return np; if (np = searchdir (builddir, prog)) return np; if (np = searchdir (builddir << "/lib", prog)) return np; } #endif /* MAINTAINER */ return path; }
void dumpable_t::s_dump (dumper_t *d, str prfx, const dumpable_t *obj) { if (prfx) { d->dump (strbuf ("%s ", prfx.cstr ()), false); } if (obj) { obj->dump (d); } else { d->dump ("(null)", true); } }
// // write out the data 's' to the file given by _file. Might need to make // some parent directories if the filename contains slashes. // // return -1 if failure, and 0 if wrote the file out OK. // int write_file (const str &nm, const str &dat, bool do_fsync) { char *s = strdup (nm.cstr ()); int rc = 0; rc = mkdir_p (s); if (rc == 0 && !my_str2file (nm, dat, 0666, do_fsync)) { warn ("cannot create file %s: %m\n", nm.cstr ()); rc = -1; } else { rc = 0; } if (s) free (s); return rc; }
void ssl_complain (const str &s) { if (s) BIO_printf (_bio_err, "%s", s.cstr ()); ERR_print_errors (_bio_err); fflush (stderr); }
str apply_container_dir (const str &d, const str &f) { if (f[0] == '/' || !d) return re_fslash (f.cstr ()); else return (strbuf (d) << "/" << f); }
void acl::fix_aclstr (str s, char *buf) { char sbuf[ACLSIZE]; int min = (ACLSIZE > s.len ()) ? s.len () : ACLSIZE; bzero (buf, ACLSIZE); bzero (sbuf, ACLSIZE); memcpy (sbuf, s.cstr (), min); str aclend (ENDACL "\n"); int tail = aclend.len (); char *c = strstr (sbuf, ENDACL); int p = c ? c - sbuf : 0; int total = p ? p + tail : s.len () + tail; if (!p) warn << "ACLEND not found in ACL \n"; if (total <= ACLSIZE) { memcpy (buf, s.cstr (), p); memcpy (buf + p, aclend.cstr (), aclend.len ()); return; } if (total > ACLSIZE) { if (p) warn << "ACLEND found at position " << p << "\n"; else warn << "ACLEND not found in ACL \n"; warn << "ACL does not fit in buffer. Truncating \n"; if ( p && p < (ACLSIZE - tail)) { warn << "Removing garbage after ACLEND \n"; memcpy (buf, s.cstr (), p); memcpy (buf + p, aclend.cstr (), aclend.len ()); return; } else { memcpy (buf, s.cstr (), ACLSIZE - tail); memcpy (buf + ACLSIZE - tail, aclend.cstr (), tail); return; } } }
bool siglog (const str &line) { if (!line) return false; int n = write (logfd, line.cstr (), line.len ()); if (n < int (line.len ())) return false; return true; }