Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Enduro/X standard utilities
0003  *
0004  * @file psstdexutil.cpp
0005  */
0006 /* -----------------------------------------------------------------------------
0007  * Enduro/X Middleware Platform for Distributed Transaction Processing
0008  * Copyright (C) 2009-2016, ATR Baltic, Ltd. All Rights Reserved.
0009  * Copyright (C) 2017-2023, Mavimax, Ltd. All Rights Reserved.
0010  * This software is released under one of the following licenses:
0011  * AGPL (with Java and Go exceptions) or Mavimax's license for commercial use.
0012  * See LICENSE file for full text.
0013  * -----------------------------------------------------------------------------
0014  * AGPL license:
0015  *
0016  * This program is free software; you can redistribute it and/or modify it under
0017  * the terms of the GNU Affero General Public License, version 3 as published
0018  * by the Free Software Foundation;
0019  *
0020  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0021  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0022  * PARTICULAR PURPOSE. See the GNU Affero General Public License, version 3
0023  * for more details.
0024  *
0025  * You should have received a copy of the GNU Affero General Public License along 
0026  * with this program; if not, write to the Free Software Foundation, Inc.,
0027  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0028  *
0029  * -----------------------------------------------------------------------------
0030  * A commercial use license is available from Mavimax, Ltd
0031  * contact@mavimax.com
0032  * -----------------------------------------------------------------------------
0033  */
0034 #define __USE_POSIX_IMPLICITLY
0035 #include <ndrstandard.h>
0036 #include <unistd.h>
0037 #include <pscript.h>
0038 #include <time.h>
0039 #include <stdlib.h>
0040 #include <stdio.h>
0041 #include <psstdexutil.h>
0042 #include <ndebug.h>
0043 #include <nstdutil.h>
0044 #include <userlog.h>
0045 #include <string.h>
0046 #include <ndrx_config.h>
0047 #include <sys/stat.h>
0048 #include <errno.h>
0049 #include <netdb.h>
0050 
0051 
0052 #define _XOPEN_SOURCE_EXTENDED 1
0053 #include <libgen.h>
0054 
0055 extern "C" const char ndrx_G_resource_WizardBase[];
0056 
0057 //Read the line from terminal
0058 //@return line read string
0059 static PSInteger _exutil_getline(HPSCRIPTVM v)
0060 {
0061     char ln[PATH_MAX+1];
0062     
0063     ndrx_fgets_stdin_strip(ln, sizeof(ln));
0064     
0065     ps_pushstring(v,ln,-1);
0066 
0067     return 1;
0068 }
0069 
0070 //Return the compiled operating system name
0071 static PSInteger _exutil_getosname(HPSCRIPTVM v)
0072 {
0073     ps_pushstring(v,NDRX_BUILD_OS_NAME,-1);
0074     
0075     return 1;
0076 }
0077 
0078 //Return the compiled operating system name
0079 static PSInteger _exutil_getpoller(HPSCRIPTVM v)
0080 {
0081     ps_pushstring(v,EX_POLLER_STR,-1);
0082     
0083     return 1;
0084 }
0085 
0086 //Return wizard base script
0087 static PSInteger _exutil_getwizardbase(HPSCRIPTVM v)
0088 {
0089     ps_pushstring(v,ndrx_G_resource_WizardBase,-1);
0090     
0091     return 1;
0092 }
0093 
0094 
0095 //Get the current working dir
0096 //@return   current working dir
0097 static PSInteger _exutil_getcwd(HPSCRIPTVM v)
0098 {
0099     char* ret;
0100     char buff[PATH_MAX + 1];
0101     
0102     ret = getcwd( buff, sizeof(buff) );
0103      
0104     ps_pushstring(v,ret,-1);
0105     
0106     
0107     return 1;
0108 }
0109 
0110 //Check that file exists on disk
0111 //@return   true exists, false does not exists
0112 static PSInteger _exutil_fileexists(HPSCRIPTVM v)
0113 {
0114     const PSChar *s;
0115     PSBool b;
0116     
0117     if(PS_SUCCEEDED(ps_getstring(v,2,&s))) {
0118         
0119         if (ndrx_file_exists((char *)s))
0120         {
0121             b = PSTrue;
0122         }
0123         else
0124         {
0125             b = PSFalse;
0126         }
0127         
0128         ps_pushbool(v, b);
0129     }
0130     
0131     return 1;
0132 }
0133 
0134 //Write user log message
0135 //@param msg    Message
0136 static PSInteger _exutil_userlog(HPSCRIPTVM v)
0137 {
0138     const PSChar *s;
0139     if(PS_SUCCEEDED(ps_getstring(v,2,&s))){
0140         
0141         userlog_const (s);
0142         
0143         return 1;
0144     }
0145     return 0;
0146 }
0147 
0148 static PSInteger _exutil_chmod(HPSCRIPTVM v)
0149 {
0150     const PSChar *file;
0151     const PSChar *mode;
0152     char err[256];
0153     
0154     if(PS_SUCCEEDED(ps_getstring(v,2,&file)) &&
0155         PS_SUCCEEDED(ps_getstring(v,3,&mode))) {
0156         
0157         int mod;
0158         sscanf(mode, "%o", &mod);
0159         
0160         if (EXSUCCEED!=chmod(file, mod))
0161         {
0162             snprintf(err, sizeof(err), "chmod failed: %d:%s", 
0163                     errno, strerror(errno));
0164             return ps_throwerror(v,err);
0165         }
0166         
0167         
0168         return 1;
0169     }
0170     return 0;
0171 }
0172 
0173 //mkdir, change to 755 mode. 
0174 //Allow recursive mkdir. In that case we shall return an array
0175 //of directories created.
0176 //@param[script] dir    Diretory to create
0177 static PSInteger _exutil_mkdir(HPSCRIPTVM v)
0178 {
0179     const PSChar *s;
0180     char err[256];
0181     struct stat sb;
0182     
0183     if(PS_SUCCEEDED(ps_getstring(v,2,&s)))
0184     {
0185         /* Check folder for existance and create if missing */
0186         if (stat(s, &sb) != 0 || !S_ISDIR(sb.st_mode))
0187         {
0188             if (EXSUCCEED!=mkdir(s, 0777))
0189             {
0190                 snprintf(err, sizeof(err), "mkdir [%s] failed: %d:%s", 
0191                         s, errno, strerror(errno));
0192                 return ps_throwerror(v,err);
0193             }
0194         }
0195         
0196         return 1;
0197     }
0198     return 0;
0199 }
0200 
0201 /**
0202  * Remove directory
0203  * @param v
0204  * @return 
0205  */
0206 static PSInteger _exutil_rmdir(HPSCRIPTVM v)
0207 {
0208     const PSChar *s;
0209     char err[256];
0210     
0211     if(PS_SUCCEEDED(ps_getstring(v,2,&s)))
0212     {
0213         if (EXSUCCEED!=rmdir(s))
0214         {
0215             snprintf(err, sizeof(err), "rmdir [%s] failed: %d:%s", 
0216                     s, errno, strerror(errno));
0217             return ps_throwerror(v,err);
0218         }
0219         
0220         return 1;
0221     }
0222     return 0;
0223 }
0224 
0225 /**
0226  * Remove file
0227  * @param v
0228  * @return 
0229  */
0230 static PSInteger _exutil_unlink(HPSCRIPTVM v)
0231 {
0232     const PSChar *s;
0233     char err[256];
0234     
0235     if(PS_SUCCEEDED(ps_getstring(v,2,&s)))
0236     {
0237         if (EXSUCCEED!=unlink(s))
0238         {
0239             snprintf(err, sizeof(err), "unlink [%s] failed: %d:%s", 
0240                     s, errno, strerror(errno));
0241             return ps_throwerror(v,err);
0242         }
0243         
0244         return 1;
0245     }
0246     return 0;
0247 }
0248 
0249 /**
0250  * Return filename in path
0251  * @param v
0252  * @return 
0253  */
0254 static PSInteger _exutil_basename(HPSCRIPTVM v)
0255 {
0256     const PSChar *str;
0257     PSInteger memsize;
0258     PSChar * stemp;
0259     
0260     ps_getstring(v,2,&str);
0261     memsize = (ps_getsize(v,2)+1)*sizeof(PSChar);
0262     stemp = ps_getscratchpad(v,memsize);
0263     memcpy(stemp, str, memsize);
0264     
0265     ps_pushstring(v,basename(stemp),-1);
0266     
0267     return 1;
0268 }
0269 
0270 /**
0271  * return path to file
0272  * @param v
0273  * @return 
0274  */
0275 static PSInteger _exutil_dirname(HPSCRIPTVM v)
0276 {
0277     const PSChar *str;
0278     PSInteger memsize;
0279     PSChar * stemp;
0280     
0281     ps_getstring(v,2,&str);
0282     memsize = (ps_getsize(v,2)+1)*sizeof(PSChar);
0283     stemp = ps_getscratchpad(v,memsize);
0284     memcpy(stemp, str, memsize);
0285     
0286     ps_pushstring(v,dirname(stemp),-1);
0287     
0288     return 1;
0289 }
0290 
0291 /**
0292  * Convert hex to long number
0293  * TODO: move to stdstring
0294  * @param [script] hex (without 0x suffix)
0295  * @return [script] converted integer
0296  */
0297 static PSInteger _exutil_hex2int(HPSCRIPTVM v)
0298 {
0299     const PSChar *hex;
0300     long l;
0301     PSInteger ret=EXFAIL;
0302     
0303     ps_getstring(v,2,&hex);
0304     
0305     sscanf(hex, "%lx", &l);
0306     
0307     ret = l;
0308     
0309 out:
0310     
0311     ps_pushinteger(v, ret);
0312 
0313     return 1;
0314 }
0315 
0316 /**
0317  * Return random string
0318  * @param v
0319  * @param [script] len
0320  * @return [script] random string a-zA-Z0-9
0321  */
0322 static PSInteger _exutil_rands(HPSCRIPTVM v)
0323 {
0324     PSChar *stemp;
0325     PSInteger len;
0326     char table[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
0327     int i, tablen;
0328     
0329     ps_getinteger(v,2,&len);
0330     
0331     PSInteger memsize = (len+1)*sizeof(PSChar);
0332     stemp = ps_getscratchpad(v,memsize);
0333     
0334     memset(stemp, 0, (len+1)*sizeof(PSChar));
0335     
0336     tablen = strlen(table);
0337     for (i=0; i<len; i++)
0338     {
0339         stemp[i]= table[ndrx_rand() % tablen];
0340     }
0341     
0342     ps_pushstring(v,stemp,-1);
0343     
0344     return 1;
0345 }
0346 
0347 
0348 /**
0349  * Parse clopt, with <block1> -- free args
0350  * @param v PS virtual machine
0351  * @param [script] clopt command line options
0352  * @param [script] optstring for getopt
0353  * @param [script] groups groups of argsX
0354  * @return {.args1[{.opt, .val}], .args2[{.opt, .val}] .freeargs[]}
0355  */
0356 static PSInteger _exutil_parseclopt(HPSCRIPTVM v, int nr_groups)
0357 {
0358     int ret = PS_OK;
0359     const PSChar *argv, *optstring, *optstring2;
0360     int c;
0361     char *token=NULL;
0362     PSInteger memsize;
0363     PSChar * stemp;
0364     char seps[] = NDRX_CMDLINE_SEP; /* to avoid c++ warning */
0365     char quotes[] = "\"";
0366     ndrx_growlist_t list;
0367     int index;
0368     int bufsz;
0369     int i;
0370     ps_getstring(v,2,&argv);
0371     ps_getstring(v,3,&optstring);
0372     
0373     if (nr_groups > 1)
0374     {
0375         ps_getstring(v,4,&optstring2);
0376     }
0377     
0378     bufsz = strlen(argv)+1;
0379     memsize = (bufsz)*sizeof(PSChar);
0380     stemp = ps_getscratchpad(v,memsize);
0381     
0382     ndrx_growlist_init(&list, 10, sizeof(char *));
0383     
0384     /* getopt require this: */
0385     if (EXSUCCEED!=ndrx_growlist_append(&list, (void *)&token))
0386     {
0387         NDRX_LOG(log_error, "ndrx_growlist_append() failed - oom?");
0388         ret=PS_ERROR;
0389         goto out;
0390     }
0391     
0392     /* load dummy name for parse... */
0393     NDRX_STRCPY_SAFE_DST(stemp, argv, bufsz);
0394     
0395     /* have strtok which respects quoted strings... */
0396     token = ndrx_strtokblk(stemp, seps, quotes);
0397     while( token != NULL )
0398     {
0399         /* Store the token up there... */
0400         if (EXSUCCEED!=ndrx_growlist_append(&list, (void *)&token))
0401         {
0402             NDRX_LOG(log_error, "ndrx_growlist_append() failed - oom?");
0403             ret=PS_ERROR;
0404             goto out;
0405         }
0406         
0407         /* Push tokens to array */
0408         token = ndrx_strtokblk( NULL, seps, quotes);
0409     }
0410     
0411 #ifdef __GNU_LIBRARY__
0412     optind=0; /* reset lib, so that we can scan again. */
0413 #else
0414     optind=1; /* reset lib, so that we can scan again. */
0415 #endif
0416     
0417     /* return value table 
0418      * table stays on the stack to have return value.
0419      */
0420     ps_newtable(v);
0421     
0422     for (i=0; i<nr_groups; i++)
0423     {
0424         char key[16];
0425         const PSChar *p_opts = optstring;
0426         
0427         if (i==1)
0428         {
0429             p_opts = optstring2;
0430         }
0431         
0432         snprintf(key, sizeof(key), "args%d", i+1);
0433         
0434         /* set the hash key... */
0435         ps_pushstring(v, key,-1);
0436         /* the value is array */
0437         ps_newarray(v, 0);
0438 
0439         while ((c = getopt (list.maxindexused+1, (char **)list.mem, (const char *)p_opts)) != -1)
0440         {
0441             char opt[2] = {(char)c, EXEOS};
0442             
0443             /* Load parsed argument */
0444             ps_newtable(v);
0445 
0446             ps_pushstring(v,"opt",-1);
0447             ps_pushstring(v,opt,-1);
0448             ps_newslot(v,-3,PSFalse);
0449 
0450             if (NULL!=optarg)
0451             {
0452                 ps_pushstring(v,"val",-1);
0453                 ps_pushstring(v,optarg,-1);
0454                 ps_newslot(v,-3,PSFalse);
0455             }
0456 
0457             ps_arrayappend(v,-2);
0458         }
0459         ps_newslot(v,-3,PSFalse);
0460     }
0461     
0462     /* set the hash key... */
0463     ps_pushstring(v,"freeargs",-1);
0464     
0465     /* value is array */
0466     ps_newarray(v, 0);
0467     
0468     for (index = optind; index < list.maxindexused+1; index++)
0469     {
0470         ps_pushstring(v,((char **)list.mem)[index],-1);
0471         ps_arrayappend(v,-2);
0472     }
0473 
0474     ps_newslot(v,-3,PSFalse);
0475     
0476 out:
0477     
0478     ndrx_growlist_free(&list);
0479 
0480     if (PS_OK==ret)
0481     {
0482         return 1;
0483     }
0484     else
0485     {
0486         return ps_throwerror(v, "Failed to process");
0487     }
0488 }
0489 
0490 /**
0491  * Parse clopt with 1 group
0492  * @param [script] clopt first group -- free args
0493  * @param [script] optstring 
0494  * @return see _exutil_parseclopt
0495  */
0496 static PSInteger _exutil_parseclopt1(HPSCRIPTVM v)
0497 {
0498     return _exutil_parseclopt(v, 1);
0499 }
0500 
0501 /**
0502  * Parse clopt with 2 groups -a -r -g -s 
0503  * @param [script] clot first group -- second group -- free args
0504  * @param optstring1 opt string for first group
0505  * @param optstring2 opt string for for second group
0506  * @return see _exutil_parseclopt
0507  */
0508 static PSInteger _exutil_parseclopt2(HPSCRIPTVM v)
0509 {
0510     return _exutil_parseclopt(v, 2);
0511 }
0512 
0513 /**
0514  * Check confirm call
0515  * @param [script] Message
0516  * @return [script] TRUE (accept) / FALSE (rejected)
0517  */
0518 static PSInteger _exutil_chk_confirm(HPSCRIPTVM v)
0519 {
0520     const PSChar *str;
0521     PSInteger ret;
0522     
0523     ps_getstring(v,2,&str);
0524     
0525     ret = ndrx_chk_confirm((char *)str, EXFALSE);
0526 
0527     ps_pushinteger(v, ret);
0528     return 1;
0529 }
0530 
0531 /**
0532  * Print to stdout
0533  * @param [stdout] message
0534  * @return 1
0535  */
0536 static PSInteger _exutil_print_stdout(HPSCRIPTVM v)
0537 {
0538     const PSChar *str;
0539     
0540     ps_getstring(v,2,&str);
0541     
0542     fprintf(stdout, "%s", str);    
0543     return 1;
0544 }
0545 
0546 /**
0547  * Print to stderr
0548  * @param [stdout] message
0549  * @return 1
0550  */
0551 static PSInteger _exutil_print_stderr(HPSCRIPTVM v)
0552 {
0553     const PSChar *str;
0554     
0555     ps_getstring(v,2,&str);
0556     
0557     fprintf(stdout, "%s", str);    
0558     return 1;
0559 }
0560 
0561 #define _DECL_FUNC(name,nparams,pmask) {_SC(#name),_exutil_##name,nparams,pmask}
0562 static PSRegFunction exutillib_funcs[]={
0563     _DECL_FUNC(getline,1,_SC(".s")),
0564         _DECL_FUNC(getcwd,1,_SC(".s")),
0565         _DECL_FUNC(getosname,1,_SC(".s")),
0566         _DECL_FUNC(getpoller,1,_SC(".s")),
0567         _DECL_FUNC(getwizardbase,1,_SC(".s")),
0568         _DECL_FUNC(userlog,2,_SC(".s")),
0569         _DECL_FUNC(mkdir,2,_SC(".s")),
0570         _DECL_FUNC(rmdir,2,_SC(".s")),
0571         _DECL_FUNC(unlink,2,_SC(".s")),
0572         _DECL_FUNC(fileexists,2,_SC(".s")),
0573         _DECL_FUNC(chmod,3,_SC(".ss")),
0574         _DECL_FUNC(basename,2,_SC(".s")),
0575         _DECL_FUNC(dirname,2,_SC(".s")),
0576         _DECL_FUNC(rands,2,_SC(".n")),
0577         _DECL_FUNC(parseclopt1,3,_SC(".ss")),
0578         _DECL_FUNC(parseclopt2,4,_SC(".sss")),
0579         _DECL_FUNC(hex2int,2,_SC(".s")),
0580         _DECL_FUNC(chk_confirm,2,_SC(".s")),
0581         _DECL_FUNC(print_stdout,2,_SC(".s")),
0582         _DECL_FUNC(print_stderr,2,_SC(".s")),
0583     {0,0}
0584 };
0585 #undef _DECL_FUNC
0586 
0587 PSInteger psstd_register_exutillib(HPSCRIPTVM v)
0588 {
0589     PSInteger i=0;
0590     while(exutillib_funcs[i].name!=0)
0591     {
0592         ps_pushstring(v,exutillib_funcs[i].name,-1);
0593         ps_newclosure(v,exutillib_funcs[i].f,0);
0594         ps_setparamscheck(v,exutillib_funcs[i].nparamscheck,exutillib_funcs[i].typemask);
0595         ps_setnativeclosurename(v,-1,exutillib_funcs[i].name);
0596         ps_newslot(v,-3,PSFalse);
0597         i++;
0598     }
0599     return 1;
0600 }
0601 /* vim: set ts=4 sw=4 et smartindent: */