Back to home page

Enduro/X

 
 

    


0001 /**
0002  * @brief Generate main() for the XATMI server
0003  *
0004  * @file buildserver.c
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 
0035 /*---------------------------Includes-----------------------------------*/
0036 
0037 #include <unistd.h>
0038 #include <stdio.h>
0039 #include <errno.h>
0040 #include <stdlib.h>
0041 #include <ndrx_config.h>
0042 #include <atmi.h>
0043 #include <atmi_int.h>
0044 #include <sys_unix.h>
0045 #include <ctype.h>
0046 #include <limits.h>
0047 
0048 #include <ubf.h>
0049 #include <ferror.h>
0050 #include <fieldtable.h>
0051 #include <fdatatype.h>
0052 
0053 #include <ndrstandard.h>
0054 #include <ndebug.h>
0055 #include "buildtools.h"
0056 
0057 /*---------------------------Externs------------------------------------*/
0058 /*---------------------------Macros-------------------------------------*/
0059 /*---------------------------Enums--------------------------------------*/
0060 /*---------------------------Typedefs-----------------------------------*/
0061 /*---------------------------Globals------------------------------------*/
0062 /*---------------------------Statics------------------------------------*/
0063 exprivate bs_svcnm_lst_t *M_bs_svcnm_lst = NULL;  /**< list of services  */
0064 exprivate bs_svcnm_lst_t *M_bs_funcnm_lst = NULL; /**< list of functions */
0065 
0066 /**
0067  * Check service name in list. If found then skip
0068  * @param svcnm - Service name to check
0069  * @return EXSUCCEED(found & skip)/EXFAIL
0070  */
0071 exprivate int chk_listed_svcnm(char *svcnm)
0072 {
0073     bs_svcnm_lst_t * ret = NULL;
0074 
0075     EXHASH_FIND_STR( M_bs_svcnm_lst, svcnm, ret);
0076     
0077     if (NULL==ret)
0078     {
0079         NDRX_LOG(log_debug, "Service name [%s] not in list", svcnm);
0080         goto out;
0081     }
0082 
0083 out:
0084     if (NULL==ret)
0085         return EXFAIL;
0086     else
0087         return EXSUCCEED;
0088 }
0089 
0090 /**
0091  * Check function name in list. If found then skip
0092  * @param funcnm function name
0093  * @param funcreg if set to EXTRUE, it will be registered in service 
0094  *  table with out name
0095  * @return EXSUCCEED(found & skip)/EXFAIL
0096  */
0097 exprivate int chk_listed_funcnm(char *funcnm, int funcreg)
0098 {
0099     bs_svcnm_lst_t * ret = NULL;
0100 
0101     EXHASH_FIND_STR( M_bs_funcnm_lst, funcnm, ret);
0102     
0103     if (NULL==ret)
0104     {
0105         NDRX_LOG(log_debug, "Function name [%s] not in list", funcnm);
0106         goto out;
0107     }
0108 
0109     if (funcreg && !ret->funcreg)
0110     {
0111         ret->funcreg = EXTRUE;
0112     }
0113 
0114 out:
0115     if (NULL==ret)
0116     {
0117         return EXFAIL;
0118     }
0119     else
0120     {
0121         return EXSUCCEED;
0122     }
0123 }
0124 
0125 /**
0126  * Add add SVCNM/FUNCNM to list
0127  * @param svcnm - Service name add to list
0128  * @param funcnm - Function name add to list
0129  * @return EXSUCCEED/EXFAIL
0130  */
0131 exprivate int add_listed_svcnm(char *svcnm, char *funcnm)
0132 {
0133     bs_svcnm_lst_t * ret = NDRX_CALLOC(1, sizeof(bs_svcnm_lst_t));
0134     
0135     if (NULL==ret)
0136     {
0137         int err = errno;
0138         
0139         _Nset_error_fmt(NEMALLOC, "Failed to alloc: %s", strerror(err));
0140         
0141         NDRX_LOG(log_error, 
0142                  "Failed to alloc bs_svcnm_lst_t: %s", strerror(errno));
0143         goto out;
0144     }
0145     
0146     NDRX_STRCPY_SAFE(ret->svcnm, svcnm);
0147     NDRX_STRCPY_SAFE(ret->funcnm, funcnm);
0148     
0149     EXHASH_ADD_STR( M_bs_svcnm_lst, svcnm, ret );
0150     
0151 out:
0152     if (NULL==ret)
0153     {
0154         return EXFAIL;
0155     }
0156     
0157     return EXSUCCEED;
0158 }
0159 
0160 /**
0161  * Add add FUNCNM to list
0162  * @param funcnm - Function name add to cache
0163  * @param funcreg if set to EXTRUE, it will be registered in service 
0164  *  table with out name
0165  * @return EXSUCCEED/EXFAIL
0166  */
0167 exprivate int add_listed_funcnm(char *funcnm, int funcreg)
0168 {
0169     bs_svcnm_lst_t * ret = NDRX_CALLOC(1, sizeof(bs_svcnm_lst_t));
0170     
0171     if (NULL==ret)
0172     {
0173         int err = errno;
0174         _Nset_error_fmt(NEMALLOC, "Failed to alloc: %s", strerror(err));
0175         NDRX_LOG(log_error, 
0176                  "Failed to alloc bs_svcnm_lst_t: %s", strerror(errno));
0177         goto out;
0178     }
0179     
0180     NDRX_STRCPY_SAFE(ret->funcnm, funcnm);
0181     ret->funcreg = funcreg;
0182     EXHASH_ADD_STR( M_bs_funcnm_lst, funcnm, ret );
0183     
0184 out:
0185     if (NULL==ret)
0186     {
0187         return EXFAIL;
0188     }
0189     
0190     return EXSUCCEED;
0191 }
0192 
0193 /**
0194  * Function to parse Service/Function from string 
0195  * Format: service[,service...][:function] | :function } ]
0196  * this could be:
0197  * 
0198  * -s a,b,c
0199  * -s a,b,c:FUNC
0200  * -s :FUNC
0201  * 
0202  * NOTE! Empty functions are allowed too. They will be registered in the service
0203  * table.
0204  * 
0205  * @param s_value string to be parsed
0206  * @param advtbl advertising table to return
0207  * @return EXSUCCEED/EXFAIL
0208  */
0209 exprivate int parse_s_string(char *p_string)
0210 {
0211     int ret = EXSUCCEED;
0212     char svcnm[128+1]={EXEOS};
0213     char funcnm[MAXTIDENT+1]={EXEOS};
0214     char *f=NULL, *p=NULL, *str=NULL;
0215     
0216     f=strchr(p_string, ':');
0217     
0218     if (NULL != f)
0219     {
0220         NDRX_STRCPY_SAFE(funcnm, f+1);
0221         *f = EXEOS; /* terminate the parsing string here.. */
0222     }
0223 
0224     /* In case when not provided SVCNM 
0225      * If : was in start of the string.. the pointer matches
0226      */
0227     if (NULL != f && p_string==f)
0228     {
0229         NDRX_LOG(log_debug, "FUNCNM=[%s] Only", funcnm);
0230         
0231         if (EXSUCCEED != chk_listed_funcnm(funcnm, EXTRUE) && 
0232                 EXSUCCEED!=add_listed_funcnm(funcnm, EXTRUE))
0233         {
0234             EXFAIL_OUT(ret);
0235         }
0236         /* we are done... */
0237         return ret;
0238     }
0239     
0240     /* lets continue to parse -s A,B,C with */
0241     for (p = strtok_r(p_string, ",", &str);p != NULL; p = strtok_r(NULL, ",", &str))
0242     {
0243         /* Function name is provided */
0244         if (NULL != f)
0245         {
0246             NDRX_STRCPY_SAFE(funcnm, f+1);
0247         }
0248         /* Function name not provided, set as Service name*/
0249         else 
0250         {
0251             NDRX_STRCPY_SAFE(funcnm, p);
0252         }
0253 
0254         NDRX_STRCPY_SAFE(svcnm, p);
0255 
0256         NDRX_LOG(log_debug, "SVCNM=[%s] FUNCNM=[%s]\n", svcnm, funcnm);
0257         
0258         /* Add function */
0259         if (EXSUCCEED != chk_listed_funcnm(funcnm, EXFALSE) && 
0260                 EXSUCCEED!=add_listed_funcnm(funcnm, EXFALSE))
0261         {
0262             NDRX_LOG(log_error, "Failed to list the function name");
0263             EXFAIL_OUT(ret);
0264         }
0265         
0266         if (EXSUCCEED == chk_listed_svcnm(svcnm))
0267         {
0268             NDRX_LOG(log_debug, 
0269                      "Warning svcnm=[%s] already exist SKIP!!!", svcnm);
0270             /* already present, process next */
0271             continue;
0272         }
0273         
0274         if (EXSUCCEED!=add_listed_svcnm(svcnm, funcnm))
0275         {
0276             NDRX_LOG(log_error, "Failed to add service [%s]", svcnm);
0277             EXFAIL_OUT(ret);
0278         }
0279     }
0280    
0281 
0282 out:
0283     return ret;
0284 }
0285 
0286 /**
0287  * print help for the command
0288  * @param name name of the program, argv[0]
0289  */
0290 exprivate void print_help(char *name)
0291 {
0292     fprintf(stderr, "Usage: %s [options]\n", name);
0293     fprintf(stderr, "Options:\n");
0294     fprintf(stderr, "  -n               Do not generate main() entry\n");
0295     fprintf(stderr, "  -C               COBOL code (RFU)\n");
0296     fprintf(stderr, "  -s {@filename|svc1,svc2,...:func|:func}\n");
0297     fprintf(stderr, "                   Services to be advertised. In case of @filename. \n");
0298     fprintf(stderr, "                   Each line in file shall contain the {svc1,svc2,...:func|:func} expression.\n");
0299     fprintf(stderr, "                   Lines starting with # are ignored\n");
0300     fprintf(stderr, "  -o <filename>    Output compiled file name, default is SERVER\n");
0301     fprintf(stderr, "  -f <firstfiles>  File names to be passed to compiler, on left side before Enduro/X libraries\n");
0302     fprintf(stderr, "  -a <firstfiles>  Alias of -f\n");
0303     fprintf(stderr, "  -l <lastfiles>   File names to be passed to compiler, on right side after Enduro/X libraries\n");
0304     fprintf(stderr, "  -r <rm_name>     Resource manager name to be searched in $NDRX_HOME/udataobj/RM.\n");
0305     fprintf(stderr, "                   If not set, null switch is used.\n");
0306     fprintf(stderr, "  -g <rm_name>     Same as -r\n");
0307     fprintf(stderr, "  -k               Keep generated source file\n");
0308     fprintf(stderr, "  -t               Program is built for threaded mode\n");
0309     fprintf(stderr, "  -v               Verbose mode (print build command)\n");
0310     fprintf(stderr, "  -h               Print this help\n");   
0311 }
0312 
0313 /**
0314  * Function to read Service/Function from file
0315  * @param s_value File name to load Services/Function
0316  * @param advtbl advertising table to return
0317  * @return EXSUCCEED/EXFAIL
0318  */
0319 exprivate int parse_s_file(char *infile)
0320 {
0321     int ret = EXSUCCEED;
0322     FILE * fp;
0323     char buf[NDRX_BPATH_MAX+1];
0324 
0325     if (NULL==(fp=NDRX_FOPEN(infile, "r")))
0326     {
0327         int err = errno;
0328         
0329         _Nset_error_fmt(NENOENT, "Failed to open file [%s] for reading: %s", 
0330                 infile, strerror(err));
0331         
0332         NDRX_LOG(log_error, "Failed to open file [%s] for reading: %s", 
0333                 infile, strerror(errno));
0334         EXFAIL_OUT(ret);
0335     }
0336 
0337     while (NULL!=fgets(buf, sizeof(buf), fp))
0338     {
0339         char *stripped;
0340         ndrx_str_rstrip(buf," \t\n\r");
0341         stripped = ndrx_str_lstrip_ptr(buf," \t\n\r");
0342         
0343         if (EXEOS==stripped[0] || '#'==stripped[0])
0344         {
0345             continue;
0346         }
0347         
0348         if ( EXSUCCEED!= parse_s_string(stripped) )
0349         {
0350             EXFAIL_OUT(ret);
0351         }
0352     }
0353     
0354 out:
0355     
0356     if (NULL!=fp)
0357     {
0358         NDRX_FCLOSE(fp);
0359         fp = NULL;
0360     }
0361 
0362     return ret;
0363 }
0364 
0365 /**
0366  * Main entry point for view compiler
0367  */
0368 int main(int argc, char **argv)
0369 {
0370     int ret = EXSUCCEED;
0371     int c;
0372     int lang_mode = HDR_C_LANG;
0373     char ofile[NDRX_BPATH_MAX+1]="SERVER";
0374     char cfile[NDRX_BPATH_MAX+1]="ndrx_bs_XXXXXX.c";
0375     char *s_value=NULL;
0376     int thread_option=EXFALSE;
0377     int keep_main=EXFALSE;
0378     char firstfiles[NDRX_BPATH_MAX+1] = {EXEOS};
0379     char lastfiles[NDRX_BPATH_MAX+1] = {EXEOS};
0380     int nomain = EXFALSE;
0381     int verbose = EXFALSE;
0382     FILE *out_fptr = NULL;
0383     ndrx_rm_def_t rmdef;
0384     bs_svcnm_lst_t *el, *elt;
0385     
0386     NDRX_BANNER("BUILDSERVER Tool");
0387     
0388     /* clear any error... */
0389     _Nunset_error();
0390     
0391     memset(&rmdef, 0, sizeof(rmdef));
0392 
0393     while ((c = getopt (argc, argv, "Cktvr:g:s:o:f:l:nha:")) != -1)
0394     {
0395         switch (c)
0396         {
0397             case 'h':
0398                 print_help(argv[0]);
0399                 return 0; /*<<<< RETURN ! */
0400                 break;
0401             case 'n':
0402                 /* No main... */
0403                 NDRX_LOG(log_debug, "Not generating main...");
0404                 nomain=EXTRUE;
0405                 break;
0406             case 'C':
0407                 NDRX_LOG(log_warn, "COBOL mode not yet supported");
0408                 _Nset_error_fmt(NESUPPORT, "COBOL mode not yet supported");
0409                 EXFAIL_OUT(ret);
0410                 break;
0411             case 's':
0412                 s_value= optarg;
0413                 NDRX_LOG(log_debug, "s_value: [%s]", s_value);
0414                 if ( '@'==s_value[0] )
0415                 {
0416                     if (EXSUCCEED != parse_s_file(s_value+1) )
0417                     {
0418                         NDRX_LOG(log_warn, 
0419                              "Failed to read Service/Function from [%s]", 
0420                              s_value);
0421                         EXFAIL_OUT(ret);
0422                     }
0423                 }
0424                 else 
0425                 {
0426                     if ( EXSUCCEED != parse_s_string(s_value) )
0427                     {
0428                         NDRX_LOG(log_error, 
0429                              "Failed to parse Service/Function from value [%s]", 
0430                              s_value);
0431                         EXFAIL_OUT(ret);
0432                     }
0433                 }
0434                 break;
0435             case 'o':
0436                 NDRX_STRCPY_SAFE(ofile, optarg);
0437                 NDRX_LOG(log_debug, "ofile: [%s]", ofile);
0438                 break;
0439             case 'a':
0440             case 'f':
0441                 if (EXEOS==firstfiles[0])
0442                 {
0443                     NDRX_STRCPY_SAFE(firstfiles, optarg);
0444                 }
0445                 else
0446                 {
0447                     NDRX_STRCAT_S(firstfiles, sizeof(firstfiles), " ");
0448                     NDRX_STRCAT_S(firstfiles, sizeof(firstfiles), optarg);
0449                 }
0450                 break;
0451             case 'l':
0452                 if (EXEOS==lastfiles[0])
0453                 {
0454                     NDRX_STRCPY_SAFE(lastfiles, optarg);
0455                 }
0456                 else
0457                 {
0458                     NDRX_STRCAT_S(lastfiles, sizeof(lastfiles), " ");
0459                     NDRX_STRCAT_S(lastfiles, sizeof(lastfiles), optarg);
0460                 }
0461                 break;
0462             case 'r':
0463             case 'g':
0464                 
0465                 if ( EXFAIL == (ret=ndrx_get_rm_name(optarg, &rmdef)))
0466                 {
0467                     /* error is set */
0468                     NDRX_LOG(log_error, 
0469                          "Failed to parse resource manager: [%s], check -r", optarg);
0470                     EXFAIL_OUT(ret);
0471                 }
0472                 else if (EXTRUE!=ret)
0473                 {
0474                     NDRX_LOG(log_error, 
0475                          "Resource manager not defined: [%s], check -r", optarg);
0476                     /* set error */
0477                     _Nset_error_fmt(NEINVAL, "Resource manager [%s] not found "
0478                             "in udataobj/RM files", optarg);
0479                     EXFAIL_OUT(ret);
0480                 }
0481                 
0482                 ret = EXSUCCEED;
0483 
0484                 break;
0485             case 'k':
0486                 keep_main=EXTRUE;
0487                 break;
0488             case 't':
0489                 thread_option = EXTRUE;
0490                 break;
0491             case 'v':
0492                 NDRX_LOG(log_debug, "running in verbose mode");
0493                 verbose = EXTRUE;
0494                 break;
0495             
0496             case '?':
0497             default:
0498             
0499                 print_help(argv[0]);
0500                 return EXFAIL; /*<<<< RETURN ! */
0501         }
0502     }
0503     
0504     /* Plot the the header */
0505     if (HDR_C_LANG==lang_mode)
0506     {
0507         if ( NULL==(out_fptr=ndrx_mkstemps(cfile,2, 0) ))
0508         {
0509             int err = errno;
0510             NDRX_LOG(log_error, "Failed with error %s", strerror(err));
0511             _Nset_error_fmt(NEUNIX, "Failed to create temporary file: %s", 
0512                     strerror(err));
0513             EXFAIL_OUT(ret);
0514         }
0515         
0516         if (EXSUCCEED!=ndrx_buildsrv_generate_code(&out_fptr, cfile, thread_option, 
0517                                                    M_bs_svcnm_lst, 
0518                                                    M_bs_funcnm_lst,
0519                                                    &rmdef, nomain))
0520         {
0521             NDRX_LOG(log_error, "Failed to generate code!");
0522             EXFAIL_OUT(ret);
0523         }
0524     }
0525     
0526     if (HDR_C_LANG==lang_mode)
0527     {
0528         if (EXSUCCEED!=ndrx_compile_c(COMPILE_SRV, verbose, cfile, ofile, 
0529                 firstfiles, lastfiles, &rmdef))
0530         {
0531             NDRX_LOG(log_error, "Failed to build");
0532             EXFAIL_OUT(ret);
0533         }
0534     }
0535     else
0536     {
0537         NDRX_LOG(log_error, "Invalid language mode: %d", lang_mode);
0538         _Nset_error_fmt(NEINVAL, "Invalid language mode %d", lang_mode);
0539         EXFAIL_OUT(ret);
0540     }
0541     
0542 out:
0543 
0544     /* cleanup hash lists... */
0545     if (EXSUCCEED!=ret)
0546     {
0547         if (!_Nis_error())
0548         {
0549             _Nset_error_fmt(NESYSTEM, "Generic error - see logs.");
0550         }
0551         
0552         /* print error */
0553         fprintf(stderr, "%s: %s\n", argv[0], ndrx_Nstrerror2(Nerror));
0554     }
0555 
0556     if (NULL!=out_fptr)
0557     {
0558         NDRX_FCLOSE(out_fptr);
0559     }
0560 
0561     if (EXFALSE == keep_main)
0562     {
0563         unlink(cfile);
0564     }
0565 
0566     /* do some cleanup... */
0567     EXHASH_ITER(hh, M_bs_svcnm_lst, el, elt)
0568     {
0569         EXHASH_DEL(M_bs_svcnm_lst, el);
0570         NDRX_FREE(el);
0571     }
0572     
0573     EXHASH_ITER(hh, M_bs_funcnm_lst, el, elt)
0574     {
0575         EXHASH_DEL(M_bs_funcnm_lst, el);
0576         NDRX_FREE(el);
0577     }
0578 
0579     return ret;
0580 }
0581 
0582 /* vim: set ts=4 sw=4 et smartindent: */