static void np_tpool_destroy(Nptpool *tp) { Npsrv *srv = tp->srv; Npwthread *wt, *next; void *retval; int err, i; for(wt = tp->wthreads; wt != NULL; wt = wt->next) { wt->shutdown = 1; } xpthread_cond_broadcast(&tp->reqcond); for (i = 0, wt = tp->wthreads; wt != NULL; wt = next, i++) { next = wt->next; if ((err = pthread_join (wt->thread, &retval))) { np_uerror (err); np_logerr(srv, "%s: join thread %d", tp->name, i); } else if (retval == PTHREAD_CANCELED) { np_logmsg(srv, "%s: join thread %d: cancelled", tp->name, i); } else if (retval != NULL) { np_logmsg(srv, "%s: join thread %d: non-NULL return", tp->name, i); } free (wt); } pthread_cond_destroy (&tp->reqcond); pthread_mutex_destroy (&tp->lock); if (tp->name) free (tp->name); free (tp); }
static Npuser * _alloc_user (Npsrv *srv, struct passwd *pwd) { Npuser *u; if (!(u = malloc (sizeof (*u)))) { np_uerror (ENOMEM); np_logerr (srv, "_alloc_user: %s", pwd->pw_name); goto error; } u->sg = NULL; u->nsg = 0; if (!(u->uname = strdup (pwd->pw_name))) { np_uerror (ENOMEM); np_logerr (srv, "_alloc_user: %s", pwd->pw_name); goto error; } u->uid = pwd->pw_uid; u->gid = pwd->pw_gid; if (u->uid != 0 && _getgrouplist(srv, u) < 0) goto error; pthread_mutex_init (&u->lock, NULL); u->refcount = 0; u->t = time (NULL); u->next = NULL; if (srv->flags & SRV_FLAGS_DEBUG_USER) np_logmsg (srv, "user lookup: %d", u->uid); return u; error: if (u) _free_user (u); return NULL; }
static void np_conn_destroy(Npconn *conn) { int n; NP_ASSERT(conn != NULL); NP_ASSERT(conn->refcount == 0); /* issue 83: remove from srv->conns before destroying fidpool */ np_srv_remove_conn (conn->srv, conn); if (conn->fidpool) { if ((n = np_fidpool_destroy(conn->fidpool)) > 0) { np_logmsg (conn->srv, "%s: connection closed with " "%d unclunked fids", np_conn_get_client_id (conn), n); } conn->fidpool = NULL; } if (conn->trans) { np_trans_destroy (conn->trans); conn->trans = NULL; } pthread_mutex_destroy(&conn->lock); pthread_mutex_destroy(&conn->wlock); pthread_cond_destroy(&conn->refcond); free(conn); }
/* Create a fid with initial refcount of 1. */ Npfid * np_fid_create (Npconn *conn, u32 fid) { Npsrv *srv = conn->srv; Npfidpool *pool = conn->fidpool; int hash = fid % pool->size; Npfid *f; xpthread_mutex_lock(&pool->lock); if ((f = _lookup_fid (&pool->htable[hash], fid))) { np_logmsg (srv, "np_fid_create: unclunked fid %d (%s): %d refs", f->fid, srv->get_path ? srv->get_path (f) : "<nil>", f->refcount); if ((srv->flags & SRV_FLAGS_LOOSEFID)) { f->flags |= FID_FLAGS_ZOMBIE; } else { np_uerror (EEXIST); f = NULL; goto done; } } if ((f = _create_fid (conn, fid))) { np_fid_incref (f); _link_fid (&pool->htable[hash], f); } done: xpthread_mutex_unlock(&pool->lock); return f; }
static void _debug_trace (Npsrv *srv, Npfcall *fc) { char s[512]; np_snprintfcall(s, sizeof (s), fc); np_logmsg(srv, "%s", s); }
static void _debug_trace (Npsrv *srv, Npfcall *fc) { if ((srv->flags & SRV_FLAGS_DEBUG_9PTRACE)) { char s[512]; static struct timeval b = { 0, 0 }; struct timeval a, c; np_snprintfcall(s, sizeof (s), fc); if ((srv->flags & SRV_FLAGS_DEBUG_TIMES)) { if (b.tv_sec == 0) (void)gettimeofday(&b, NULL); (void)gettimeofday(&a, NULL); timersub(&a, &b, &c); np_logmsg(srv, "[%lu.%-3lu] %s", c.tv_sec, c.tv_usec/1000, s); } else np_logmsg(srv, "%s", s); } }
/* Create an Npuser struct for a user, without requiring * that user to be in the password/group file. * N.B. gid is assumed to be same as uid. */ static Npuser * _alloc_nouserdb (Npsrv *srv, uid_t uid, char *name) { Npuser *u = NULL; char ustr[32] = "root"; if (name) { if (strcmp (name, "root") != 0) { np_uerror (EPERM); goto error; } uid = 0; } if (uid != 0) snprintf (ustr, sizeof (ustr), "%d", uid); if (!(u = malloc (sizeof (*u)))) { np_uerror (ENOMEM); np_logerr (srv, "_alloc_nouserdb: %s", ustr); goto error; } u->sg = NULL; if (!(u->uname = strdup (ustr))) { np_uerror (ENOMEM); np_logerr (srv, "_alloc_nouserdb: %s", ustr); goto error; } u->uid = uid; u->gid = (gid_t)uid; u->nsg = 1; if (!(u->sg = malloc (sizeof (gid_t) * u->nsg))) { np_uerror (ENOMEM); np_logerr (srv, "_alloc_nouserdb: %s", ustr); goto error; } u->sg[0] = u->gid; pthread_mutex_init (&u->lock, NULL); if (srv->flags & SRV_FLAGS_DEBUG_USER) np_logmsg (srv, "user lookup: %d", u->uid); u->refcount = 0; u->t = time (NULL); u->next = NULL; return u; error: if (u) _free_user (u); return NULL; }
void np_logerr(Npsrv *srv, const char *fmt, ...) { va_list ap; if (srv->logmsg) { char buf[128]; char ebuf[64]; char *s = strerror_r (np_rerror (), ebuf, sizeof (ebuf)); va_start (ap, fmt); vsnprintf (buf, sizeof(buf), fmt, ap); va_end (ap); np_logmsg (srv, "%s: %s", buf, s); } }
static Npuser * _real_lookup_byname (Npsrv *srv, char *uname) { Npuser *u; int err, len; struct passwd pw, *pwd = NULL; char *buf = NULL; if (srv->flags & SRV_FLAGS_NOUSERDB) { if (!(u = _alloc_nouserdb (srv, P9_NONUNAME, uname))) goto error; } else { len= sysconf(_SC_GETPW_R_SIZE_MAX); if (len < 4096) len = 4096; if (!(buf = malloc (len))) { np_uerror (ENOMEM); np_logerr (srv, "uname2user: %s", uname); goto error; } if ((err = getpwnam_r (uname, &pw, buf, len, &pwd)) != 0) { np_uerror (err); np_logerr (srv, "uname2user: %s: getpwnam_r", uname); goto error; } if (!pwd) { np_logmsg (srv, "uname2user: %s lookup failure", uname); np_uerror (EPERM); goto error; } if (!(u = _alloc_user (srv, pwd))) goto error; free (buf); } return u; error: if (buf) free (buf); return NULL; }
static Npuser * _real_lookup_byuid (Npsrv *srv, uid_t uid) { Npuser *u; int err, len; struct passwd pw, *pwd; char *buf = NULL; if (srv->flags & SRV_FLAGS_NOUSERDB) { if (!(u = _alloc_nouserdb (srv, uid, NULL))) goto error; } else { len = sysconf(_SC_GETPW_R_SIZE_MAX); if (len < 4096) len = 4096; if (!(buf = malloc (len))) { np_uerror (ENOMEM); np_logerr (srv, "uid2user"); goto error; } if ((err = getpwuid_r (uid, &pw, buf, len, &pwd)) != 0) { np_uerror (err); np_logerr (srv, "uid2user: unable to lookup %d", uid); goto error; } if (!pwd) { np_logmsg (srv, "uid2user: unable to lookup %d", uid); np_uerror (EPERM); goto error; } if (!(u = _alloc_user (srv, pwd))) goto error; free (buf); } return u; error: if (buf) free (buf); return NULL; }
static Npfid * _destroy_fid (Npfid *f) { Npsrv *srv; Npfid *next; NP_ASSERT(f != NULL); NP_ASSERT(f->magic == FID_MAGIC); srv = f->conn->srv; next = f->next; if (f->refcount > 0 && (srv->flags & SRV_FLAGS_DEBUG_FIDPOOL)) { np_logmsg (srv, "_destroy_fid: fid %d has %d refs", f->fid, f->refcount); } if ((f->type & P9_QTAUTH)) { if (srv->auth && srv->auth->clunk) (*srv->auth->clunk)(f); } else if ((f->type & P9_QTTMP)) { np_ctl_fiddestroy (f); } else { if (srv->fiddestroy) (*srv->fiddestroy)(f); } if (f->user) np_user_decref(f->user); if (f->tpool) np_tpool_decref(f->tpool); if (f->aname) free (f->aname); pthread_mutex_destroy (&f->lock); f->magic = FID_MAGIC_FREED; free(f); return next; }
/* Per-connection read thread. */ static void * np_conn_read_proc(void *a) { Npconn *conn = (Npconn *)a; Npsrv *srv = conn->srv; Npreq *req; Npfcall *fc; pthread_detach(pthread_self()); for (;;) { if (np_trans_recv(conn->trans, &fc, conn->msize) < 0) { np_logerr (srv, "recv error - " "dropping connection to '%s'", conn->client_id); break; } if (!fc) /* EOF */ break; _debug_trace (srv, fc); /* Encapsulate fc in a request and hand to srv worker threads. * In np_req_alloc, req->fid is looked up/initialized. */ req = np_req_alloc(conn, fc); if (!req) { np_logmsg (srv, "out of memory in receive path - " "dropping connection to '%s'", conn->client_id); free (fc); break; } /* Enqueue request for processing by next available worker * thread, except P9_TFLUSH which is handled immediately. */ if (fc->type == P9_TFLUSH) { if (np_flush (req, fc)) { np_req_respond_flush (req); np_req_unref(req); } xpthread_mutex_lock (&srv->lock); srv->tpool->stats.nreqs[P9_TFLUSH]++; xpthread_mutex_unlock (&srv->lock); } else { xpthread_mutex_lock(&srv->lock); np_srv_add_req(srv, req); xpthread_mutex_unlock(&srv->lock); } } /* Just got EOF on read, or some other fatal error for the * connection like out of memory. */ np_conn_flush (conn); xpthread_mutex_lock(&conn->lock); while (conn->refcount > 0) xpthread_cond_wait(&conn->refcond, &conn->lock); xpthread_mutex_unlock(&conn->lock); np_conn_destroy(conn); return NULL; }