/* Copyright 2005-2008 Luis Furquim * * * 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; version 3 of the License. * * 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 * */ // // The lines below are from a patch contributed by Yen-Ming Lee, // porting ChironFS to FreeBSD // #include #if defined(linux) || defined(__FreeBSD__) #include #include #else typedef uint64_t cpuset_t; // // The lines below are from a patch contributed by Antti Kantee // to make ChironFS run on NetBSD // #include #endif // // End of BSD patches // #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __linux__ #define _REENTRANT #ifndef _POSIX_SOURCE #define _POSIX_SOURCE #endif /* for LinuxThreads */ #define _P __P #endif #include #include "config.h" #include "chiron-types.h" #include "chirondbg.h" #define _CHIRON_CTL_H_ #include "chirctl.h" #include "chironfn.h" ctlfs_entry_t mkstatnod(char *path, unsigned long mode, unsigned short uid, unsigned short gid) { ctlfs_entry_t c; memset(&c,0,sizeof(ctlfs_entry_t)); c.path = path; c.attr.st_mode = mode; c.attr.st_ino = ++inode_count; c.attr.st_dev = 0; c.attr.st_nlink = 0; c.attr.st_uid = uid; c.attr.st_gid = gid; c.attr.st_size = 1; c.attr.st_atime = 0; c.attr.st_mtime = 0; c.attr.st_ctime = 0; c.attr.st_blocks = 0; c.attr.st_blksize = 0; c.ctlfs = NULL; return(c); } void free_ctlnode(ctlfs_entry_t *ctlroot) { ctlfs_entry_t *c = ctlroot; for(;c->path!=NULL;++c) { if (c->ctlfs!=NULL) { free_ctlnode(c->ctlfs); } free(c->path); } free(ctlroot); } int mkctlfs() { int i; struct stat st; // uid_t uid = geteuid(); // gid_t gid = getegid(); i = stat(chironctl_mountpoint,&st); if (i) { return(-1); } ctlfs[0] = mkstatnod("/",S_IFDIR | S_IREAD | S_IEXEC | ((S_IREAD | S_IEXEC)>>3),st.st_uid,st.st_gid); ctlfs[0].ctlfs = malloc(sizeof(ctlfs_entry_t)*max_replica+1); if (ctlfs[0].ctlfs==NULL) { return(-1); } ctlfs[1].path = NULL; dbg(("\nalloced")); for(i=0;ictlfs[i] = mkstatnod(malloc(sizeof(char) * (2+strlen(paths[i].path))), S_IFDIR | S_IREAD | S_IEXEC | ((S_IREAD | S_IEXEC)>>3), st.st_uid,st.st_gid); if (ctlfs->ctlfs[i].path == NULL) { free_ctlnode(ctlfs->ctlfs); dbg(("\nctl out of mem")); return(-1); } sprintf(ctlfs->ctlfs[i].path,"%s",paths[i].path); dbg(("\nctl: path=%s, path2=%s ino=%d",paths[i].path, ctlfs->ctlfs[i].path, ctlfs->ctlfs[i].attr.st_ino)); // replica subdir ctlfs->ctlfs[i].ctlfs = malloc(sizeof(ctlfs_entry_t)*3); if (ctlfs->ctlfs[i].ctlfs==NULL) { free_ctlnode(ctlfs->ctlfs); return(-1); } // end of the list ctlfs->ctlfs[i].ctlfs[2].path = NULL; // status file ctlfs->ctlfs[i].ctlfs[0] = mkstatnod(malloc(sizeof(char) * (2+strlen(status_fname))), S_IFREG | S_IREAD | S_IWRITE | ((S_IREAD | S_IWRITE)>>3), st.st_uid,st.st_gid); if (ctlfs->ctlfs[i].ctlfs[0].path == NULL) { free_ctlnode(ctlfs->ctlfs); dbg(("\nctl out of mem")); return(-1); } sprintf(ctlfs->ctlfs[i].ctlfs[0].path,status_fname); dbg(("\nctl: status ino=%d",ctlfs->ctlfs[i].ctlfs[0].attr.st_ino)); // nagios plugin script ctlfs->ctlfs[i].ctlfs[1] = mkstatnod(malloc(sizeof(char) * (2+strlen(nagios_fname))), S_IFREG | S_IREAD | S_IEXEC | ((S_IREAD | S_IEXEC)>>3), st.st_uid,st.st_gid); if (ctlfs->ctlfs[i].ctlfs[1].path == NULL) { free_ctlnode(ctlfs->ctlfs); dbg(("\nctl out of mem")); return(-1); } ctlfs->ctlfs[i].ctlfs[1].attr.st_size = strlen(nagios_script); sprintf(ctlfs->ctlfs[i].ctlfs[1].path,nagios_fname); dbg(("\nctl: status ino=%d",ctlfs->ctlfs[i].ctlfs[1].attr.st_ino)); } ctlfs->ctlfs[i].path = NULL; return(0); } ctlfs_search_t find_path(const char *path, ctlfs_entry_t *c, int deep) { ctlfs_search_t res; size_t s; int i; for(i=0;c[i].path!=NULL;++i) { if (!strcmp(path,c[i].path)) { res.ctlfs = c; res.i = i; return(res); } s = strlen(c[i].path); if ((!strncmp(path,c[i].path,s)) && (path[s]=='/') && (c[i].ctlfs!=NULL)) { if (!deep) { res.ctlfs = c; res.i = i; return(res); } return(find_path(path+s, c[i].ctlfs,deep-1)); } } res.ctlfs = NULL; res.i = 0; return(res); } char *get_daddy(const char *path) { char *s, *p; if (path[1]=='\0') { s = strdup(""); return(s); } s = strdup(path); if (s==NULL) { return(s); } p = strrchr(s,'/'); if (p==s) { s[1] = '\0'; } else { (*p) = '\0'; } return(s); } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // // // P E R M I S S I O N C H E C K F U N C T I O N S // // //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// int get_perm(uid_t uid, gid_t gid, struct stat st) { int i, res=0; char *buffer; struct group result_buf, *result=NULL; struct passwd *pw; char **member; dbg(("\ncuid:%d\tstuid:%d",uid,st.st_uid)); if (uid==st.st_uid) { return((st.st_mode&0700) >> 6); } if (gid==st.st_gid) { return((st.st_mode&070) >> 3); } i = 1024; do { buffer = calloc(i,sizeof(char)); if (buffer!=NULL) { res = getgrgid_r(st.st_gid,&result_buf,buffer,i,&result); if (res==ERANGE) { free(buffer); i <<= 1; } } } while ((res==ERANGE) && (buffer!=NULL)); if (buffer==NULL) { errno = ENOMEM; return(-1); } if (result!=NULL) { member = result->gr_mem; while (*member) { pw = getpwnam(*member); if (pw->pw_uid==uid) { free(buffer); return((st.st_mode&070) >> 3); } member++; } } free(buffer); return(st.st_mode&7); } int get_path_perm(const char *path) { ctlfs_search_t res, path_res; static struct fuse_context *context; int perm, path_perm; context = fuse_get_context(); if ((!context->uid) || (!context->gid)) { return(7); } perm = get_perm(context->uid,context->gid,ctlfs[0].attr); if (path[1]=='\0') { dbg(("\nperm (/):%d",perm)); return(perm); } if (perm&1) { path_perm = perm; res = find_path(path,ctlfs->ctlfs,0); if (res.ctlfs==NULL) { return(-ENOENT); } perm = get_perm(context->uid,context->gid,res.ctlfs->attr); path_res = res; res = find_path(path,ctlfs->ctlfs,1); if ((res.ctlfs==path_res.ctlfs) && (res.i==path_res.i)) { dbg(("\nperm:%d",perm)); return(perm); } if (perm&1) { perm = get_perm(context->uid,context->gid,res.ctlfs->attr); dbg(("\nperm:%d",perm)); return(perm); } } return(0); } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // // // W R A P P E R F U N C T I O N S // // //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// static int chironctl_statfs(const char *path, struct statvfs *stbuf) { (void) path; stbuf->f_bsize = 4096; stbuf->f_frsize = 4096; stbuf->f_bsize = 4096; stbuf->f_frsize = 4096; stbuf->f_blocks = 0xFFFFF; stbuf->f_bfree = 0xFFFFF; stbuf->f_bavail = 0xFFFFF; stbuf->f_files = 0xFFFF; stbuf->f_ffree = 0xFFFF; stbuf->f_favail = 0xFFFF; stbuf->f_fsid = -1047; stbuf->f_flag = 1024; stbuf->f_namemax= 255; return(0); } static int chironctl_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { ctlfs_entry_t *dir; ctlfs_search_t res; (void) offset; (void) fi; dbg(("\nctlreaddir: %s, offset: %ld\n",path,offset)); if ((get_path_perm(path)&5)!=5) { return(-EACCES); } if (path[1]=='\0') { dir = ctlfs; } else { res = find_path(path,ctlfs->ctlfs,-1); if (res.ctlfs==NULL) { return(-ENOENT); } dir = res.ctlfs+res.i; } filler(buf, ".", &(dir->attr), 0); // lstat(chironctl_parentdir,&st); // filler(buf, "..", &st, 0); for(dir = dir->ctlfs;dir->path!=NULL;++dir) { if (filler(buf, dir->path+1, &(dir->attr), 0)) { // dbg(("\nctlreaddir: i=%d\n",i)); return 0; } } return 0; } static void chironctl_destroy(void *notused) { (void) notused; } static int chironctl_truncate(const char *path_orig, off_t size) { dbg(("\ntruncate: %s\n",path_orig)); (void) path_orig; (void) size; return(0); } static int chironctl_getattr(const char *path, struct stat *stbuf) { dbg(("\nctlgetattr: %s\n",path)); ctlfs_entry_t *dir; ctlfs_search_t res; char *p; int perm; p = get_daddy(path); if (p==NULL) { return(-ENOMEM); } dbg(("\nctlgetattr-daddy: %s\n",p)); if (p[0]) { perm = get_path_perm(p); dbg(("\nctlgetattr-perm: %d\n",perm)); if ((perm&5)!=5) { return(-EACCES); } } else { if ((get_path_perm(path)&5)!=5) { return(-EACCES); } } dbg(("\nctlgetattr-perm: ok, path=%s\n",path)); if (path[1]=='\0') { dir = ctlfs; } else { res = find_path(path,ctlfs->ctlfs,-1); if (res.ctlfs==NULL) { dbg(("\nctlgetattr-404: notfound\n")); return(-ENOENT); } dir = res.ctlfs+res.i; } dbg(("\nctlgetattr: mode=%o\n",dir->attr.st_mode)); memcpy(stbuf, &(dir->attr), sizeof(struct stat)); return(0); } static int chironctl_open(const char *path, struct fuse_file_info *fi) { int perm = 0, perm_mask = 0; ctlfs_search_t res; (void) fi; if (fi->flags&O_CREAT) { return(-EACCES); } if (fi->flags&(O_WRONLY|O_TRUNC|O_APPEND)) { perm_mask = 2; } else if (fi->flags&O_RDWR) { perm_mask = 6; } else if ((fi->flags&(O_RDONLY|O_EXCL)) == (O_RDONLY)) { perm_mask = 4; } perm = get_path_perm(path); if (((perm&perm_mask)!=perm_mask) || (!perm_mask) || (!perm)) { return(-EACCES); } if (path[1]!='\0') { res = find_path(path,ctlfs->ctlfs,-1); if (res.ctlfs==NULL) { return(-ENOENT); } } return 0; } static int chironctl_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { int sz, rep, someerr, fname; ctlfs_search_t res; ctlfs_entry_t *cmd; char *chbuf = NULL; (void) fi; if ((get_path_perm(path)&4)!=4) { return(-EACCES); } if (path[1]=='\0') { return(-ENOSYS); } res = find_path(path,ctlfs->ctlfs,-1); if (res.ctlfs==NULL) { return(-ENOENT); } cmd = res.ctlfs+res.i; res = find_path(path,ctlfs->ctlfs,0); rep = res.i; dbg(("\nctlread: rep: %d, cmd: %s\n",rep,cmd->path)); fname = (!strcmp(cmd->path,status_fname)) ? 1 : ( (!strcmp(cmd->path,nagios_fname)) ? 2 : 0 ); if (fname) { pthread_mutex_lock(&comm); fprintf(tochironfs,"0007stat:%02X",res.i); fflush(tochironfs); someerr = read_a_line(&chbuf,&sz,fromchironfs); pthread_mutex_unlock(&comm); if (someerr) { return (-EIO); } dbg(("\nctlread: rep: %d, cmd: %s=%s\n",rep,cmd->path,chbuf)); if (fname==1) { sprintf(buf,"%c",chbuf[0]); free(chbuf); return(1); } if (fname==2) { sz = strlen(nagios_script) - offset; if (sz<0) { sz = 0; } sz = min(sz,(int)size); memcpy(nagios_script+538,status_msgs[chbuf[0]-'0'],strlen(status_msgs[chbuf[0]-'0'])); nagios_script[602] = chbuf[0]; memcpy(buf,nagios_script+offset,sz); free(chbuf); return(sz); } } return(-ENOSYS); } static int chironctl_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { int sz, rep, someerr; ctlfs_search_t res; ctlfs_entry_t *cmd; char *chbuf = NULL; (void) fi; (void) offset; dbg(("\nctlwrite: %d=%s\n",size,buf)); if ((get_path_perm(path)&2)!=2) { return(-EACCES); } if (path[1]=='\0') { return(-ENOSYS); } res = find_path(path,ctlfs->ctlfs,-1); if (res.ctlfs==NULL) { return(-ENOENT); } cmd = res.ctlfs+res.i; res = find_path(path,ctlfs->ctlfs,0); rep = res.i; if (!strcmp(cmd->path,status_fname)) { if ((size>2) || ((size==2) && (buf[1]!='\n')) // || ((buf[0]!='0') && (buf[0]!='1') && (buf[0]!='2')) || ((buf[0]!='0') && (buf[0]!='2')) ) { return(-ENOSYS); } pthread_mutex_lock(&comm); if (buf[0]=='0') { fprintf(tochironfs,"0008trust:%02X",res.i); } else if (buf[0]=='1') { fprintf(tochironfs,"0009enable:%02X",res.i); } else if (buf[0]=='2') { fprintf(tochironfs,"000Adisable:%02X",res.i); } fflush(tochironfs); someerr = read_a_line(&chbuf,&sz,fromchironfs); pthread_mutex_unlock(&comm); if (someerr) { return (-EIO); } dbg(("\nctlwrite: rep: %d, cmd: %s=%s\n",rep,cmd->path,chbuf)); if ((chbuf[0]=='O') && (chbuf[1]=='K')) { free(chbuf); return(size); } free(chbuf); return(-EIO); } return(-ENOSYS); } struct fuse_operations chironctl_oper = { .readdir = chironctl_readdir, .statfs = chironctl_statfs, .destroy = chironctl_destroy, .getattr = chironctl_getattr, .open = chironctl_open, .read = chironctl_read, .write = chironctl_write, .truncate = chironctl_truncate, }; void free_vars(void) { int i; if (chironctl_parentdir!=NULL) { free(chironctl_parentdir); } if (chironctl_mountpoint!=NULL) { free(chironctl_mountpoint); } if (mount_point!=NULL) { free(mount_point); } if (paths!=NULL) { for(i=0;i