diff --git a/examples/smpfd.c b/examples/smpfd.c index 7e08162..1aa6ee0 100644 --- a/examples/smpfd.c +++ b/examples/smpfd.c @@ -4,15 +4,15 @@ * (c) Alexander Vdolainen 2013-2015 * (c) Alexander Vdolainen 2016 * - * libsxmp is free software: you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published + * libsxmp examples 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 3 of the License, or * (at your option) any later version. * * libsxmp 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 Lesser General Public License for more details. + * 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, see ."; @@ -27,8 +27,9 @@ * This implements a simple client-server topology, to see * more advanced technics check out other examples. * - * NOTE(win32): don't have a time to test it or fix it to - * make it works on windows, if you can - u're welcome. + * NOTE(win32): win32 is not a platform for any serious, + * except the games maybe... well, this code contains linux + * stuff (not sure about other *nixes) */ #include @@ -37,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -44,21 +46,22 @@ #include #include #include -#include +#include +#include #include #include +#include +#include +#include +#include +#include #include #include #include #include #include -#include -#include -#include -#include - #include "smpf.h" #include "smpfd_defs.h" #include "../config.h" @@ -73,6 +76,102 @@ static struct smpfd_ctx daemon_ctx; */ static usrtc_t *fulist; +/* misc functions */ +static char *__humansize(struct stat *buf) +{ + char *hsize = malloc(64); + int d = 0; + + if(!hsize) return NULL; + if(buf->st_size < 10*1024) snprintf(hsize, 64, "%ld", buf->st_size); + else if(buf->st_size >= 10*1024 && buf->st_size < 1024*1024) { /* KiB */ + d = buf->st_size % 1024; + if(!d) snprintf(hsize, 64, "%ldKiB", buf->st_size/1024); + else snprintf(hsize, 64, "%ld.%dKiB", buf->st_size/1024, d /= 102); + } else if(buf->st_size >= 1024*1024 && buf->st_size < 1024*1024*1024) { /* MiB */ + d = buf->st_size % (1024*1024); + if(!d) snprintf(hsize, 64, "%ldMiB", buf->st_size/(1024*1024)); + else snprintf(hsize, 64, "%ld.%dMiB", buf->st_size/(1024*1024), d /= 102); + } else { /* GiB */ + d = buf->st_size % (1024*1024*1024); + if(!d) snprintf(hsize, 64, "%ldGiB", buf->st_size/(1024*1024*1024)); + else snprintf(hsize, 64, "%ld.%dGiB", buf->st_size/(1024*1024*1024), d /= 102); + } + return hsize; +} + +static char *__humanmode(struct stat *buf) +{ + char *hmode = malloc(12); + char s = 0; + int i; + + if(!hmode) return NULL; + memset(hmode, 0, 12); + + for(i = 0; i < 10; i++) { + switch(i) { + case 0: + if(S_ISDIR(buf->st_mode)) s = 'd'; + else if(S_ISCHR(buf->st_mode)) s = 'c'; + else if(S_ISBLK(buf->st_mode)) s = 'b'; + else if(S_ISFIFO(buf->st_mode)) s = 'f'; + else if(S_ISLNK(buf->st_mode)) s = 'l'; + else if(S_ISSOCK(buf->st_mode)) s = 's'; + else s = '-'; + break; + } + hmode[i] = s; + } + + return hmode; +} + +static char *__humanuser(struct stat *buf) +{ + struct passwd pwd; + struct passwd *res; + char *pwdbuf, *huser; + size_t pwdlen; + + if((pwdlen = sysconf(_SC_GETPW_R_SIZE_MAX)) == -1) pwdlen = 16384; + + if(!(pwdbuf = malloc(pwdlen))) return NULL; + + getpwuid_r(buf->st_uid, &pwd, pwdbuf, pwdlen, &res); + if(!res) { + if(!(huser = malloc(12))) goto __fini; + snprintf(huser, 12, "%d", buf->st_uid); + } else huser = strdup(pwd.pw_name); + + __fini: + free(pwdbuf); + return huser; +} + +static char *__humangroup(struct stat *buf) +{ + struct group grp; + struct group *res; + char *pwdbuf, *hgroup; + size_t pwdlen; + + if((pwdlen = sysconf(_SC_GETGR_R_SIZE_MAX)) == -1) pwdlen = 16384; + + if(!(pwdbuf = malloc(pwdlen))) return NULL; + + getgrgid_r(buf->st_gid, &grp, pwdbuf, pwdlen, &res); + if(!res) { + if(!(hgroup = malloc(12))) goto __fini; + snprintf(hgroup, 12, "%d", buf->st_gid); + } else hgroup = strdup(grp.gr_name); + + __fini: + free(pwdbuf); + return hgroup; +} + + /* ok, here we will define out sxmp specific functions */ /* @@ -211,6 +310,74 @@ static int __getcwd(void *m, sexp_t *sx) return sxmsg_rreply(msg, rbuf_len); } +static int __stat(void *m, sexp_t *sx) +{ + sxmsg_t *msg = (sxmsg_t*)m; + sxlink_t *link = sxmsg_link(msg); + char *rbuf = sxmsg_rapidbuf(msg), *dirname = NULL, *odir = NULL; + char *hsize, *hmode, *huser, *hgroup; + sexp_t *isx; + size_t rbuf_len = 0; + int r = SXE_SUCCESS, idx, olen = 0, rc; + struct mp_session *session = (struct mp_session *)sxlink_getpriv(link); + struct stat statbuf; + + SEXP_ITERATE_LIST(sx, isx, idx) { + if(isx->ty == SEXP_LIST) r = SXE_BADPROTO; + if(idx > 1) r = SXE_BADPROTO; + + if(idx) dirname = isx->val; + } + if(r != SXE_SUCCESS || !dirname) goto __fail; + if(!strcmp(dirname, "./")) goto __fail; + if(!strlen(dirname) || !strcmp(dirname, ".")) goto __fail; + + + if(*dirname == '/') odir = strdup(dirname); + else { + olen = strlen(session->cwd) + strlen(dirname) + 2*sizeof(char); + odir = malloc(olen); + } + + if(!odir) { + r = SXE_ENOMEM; + goto __fail; + } + + if(olen) snprintf(odir, olen, "%s/%s", session->cwd, dirname); + + if(normalize_path(odir)) r = SXE_FAILED; + else { /* take stat of the file */ + rc = stat(odir, &statbuf); + if(rc) { + r = SXE_FAILED; + goto __fail; + } + /* make this human readable to reply for client */ + hsize = __humansize(&statbuf); + hmode = __humanmode(&statbuf); + huser = __humanuser(&statbuf); + hgroup = __humangroup(&statbuf); + /* create a reply */ + rbuf_len = snprintf(rbuf, MAX_RBBUF_LEN, "((:user %s)(:group %s)(:size %s)(:mode %s))", + huser, hgroup, hsize, hmode); + + /* free */ + if(odir) free(odir); + if(hsize) free(hsize); + if(hmode) free(hmode); + if(huser) free(huser); + if(hgroup) free(hgroup); + + /* reply rapidly */ + return sxmsg_rreply(msg, rbuf_len); + } + + __fail: + if(odir) free(odir); + return sxmsg_return(msg, r); +} + /* stream, simple entry nonamed streams */ /* dir listing stream */ typedef struct __dirlist_type { @@ -474,7 +641,7 @@ int main(int argc, char **argv) if(opt) goto __failaddrpc; opt = sxmp_rpclist_add_function(fulist, READONLY_CHANNEL, GETCWD_CMD, __getcwd); if(opt) goto __failaddrpc; - opt = sxmp_rpclist_add_function(fulist, READONLY_CHANNEL, STAT_CMD, __ping); + opt = sxmp_rpclist_add_function(fulist, READONLY_CHANNEL, STAT_CMD, __stat); if(opt) goto __failaddrpc; /* streams */