/* Trename - rename a file, potentially to another directory */ Npfcall* diod_rename (Npfid *fid, Npfid *dfid, Npstr *name) { Npsrv *srv = fid->conn->srv; Fid *f = fid->aux; Fid *d = dfid->aux; Npfcall *ret; Path npath = NULL; int renamed = 0; if ((f->flags & DIOD_FID_FLAGS_ROFS)) { np_uerror (EROFS); goto error_quiet; } if (!(npath = path_append (srv, d->path, name))) { np_uerror (ENOMEM); goto error; } if (rename (path_s (f->path), path_s (npath)) < 0) { np_uerror (errno); goto error_quiet; } renamed = 1; if (!(ret = np_create_rrename ())) { np_uerror (ENOMEM); goto error; } path_decref (srv, f->path); f->path = npath; return ret; error: errn (np_rerror (), "diod_rename %s@%s:%s to %s/%.*s", fid->user->uname, np_conn_get_client_id (fid->conn), path_s (f->path), path_s (d->path), name->len, name->str); error_quiet: if (renamed && npath) (void)rename (path_s (npath), path_s (f->path)); if (npath) path_decref (srv, npath); return NULL; }
Npfcall* diod_link (Npfid *dfid, Npfid *fid, Npstr *name) { Fid *f = fid->aux; Npfcall *ret = NULL; Fid *df = dfid->aux; char *npath = NULL; int created = 0; if ((f->xflags & XFLAGS_RO)) { np_uerror (EROFS); goto error_quiet; } if (!(npath = _mkpath(df->path, name))) { np_uerror (ENOMEM); goto error; } if (link (f->path, npath) < 0) { np_uerror (errno); goto error_quiet; } created = 1; if (!((ret = np_create_rlink ()))) { np_uerror (ENOMEM); goto error; } free (npath); return ret; error: errn (np_rerror (), "diod_link %s@%s:%s %s/%.*s", fid->user->uname, np_conn_get_client_id (fid->conn), f->path, df->path, name->len, name->str); error_quiet: if (created && npath) (void)unlink (npath); if (npath) free (npath); if (ret) free (ret); return NULL; }
/* Twalk - walk a file path * Called from fcall.c::np_walk () to clone the fid. * On error, call np_uerror () and return 0. */ int diod_clone (Npfid *fid, Npfid *newfid) { Fid *f = fid->aux; Fid *nf = NULL; if (!(nf = _fidalloc ()) || !(nf->path = strdup (f->path))) { np_uerror (ENOMEM); goto error; } nf->xflags = f->xflags; nf->mountpt = f->mountpt; newfid->aux = nf; return 1; error: errn (np_rerror (), "diod_clone %s@%s:%s", fid->user->uname, np_conn_get_client_id (fid->conn), f->path); if (nf) _fidfree (nf); return 0; }
/* Twalk - walk a file path * Called from fcall.c::np_walk () on each wname component in succession. * On error, call np_uerror () and return 0. */ int diod_walk (Npfid *fid, Npstr* wname, Npqid *wqid) { Fid *f = fid->aux; struct stat st; char *npath; if (!(npath = _mkpath (f->path, wname))) { np_uerror (ENOMEM); goto error; } if (lstat (npath, &st) < 0) { np_uerror (errno); goto error_quiet; } /* N.B. inodes would not be unique if we could cross over to another * file system. But with the code below, ls -l returns ??? for mount * point dirs, which would otherwise have a "foreign" inode number. * How does NFS make them appear as empty directories? That would be * prettier. */ if (_fidstat (f) < 0) goto error; if (st.st_dev != f->stat.st_dev) { np_uerror (EXDEV); goto error; } free (f->path); f->path = npath; _ustat2qid (&st, wqid); return 1; error: errn (np_rerror (), "diod_walk %s@%s:%s/%.*s", fid->user->uname, np_conn_get_client_id (fid->conn), f->path, wname->len, wname->str); error_quiet: if (npath) free (npath); return 0; }
/* Tattach - attach a new user (fid->user) to aname. * diod_auth.c::diod_checkauth first authenticates/authorizes user */ Npfcall* diod_attach (Npfid *fid, Npfid *afid, Npstr *aname) { Npfcall* ret = NULL; Fid *f = NULL; Npqid qid; if (aname->len == 0 || *aname->str != '/') { np_uerror (EPERM); goto error; } if (!(f = _fidalloc ()) || !(f->path = np_strdup (aname))) { np_uerror (ENOMEM); goto error; } if (diod_conf_opt_runasuid ()) { if (fid->user->uid != diod_conf_get_runasuid ()) { np_uerror (EPERM); goto error; } } if (!diod_match_exports (f->path, fid->conn, fid->user, &f->xflags)) goto error; if (_fidstat (f) < 0) goto error; _ustat2qid (&f->stat, &qid); if ((ret = np_create_rattach (&qid)) == NULL) { np_uerror (ENOMEM); goto error; } fid->aux = f; np_fid_incref (fid); return ret; error: errn (np_rerror (), "diod_attach %s@%s:%.*s", fid->user->uname, np_conn_get_client_id (fid->conn), aname->len, aname->str); if (f) _fidfree (f); return NULL; }
Npfcall* diod_mknod(Npfid *fid, Npstr *name, u32 mode, u32 major, u32 minor, u32 gid) { Npsrv *srv = fid->conn->srv; Npfcall *ret; Fid *f = fid->aux; Path npath = NULL; Npqid qid; struct stat sb; if ((f->flags & DIOD_FID_FLAGS_ROFS)) { np_uerror (EROFS); goto error_quiet; } if (!(npath = path_append (srv, f->path, name))) { np_uerror (ENOMEM); goto error; } if (mknod (path_s (npath), mode, makedev (major, minor)) < 0 || lstat (path_s (npath), &sb) < 0) { np_uerror (errno); goto error_quiet; } diod_ustat2qid (&sb, &qid); if (!((ret = np_create_rmknod (&qid)))) { (void)unlink (path_s (npath)); np_uerror (ENOMEM); goto error; } path_decref (srv, npath); return ret; error: errn (np_rerror (), "diod_mknod %s@%s:%s/%.*s", fid->user->uname, np_conn_get_client_id (fid->conn), path_s (f->path), name->len, name->str); error_quiet: if (npath) path_decref (srv, npath); return NULL; }
/* Trename - rename a file, potentially to another directory */ Npfcall* diod_rename (Npfid *fid, Npfid *dfid, Npstr *name) { Fid *f = fid->aux; Fid *d = dfid->aux; Npfcall *ret; char *npath = NULL; int renamed = 0; if ((f->xflags & XFLAGS_RO)) { np_uerror (EROFS); goto error_quiet; } if (!(npath = _mkpath(d->path, name))) { np_uerror (ENOMEM); goto error; } if (rename (f->path, npath) < 0) { np_uerror (errno); goto error_quiet; } renamed = 1; if (!(ret = np_create_rrename ())) { np_uerror (ENOMEM); goto error; } free (f->path); f->path = npath; return ret; error: errn (np_rerror (), "diod_rename %s@%s:%s to %s/%.*s", fid->user->uname, np_conn_get_client_id (fid->conn), f->path, d->path, name->len, name->str); error_quiet: if (renamed && npath) (void)rename (npath, f->path); if (npath) free (npath); return NULL; }
/* Tclunk - close a file. */ Npfcall* diod_clunk (Npfid *fid) { Fid *f = fid->aux; Npfcall *ret; if (f->ioctx) { if (ioctx_close (fid, 1) < 0) goto error_quiet; } if (!(ret = np_create_rclunk ())) { np_uerror (ENOMEM); goto error; } return ret; error: errn (np_rerror (), "diod_clunk %s@%s:%s", fid->user->uname, np_conn_get_client_id (fid->conn), path_s (f->path)); error_quiet: return NULL; }
Npfcall* diod_mknod(Npfid *fid, Npstr *name, u32 mode, u32 major, u32 minor, u32 gid) { Npfcall *ret; Fid *f = fid->aux; char *npath = NULL; Npqid qid; struct stat sb; if ((f->xflags & XFLAGS_RO)) { np_uerror (EROFS); goto error_quiet; } if (!(npath = _mkpath(f->path, name))) { np_uerror (ENOMEM); goto error; } if (mknod (npath, mode, makedev (major, minor)) < 0 || lstat (npath, &sb) < 0) { np_uerror (errno); goto error_quiet; } _ustat2qid (&sb, &qid); if (!((ret = np_create_rmknod (&qid)))) { (void)unlink (npath); np_uerror (ENOMEM); goto error; } free (npath); return ret; error: errn (np_rerror (), "diod_mknod %s@%s:%s/%.*s", fid->user->uname, np_conn_get_client_id (fid->conn), f->path, name->len, name->str); error_quiet: if (npath) free (npath); return NULL; }
Npfcall* diod_getattr(Npfid *fid, u64 request_mask) { Fid *f = fid->aux; Npfcall *ret = NULL; Npqid qid; if (_fidstat (f) < 0) goto error_quiet; _ustat2qid (&f->stat, &qid); if (!(ret = np_create_rgetattr(request_mask, &qid, f->stat.st_mode, f->stat.st_uid, f->stat.st_gid, f->stat.st_nlink, f->stat.st_rdev, f->stat.st_size, f->stat.st_blksize, f->stat.st_blocks, f->stat.st_atim.tv_sec, f->stat.st_atim.tv_nsec, f->stat.st_mtim.tv_sec, f->stat.st_mtim.tv_nsec, f->stat.st_ctim.tv_sec, f->stat.st_ctim.tv_nsec, 0, 0, 0, 0))) { np_uerror (ENOMEM); goto error; } return ret; error: errn (np_rerror (), "diod_getattr %s@%s:%s", fid->user->uname, np_conn_get_client_id (fid->conn), f->path); error_quiet: if (ret) free (ret); return NULL; }
Npfcall* diod_readdir(Npfid *fid, u64 offset, u32 count, Npreq *req) { int n; Fid *f = fid->aux; Npfcall *ret; if (!(ret = np_create_rreaddir (count))) { np_uerror (ENOMEM); goto error; } n = _read_dir_linux (f, ret->u.rreaddir.data, offset, count); if (np_rerror ()) { free (ret); ret = NULL; } else np_finalize_rreaddir (ret, n); return ret; error: errn (np_rerror (), "diod_readdir %s@%s:%s", fid->user->uname, np_conn_get_client_id (fid->conn), f->path); return NULL; }
Npfcall* diod_link (Npfid *dfid, Npfid *fid, Npstr *name) { Npsrv *srv = fid->conn->srv; Fid *f = fid->aux; Npfcall *ret; Fid *df = dfid->aux; Path npath = NULL; if ((f->flags & DIOD_FID_FLAGS_ROFS)) { np_uerror (EROFS); goto error_quiet; } if (!(npath = path_append (srv, df->path, name))) { np_uerror (ENOMEM); goto error; } if (link (path_s (f->path), path_s (npath)) < 0) { np_uerror (errno); goto error_quiet; } if (!((ret = np_create_rlink ()))) { (void)unlink (path_s (npath)); np_uerror (ENOMEM); goto error; } path_decref (srv, npath); return ret; error: errn (np_rerror (), "diod_link %s@%s:%s %s/%.*s", fid->user->uname, np_conn_get_client_id (fid->conn), path_s (f->path), path_s (df->path), name->len, name->str); error_quiet: if (npath) path_decref (srv, npath); return NULL; }
Npfcall* diod_readlink(Npfid *fid) { Fid *f = fid->aux; Npfcall *ret; char target[PATH_MAX + 1]; int n; if ((n = readlink (f->path, target, sizeof(target) - 1)) < 0) { np_uerror (errno); goto error_quiet; } target[n] = '\0'; if (!(ret = np_create_rreadlink(target))) { np_uerror (ENOMEM); goto error; } return ret; error: errn (np_rerror (), "diod_readlink %s@%s:%s", fid->user->uname, np_conn_get_client_id (fid->conn), f->path); error_quiet: return NULL; }
int main (int argc, char *argv[]) { Npcfsys *fs; Npcfid *afid, *root; uid_t uid = geteuid (); char *aname, *path, *attr, *value; int fd = 0; /* stdin */ diod_log_init (argv[0]); if (argc < 3) usage (); aname = argv[1]; path = argv[2]; attr = argv[3]; value = argv[4]; if (!(fs = npc_start (fd, fd, 65536+24, 0))) errn_exit (np_rerror (), "npc_start"); if (!(afid = npc_auth (fs, aname, uid, diod_auth)) && np_rerror () != 0) errn_exit (np_rerror (), "npc_auth"); if (!(root = npc_attach (fs, afid, aname, uid))) errn_exit (np_rerror (), "npc_attach"); if (afid && npc_clunk (afid) < 0) errn (np_rerror (), "npc_clunk afid"); if (npc_setxattr (root, path, attr, NULL, 0, 0) < 0) errn_exit (np_rerror (), "npc_setxattr"); if (npc_clunk (root) < 0) errn_exit (np_rerror (), "npc_clunk root"); npc_finish (fs); exit (0); }
Npfcall* diod_getlock (Npfid *fid, u8 type, u64 start, u64 length, u32 proc_id, Npstr *client_id) { Fid *f = fid->aux; Npfcall *ret; char *cid = NULL; struct stat sb; if ((f->xflags & XFLAGS_RO)) { np_uerror (EROFS); goto error_quiet; } if (!(cid = np_strdup (client_id))) { np_uerror (ENOMEM); goto error; } if (fstat(f->fd, &sb) < 0) { np_uerror (errno); goto error_quiet; } switch (type) { case P9_LOCK_TYPE_RDLCK: switch (f->lock_type) { case LOCK_EX: case LOCK_SH: type = P9_LOCK_TYPE_UNLCK; break; case LOCK_UN: if (flock (f->fd, LOCK_SH | LOCK_NB) >= 0) { (void)flock (f->fd, LOCK_UN); type = P9_LOCK_TYPE_UNLCK; } else type = P9_LOCK_TYPE_WRLCK; break; } break; case P9_LOCK_TYPE_WRLCK: switch (f->lock_type) { case LOCK_EX: type = P9_LOCK_TYPE_UNLCK; break; case LOCK_SH: /* Rather than upgrade the lock to LOCK_EX and risk * not reacquiring the LOCK_SH afterwards, lie about * the lock being available. Getlock is racy anyway. */ type = P9_LOCK_TYPE_UNLCK; break; case LOCK_UN: if (flock (f->fd, LOCK_EX | LOCK_NB) >= 0) { (void)flock (f->fd, LOCK_UN); type = P9_LOCK_TYPE_UNLCK; } else type = P9_LOCK_TYPE_WRLCK; /* could also be LOCK_SH actually */ } break; default: np_uerror (EINVAL); goto error; } if (type != P9_LOCK_TYPE_UNLCK && type != F_UNLCK) { /* FIXME: need to fake up start, length, proc_id, cid? */ } if (!((ret = np_create_rgetlock(type, start, length, proc_id, cid)))) { np_uerror (ENOMEM); goto error; } free (cid); return ret; error: errn (np_rerror (), "diod_getlock %s@%s:%s", fid->user->uname, np_conn_get_client_id (fid->conn), f->path); error_quiet: if (cid) free (cid); return NULL; }
/* Locking note: * Implement POSIX locks in terms of BSD flock locks. * This at least gets distributed whole-file locking to work. * Strategies for distributed record locking will deadlock. */ Npfcall* diod_lock (Npfid *fid, u8 type, u32 flags, u64 start, u64 length, u32 proc_id, Npstr *client_id) { Fid *f = fid->aux; Npfcall *ret; u8 status = P9_LOCK_ERROR; struct stat sb; if ((f->xflags & XFLAGS_RO)) { np_uerror (EROFS); goto error_quiet; } if (flags & ~P9_LOCK_FLAGS_BLOCK) { /* only one valid flag for now */ np_uerror (EINVAL); /* (which we ignore) */ goto error; } if (fstat(f->fd, &sb) < 0) { np_uerror (errno); goto error_quiet; } switch (type) { case P9_LOCK_TYPE_UNLCK: if (flock (f->fd, LOCK_UN) >= 0) { status = P9_LOCK_SUCCESS; f->lock_type = LOCK_UN; } else status = P9_LOCK_ERROR; break; case P9_LOCK_TYPE_RDLCK: if (flock (f->fd, LOCK_SH | LOCK_NB) >= 0) { status = P9_LOCK_SUCCESS; f->lock_type = LOCK_SH; } else if (errno == EWOULDBLOCK) { status = P9_LOCK_BLOCKED; } else status = P9_LOCK_ERROR; break; case P9_LOCK_TYPE_WRLCK: if (flock (f->fd, LOCK_EX | LOCK_NB) >= 0) { status = P9_LOCK_SUCCESS; f->lock_type = LOCK_EX; } else if (errno == EWOULDBLOCK) { status = P9_LOCK_BLOCKED; } break; default: np_uerror (EINVAL); goto error; } if (!((ret = np_create_rlock (status)))) { np_uerror (ENOMEM); goto error; } return ret; error: errn (np_rerror (), "diod_lock %s@%s:%s", fid->user->uname, np_conn_get_client_id (fid->conn), f->path); error_quiet: return NULL; }
void usage(char *tail) { char *s, *t, c; int count, nflag = 0; switch(reason){ case RESET: errs("Flag -"); errc(badflag); errs(": set twice\n"); break; case FEWARGS: errs("Flag -"); errc(badflag); errs(": too few arguments\n"); break; case FLAGSYN: errs("Bad argument to getflags!\n"); break; case BADFLAG: errs("Illegal flag -"); errc(badflag); errc('\n'); break; } errs("Usage: "); errs(cmdname); for(s = flagarg;*s;){ c=*s; if(*s++==' ') continue; if(*s==':'){ s++; count = 0; while('0'<=*s && *s<='9') count = count*10+*s++-'0'; } else count = 0; if(count==0){ if(nflag==0) errs(" [-"); nflag++; errc(c); } if(*s=='['){ s++; while(*s!=']' && *s!='\0') s++; if(*s==']') s++; } } if(nflag) errs("]"); for(s = flagarg;*s;){ c=*s; if(*s++==' ') continue; if(*s==':'){ s++; count = 0; while('0'<=*s && *s<='9') count = count*10+*s++-'0'; } else count = 0; if(count!=0){ errs(" [-"); errc(c); if(*s=='['){ s++; t = s; while(*s!=']' && *s!='\0') s++; errs(" "); errn(t, s-t); if(*s==']') s++; } else while(count--) errs(" arg"); errs("]"); } else if(*s=='['){ s++; while(*s!=']' && *s!='\0') s++; if(*s==']') s++; } } if(tail){ errs(" "); errs(tail); } errs("\n"); Exit("bad flags"); }
Npfcall* diod_setattr (Npfid *fid, u32 valid, u32 mode, u32 uid, u32 gid, u64 size, u64 atime_sec, u64 atime_nsec, u64 mtime_sec, u64 mtime_nsec) { Npfcall *ret; Fid *f = fid->aux; int ctime_updated = 0; if ((f->xflags & XFLAGS_RO)) { np_uerror (EROFS); goto error_quiet; } if ((valid & P9_SETATTR_MODE)) { /* N.B. derefs symlinks */ if (chmod (f->path, mode) < 0) { np_uerror(errno); goto error_quiet; } ctime_updated = 1; } if ((valid & P9_SETATTR_UID) || (valid & P9_SETATTR_GID)) { if (lchown (f->path, (valid & P9_SETATTR_UID) ? uid : -1, (valid & P9_SETATTR_GID) ? gid : -1) < 0) { np_uerror(errno); goto error_quiet; } ctime_updated = 1; } if ((valid & P9_SETATTR_SIZE)) { if (truncate (f->path, size) < 0) { np_uerror(errno); goto error_quiet; } ctime_updated = 1; } if ((valid & P9_SETATTR_ATIME) || (valid & P9_SETATTR_MTIME)) { #if HAVE_UTIMENSAT struct timespec ts[2]; if (!(valid & P9_SETATTR_ATIME)) { ts[0].tv_sec = 0; ts[0].tv_nsec = UTIME_OMIT; } else if (!(valid & P9_SETATTR_ATIME_SET)) { ts[0].tv_sec = 0; ts[0].tv_nsec = UTIME_NOW; } else { ts[0].tv_sec = atime_sec; ts[0].tv_nsec = atime_nsec; } if (!(valid & P9_SETATTR_MTIME)) { ts[1].tv_sec = 0; ts[1].tv_nsec = UTIME_OMIT; } else if (!(valid & P9_SETATTR_MTIME_SET)) { ts[1].tv_sec = 0; ts[1].tv_nsec = UTIME_NOW; } else { ts[1].tv_sec = mtime_sec; ts[1].tv_nsec = mtime_nsec; } if (utimensat(-1, f->path, ts, AT_SYMLINK_NOFOLLOW) < 0) { np_uerror(errno); goto error_quiet; } #else /* HAVE_UTIMENSAT */ struct timeval tv[2], now, *tvp; struct stat sb; if ((valid & P9_SETATTR_ATIME) && !(valid & P9_SETATTR_ATIME_SET) && (valid & P9_SETATTR_MTIME) && !(valid & P9_SETATTR_MTIME_SET)) { tvp = NULL; /* set both to now */ } else { if (lstat(f->path, &sb) < 0) { np_uerror (errno); goto error_quiet; } if (gettimeofday (&now, NULL) < 0) { np_uerror (errno); goto error_quiet; } if (!(valid & P9_SETATTR_ATIME)) { tv[0].tv_sec = sb.st_atim.tv_sec; tv[0].tv_usec = sb.st_atim.tv_nsec / 1000; } else if (!(valid & P9_SETATTR_ATIME_SET)) { tv[0].tv_sec = now.tv_sec; tv[0].tv_usec = now.tv_usec; } else { tv[0].tv_sec = atime_sec; tv[0].tv_usec = atime_nsec / 1000; } if (!(valid & P9_SETATTR_MTIME)) { tv[1].tv_sec = sb.st_mtim.tv_sec; tv[1].tv_usec = sb.st_mtim.tv_nsec / 1000; } else if (!(valid & P9_SETATTR_MTIME_SET)) { tv[1].tv_sec = now.tv_sec; tv[1].tv_usec = now.tv_usec; } else { tv[1].tv_sec = mtime_sec; tv[1].tv_usec = mtime_nsec / 1000; } tvp = tv; } if (utimes (f->path, tvp) < 0) { np_uerror(errno); goto error_quiet; } #endif /* HAVE_UTIMENSAT */ ctime_updated = 1; } if ((valid & P9_SETATTR_CTIME) && !ctime_updated) { if (lchown (f->path, -1, -1) < 0) { np_uerror (errno); goto error_quiet; } } if (!(ret = np_create_rsetattr())) { np_uerror (ENOMEM); goto error; } return ret; error: errn (np_rerror (), "diod_setattr %s@%s:%s (valid=0x%x)", fid->user->uname, np_conn_get_client_id (fid->conn), f->path, valid); error_quiet: return NULL; }
Npfcall* diod_setattr (Npfid *fid, u32 valid, u32 mode, u32 uid, u32 gid, u64 size, u64 atime_sec, u64 atime_nsec, u64 mtime_sec, u64 mtime_nsec) { Npfcall *ret = NULL; Fid *f = fid->aux; int fidstat_updated = 0; int ctime_updated = 0; if ((f->xflags & XFLAGS_RO)) { np_uerror (EROFS); goto error_quiet; } if ((valid & P9_SETATTR_MODE) || (valid & P9_SETATTR_SIZE)) { if (_fidstat(f) < 0) goto error_quiet; fidstat_updated = 1; if (S_ISLNK(f->stat.st_mode)) { msg ("diod_setattr: unhandled mode/size update on symlink"); np_uerror(EINVAL); goto error; } } /* chmod (N.B. dereferences symlinks) */ if ((valid & P9_SETATTR_MODE)) { if (chmod (f->path, mode) < 0) { np_uerror(errno); goto error_quiet; } ctime_updated = 1; } /* chown */ if ((valid & P9_SETATTR_UID) || (valid & P9_SETATTR_GID)) { if (lchown (f->path, (valid & P9_SETATTR_UID) ? uid : -1, (valid & P9_SETATTR_GID) ? gid : -1) < 0) { np_uerror(errno); goto error_quiet; } ctime_updated = 1; } /* truncate (N.B. dereferences symlinks) */ if ((valid & P9_SETATTR_SIZE)) { if (truncate (f->path, size) < 0) { np_uerror(errno); goto error_quiet; } ctime_updated = 1; } /* utimes */ if ((valid & P9_SETATTR_ATIME) || (valid & P9_SETATTR_MTIME)) { #if HAVE_UTIMENSAT struct timespec ts[2]; if (!(valid & P9_SETATTR_ATIME)) { ts[0].tv_sec = 0; ts[0].tv_nsec = UTIME_OMIT; } else if (!(valid & P9_SETATTR_ATIME_SET)) { ts[0].tv_sec = 0; ts[0].tv_nsec = UTIME_NOW; } else { ts[0].tv_sec = atime_sec; ts[0].tv_nsec = atime_nsec; } if (!(valid & P9_SETATTR_MTIME)) { ts[1].tv_sec = 0; ts[1].tv_nsec = UTIME_OMIT; } else if (!(valid & P9_SETATTR_MTIME_SET)) { ts[1].tv_sec = 0; ts[1].tv_nsec = UTIME_NOW; } else { ts[1].tv_sec = mtime_sec; ts[1].tv_nsec = mtime_nsec; } if (utimensat(-1, f->path, ts, AT_SYMLINK_NOFOLLOW) < 0) { np_uerror(errno); goto error_quiet; } ctime_updated = 1; #else /* HAVE_UTIMENSAT */ struct timeval tv[2], now, *tvp; /* N.B. this utimes () implementation loses atomicity and precision. */ if ((valid & P9_SETATTR_ATIME) && !(valid & P9_SETATTR_ATIME_SET) && (valid & P9_SETATTR_MTIME) && !(valid & P9_SETATTR_MTIME_SET)) { tvp = NULL; /* set both to now */ } else { if (!fidstat_updated && _fidstat(f) < 0) goto error_quiet; fidstat_updated = 1; if (gettimeofday (&now, NULL) < 0) { np_uerror (errno); goto error_quiet; } if (!(valid & P9_SETATTR_ATIME)) { tv[0].tv_sec = f->stat.st_atim.tv_sec; tv[0].tv_usec = f->stat.st_atim.tv_nsec / 1000; } else if (!(valid & P9_SETATTR_ATIME_SET)) { tv[0].tv_sec = now.tv_sec; tv[0].tv_usec = now.tv_usec; } else { tv[0].tv_sec = atime_sec; tv[0].tv_usec = atime_nsec / 1000; } if (!(valid & P9_SETATTR_MTIME)) { tv[1].tv_sec = f->stat.st_mtim.tv_sec; tv[1].tv_usec = f->stat.st_mtim.tv_nsec / 1000; } else if (!(valid & P9_SETATTR_MTIME_SET)) { tv[1].tv_sec = now.tv_sec; tv[1].tv_usec = now.tv_usec; } else { tv[1].tv_sec = mtime_sec; tv[1].tv_usec = mtime_nsec / 1000; } tvp = tv; } if (utimes (f->path, tvp) < 0) { np_uerror(errno); goto error_quiet; } ctime_updated = 1; #endif } if ((valid & P9_SETATTR_CTIME) && !ctime_updated) { if (lchown (f->path, -1, -1) < 0) { np_uerror (errno); goto error_quiet; } } if (!(ret = np_create_rsetattr())) { np_uerror (ENOMEM); goto error; } return ret; error: errn (np_rerror (), "diod_setattr %s@%s:%s (valid=0x%x)", fid->user->uname, np_conn_get_client_id (fid->conn), f->path, valid); error_quiet: if (ret) free (ret); return NULL; }
static void * loadgen (void *arg) { thd_t *t = (thd_t *)arg; uid_t uid = geteuid (); void *ret = NULL; int n, loops = 0; if ((t->fd = diod_sock_connect (t->host, t->port, 0)) < 0) goto done; if (!(t->fs = npc_start (t->fd, t->fd, t->msize, 0))) { errn (np_rerror (), "error negotiating protocol with server"); goto done; } if (!(t->afid = npc_auth (t->fs, "ctl", uid, diod_auth)) && np_rerror () != 0) { errn (np_rerror (), "error authenticating to server"); goto done; } if (!(t->root = npc_attach (t->fs, t->afid, "ctl", uid))) { errn (np_rerror (), "error attaching to aname=ctl"); goto done; } if (t->loadtype == LOAD_IO) { if (!(t->infile = npc_open_bypath (t->root, "zero", O_RDONLY))) { errn (np_rerror (), "open zero"); goto done; } if (!(t->outfile = npc_open_bypath (t->root, "null", O_WRONLY))) { errn (np_rerror (), "open null"); goto done; } do { if ((n = npc_pread (t->infile, t->buf, t->msize, 0)) <= 0) { errn (np_rerror (), "read zero"); break; } t->readbytes += n; if ((n = npc_pwrite (t->outfile, t->buf, t->msize, 0)) < 0) { errn (np_rerror (), "write null"); break; } t->writebytes += n; t->opcount++; loops++; } while ((loops % 100 != 0) || time (NULL) < t->stoptime); } else if (t->loadtype == LOAD_GETATTR) { if (!(t->infile = npc_walk (t->root, "null"))) { errn (np_rerror (), "walk null"); goto done; } do { struct stat sb; if (npc_fstat (t->infile, &sb) < 0) { errn (np_rerror (), "walk null"); break; } t->opcount++; loops++; } while ((loops % 100 != 0) || time (NULL) < t->stoptime); } done: if (t->outfile && npc_clunk (t->outfile) < 0) errn (np_rerror (), "error clunking null"); if (t->infile && npc_clunk (t->infile) < 0) errn (np_rerror (), "error clunking zero"); if (t->root && npc_clunk (t->root) < 0) errn (np_rerror (), "error clunking ctl"); if (t->afid && npc_clunk (t->afid) < 0) errn (np_rerror (), "error clunking afid"); if (t->fs) { npc_finish (t->fs); /* closes fd */ t->fd = -1; } if (t->fd != -1) close (t->fd); return ret; }
int main (int argc, char *argv[]) { char *aname = "ctl"; char *server = NULL; int msize = 65536; uid_t uid = geteuid (); int topt = 0; int Sopt = 0; int flags = 0; int fd, c; Npcfsys *fs = NULL; Npcfid *afid = NULL, *root = NULL; char *buf = NULL; struct timeval tv; struct timezone tz; diod_log_init (argv[0]); opterr = 0; while ((c = GETOPT (argc, argv, OPTIONS, longopts)) != -1) { switch (c) { case 's': /* --server HOST[:PORT] or /path/to/socket */ server = optarg; break; case 'm': /* --msize SIZE */ msize = strtoul (optarg, NULL, 10); break; case 'u': /* --uid UID */ uid = strtoul (optarg, NULL, 10); break; case 't': /* --timeout SECS */ topt = strtoul (optarg, NULL, 10); break; case 'S': /* --set-time */ Sopt = 1; break; default: usage (); } } if (signal (SIGPIPE, SIG_IGN) == SIG_ERR) err_exit ("signal"); if (signal (SIGALRM, sigalarm) == SIG_ERR) err_exit ("signal"); if (topt > 0) alarm (topt); if ((fd = diod_sock_connect (server, flags)) < 0) exit (1); if (!(fs = npc_start (fd, fd, msize, 0))) { errn (np_rerror (), "error negotiating protocol with server"); goto done; } if (!(afid = npc_auth (fs, aname, uid, diod_auth)) && np_rerror () != 0) { errn (np_rerror (), "error authenticating to server"); goto done; } if (!(root = npc_attach (fs, afid, aname, uid))) { errn (np_rerror (), "error attaching to aname='%s'", aname); goto done; } buf = npc_aget (root, "date"); if (!buf) { errn (np_rerror (), "error reading date"); goto done; } if (sscanf (buf, "%lu.%lu %d.%d", &tv.tv_sec, &tv.tv_usec, &tz.tz_minuteswest, &tz.tz_dsttime) != 4) { msg ("error scanning returned date: %s", buf); goto done; } if (Sopt) { if (settimeofday (&tv, &tz) < 0) err_exit ("settimeofday"); } else { time_t t = tv.tv_sec; printf ("%s", ctime (&t)); } done: if (buf) free (buf); if (root && npc_clunk (root) < 0) errn_exit (np_rerror (), "error clunking %s", aname); if (afid && npc_clunk (afid) < 0) errn_exit (np_rerror (), "error clunking afid"); if (fs) npc_finish (fs); close (fd); diod_log_fini (); exit (0); }
void test_mt (int argc, char **argv) { thd_t *thd; int i, rc; flux_t h; int errors = 0; if (argc != 3) { fprintf (stderr, "Usage: mt nthreads changes key\n"); exit (1); } nthreads = strtoul (argv[0], NULL, 10); changes = strtoul (argv[1], NULL, 10); key = argv[2]; thd = xzmalloc (sizeof (*thd) * nthreads); if (!(h = flux_open (NULL, 0))) err_exit ("flux_open"); /* Set initial value of 'key' to -1 */ if (kvs_put_int (h, key, -1) < 0) err_exit ("kvs_put_int %s", key); key_stable = xasprintf ("%s-stable", key); if (kvs_put_int (h, key_stable, 0) < 0) err_exit ("kvs_put_int %s", key); if (kvs_commit (h) < 0) err_exit ("kvs_commit"); for (i = 0; i < nthreads; i++) { thd[i].n = i; thd[i].last_val = -42; if ((rc = pthread_attr_init (&thd[i].attr))) errn (rc, "pthread_attr_init"); if ((rc = pthread_create (&thd[i].tid, &thd[i].attr, thread, &thd[i]))) errn (rc, "pthread_create"); } wait_ready (); for (i = 0; i < changes; i++) { if (kvs_put_int (h, key, i) < 0) err_exit ("kvs_put_int %s", key); if (kvs_commit (h) < 0) err_exit ("kvs_commit"); } /* Verify that callbacks were called the correct number of times. * The nil and stable callbacks will be called exactly once before the * reactor is started, then should never be called again. * Due to commit merging on the master, the changing callback may * miss intervening values but it shouldn't be called extra times. */ for (i = 0; i < nthreads; i++) { if ((rc = pthread_join (thd[i].tid, NULL))) errn (rc, "pthread_join"); if (thd[i].nil_count != 1) { msg ("%d: nil callback called %d times (expected one)", i, thd[i].nil_count); errors++; } if (thd[i].stable_count != 1) { msg ("%d: stable callback called %d times (expected one)", i, thd[i].stable_count); errors++; } if (thd[i].change_count > changes + 1) { msg ("%d: changing callback called %d times (expected <= %d)", i, thd[i].change_count, changes + 1); errors++; } } if (errors > 0) exit (1); free (thd); free (key_stable); flux_close (h); }