Annotation of freem/src/global_dispatch.c, revision 1.11

1.1       snw         1: /*
1.11    ! snw         2:  *   $Id: global_dispatch.c,v 1.10 2025/04/13 04:22:43 snw Exp $
1.1       snw         3:  *    global handler dispatch module
                      4:  *
                      5:  *  
1.3       snw         6:  *   Author: Serena Willis <snw@coherent-logic.com>
1.1       snw         7:  *    Copyright (C) 1998 MUG Deutschland
1.4       snw         8:  *    Copyright (C) 2020, 2025 Coherent Logic Development LLC
1.1       snw         9:  *
                     10:  *
                     11:  *   This file is part of FreeM.
                     12:  *
                     13:  *   FreeM is free software: you can redistribute it and/or modify
                     14:  *   it under the terms of the GNU Affero Public License as published by
                     15:  *   the Free Software Foundation, either version 3 of the License, or
                     16:  *   (at your option) any later version.
                     17:  *
                     18:  *   FreeM is distributed in the hope that it will be useful,
                     19:  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
                     20:  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     21:  *   GNU Affero Public License for more details.
                     22:  *
                     23:  *   You should have received a copy of the GNU Affero Public License
                     24:  *   along with FreeM.  If not, see <https://www.gnu.org/licenses/>.
                     25:  *
1.5       snw        26:  *   $Log: global_dispatch.c,v $
1.11    ! snw        27:  *   Revision 1.10  2025/04/13 04:22:43  snw
        !            28:  *   Fix snprintf calls
        !            29:  *
1.10      snw        30:  *   Revision 1.9  2025/04/10 01:24:38  snw
                     31:  *   Remove C++ style comments
                     32:  *
1.9       snw        33:  *   Revision 1.8  2025/04/09 19:52:02  snw
                     34:  *   Eliminate as many warnings as possible while building with -Wall
                     35:  *
1.8       snw        36:  *   Revision 1.7  2025/04/09 15:16:50  snw
                     37:  *   Fix buffer overruns in mref_to_external and ssvn.c
                     38:  *
1.7       snw        39:  *   Revision 1.6  2025/03/29 16:50:42  snw
                     40:  *   Back to cvs-current as version for development; temp fix for double-free issue in global_dispatch
                     41:  *
1.6       snw        42:  *   Revision 1.5  2025/03/24 04:13:11  snw
                     43:  *   Replace action macro dat with fra_dat to avoid symbol conflict on OS/2
                     44:  *
1.5       snw        45:  *   Revision 1.4  2025/03/09 19:14:25  snw
                     46:  *   First phase of REUSE compliance and header reformat
                     47:  *
1.4       snw        48:  *
                     49:  * SPDX-FileCopyrightText:  (C) 2025 Coherent Logic Development LLC
                     50:  * SPDX-License-Identifier: AGPL-3.0-or-later
1.1       snw        51:  **/
                     52: 
                     53: #include <stdlib.h>
                     54: #include <string.h>
                     55: #include <unistd.h>
                     56: #include <ctype.h>
                     57: 
                     58: #include "mpsdef.h"
                     59: #include "mref.h"
                     60: #include "events.h"
                     61: #include "config.h"
                     62: #include "namespace.h"
                     63: #include "transact.h"
                     64: #include "mdebug.h"
                     65: #include "journal.h"
                     66: #include "iftab.h"
                     67: #include "shmmgr.h"
1.11    ! snw        68: #include "log.h"
1.1       snw        69: 
                     70: void (*gbl_u)(short, char *, char *);
                     71: void (*gbl_s)(short, char *, char *);
                     72: 
                     73: void global_set_engine(char ns, char *engine)
                     74: {
1.8       snw        75:                 
                     76:     if (strcmp (engine, "BUILTIN") != 0) {
1.1       snw        77: 
                     78:         printf ("\r\nERROR:  '%s' is not a valid global storage engine\r\n", engine);
                     79:         merr_raise (M38);
                     80:         
                     81:         return;
                     82:         
                     83:     }
                     84: 
                     85:     switch (ns) {
                     86: 
                     87:         case 'u':
                     88:             strcpy (gbl_u_engine, engine);
                     89: 
                     90:             if (strcmp (engine, "BUILTIN") == 0) {
                     91:                 gbl_u = &global_bltin;
                     92:             }
                     93:             else {
1.11    ! snw        94:                 logprintf (FM_LOG_WARNING, "global_set_engine:  invalid global handler '%s' or FreeM built without '%s' global handler support", engine, engine);
        !            95:                 logprintf (FM_LOG_WARNING, "global_set_engine:  defaulting to 'BUILTIN' global handler for namespace '%s'", nsname);
1.1       snw        96:                 gbl_u = &global_bltin;
                     97:             }
                     98:            
                     99:             break;
                    100: 
                    101:         case 's':
                    102:             strcpy (gbl_s_engine, engine);
                    103: 
                    104:             if (strcmp (engine, "BUILTIN") == 0) {
                    105:                 gbl_s = &global_bltin;
                    106:             }
                    107:             else {
1.11    ! snw       108:                 logprintf (FM_LOG_WARNING, "global_set_engine:  invalid global handler '%s' or FreeM built without '%s' global handler support", engine, engine);
        !           109:                 logprintf (FM_LOG_WARNING, "global_set_engine:  defaulting to 'BUILTIN' global handler for namespace 'SYSTEM'");
1.1       snw       110:                 gbl_s = &global_bltin;
                    111:             }
                    112:             
                    113:             break;
                    114: 
                    115:     }
                    116: 
                    117:     merr_raise (OK);
                    118:     return;
                    119:     
                    120: }
                    121: 
                    122: void global (short action, char *key, char *data)
                    123: {
                    124: 
                    125:     int ierr_sav = OK;
                    126: 
                    127:     char *ptr;
                    128:     char name[256];
                    129:     char old_gloplib[PATHLEN];
                    130:     register int i = 0;
                    131:     register int j = 0;
                    132:     register char ch;
                    133: 
                    134:     char *old_ns;
                    135:     char *old_value;
                    136:     char *new_value;
                    137:     char *tk_buf;
                    138:     char *mapk_buf;
                    139:     char *mapd_buf;
                    140:     freem_ref_t *r;
                    141:     short extref_flg;
                    142:     short mapped_flg;
                    143: 
                    144:     /* variables for transaction-in-flight symbol table */
                    145:     iftab *ift; 
                    146:     char tmpd[256];          
                    147: 
                    148:     old_ns = (char *) malloc (STRLEN * sizeof (char));
                    149:     NULLPTRCHK(old_ns,"global");
                    150:     
                    151:     old_value = (char *) malloc (STRLEN * sizeof (char));
                    152:     NULLPTRCHK(old_value,"global");
                    153: 
                    154:     new_value = (char *) malloc (STRLEN * sizeof (char));
                    155:     NULLPTRCHK(new_value,"global");
                    156: 
                    157:     tk_buf = (char *) malloc (STRLEN * sizeof (char));
                    158:     NULLPTRCHK(tk_buf,"global");
                    159: 
                    160:     mapk_buf = (char *) malloc (STRLEN * sizeof (char));
                    161:     NULLPTRCHK(mapk_buf,"global");
                    162: 
                    163:     mapd_buf = (char *) malloc (STRLEN * sizeof (char));
                    164:     NULLPTRCHK(mapd_buf,"global");
                    165:     
                    166:     r = (freem_ref_t *) malloc (sizeof (freem_ref_t));
                    167:     NULLPTRCHK(r,"global");
                    168: 
                    169:     extref_flg = FALSE;
                    170:     mapped_flg = FALSE;
                    171: 
                    172:     ptr = key;
                    173:     if (key[1] != '$') {
                    174:         while ((shm_config->hdr->tp_owner != pid) && (shm_config->hdr->tp_owner != 0)) {
                    175:             sleep (1);
                    176:         }
                    177:     }
                    178:     
                    179:     stcpy (tk_buf, key);
                    180:     
                    181:     if (key[1] != '$') frm_process_alias (key);
                    182: 
                    183:     if (key[1] != '$') {
                    184:         /* process mappings */
                    185:         ierr_sav = OK;
                    186:         
                    187:         while ((ch = *(ptr++)) != DELIM && ch != EOL && i < 256) {
                    188:             name[i++] = ch;
                    189:         }
                    190:         
                    191:         name[i] = '\0';
                    192:         
                    193:         snprintf (mapk_buf, STRLEN - 1, "^$SYSTEM\202MAPPINGS\202GLOBAL\202%s\201", name);
1.7       snw       194:         symtab_shm (get_sym, mapk_buf, mapd_buf);
1.1       snw       195: 
                    196:         stcnv_m2c (mapd_buf);
                    197:         
                    198:         if (merr () == OK) {
                    199:             mapped_flg = TRUE;
                    200:             strncpy (old_ns, nsname, STRLEN - 1);
                    201:             set_namespace (mapd_buf, 0);
                    202:             strncpy (old_gloplib, gloplib, PATHLEN - 1);
                    203:             strncpy (gloplib, glopath, PATHLEN - 1);
                    204:         }
                    205:         else {
                    206:             merr_raise (OK);
                    207:         }
                    208:     }
                    209:         
                    210:     if (dbg_enable_watch && (action == set_sym)) dbg_fire_watch (key);
                    211:     
                    212:     if ((jnl_enabled == TRUE) && (key[1] != '$') && (tp_committing == FALSE)) {
                    213:         switch (action) {
                    214:             
                    215:             case set_sym:
                    216:                 jnl_ent_write (JNLA_SET, key, data);
                    217:                 break;
                    218: 
                    219:             case kill_sym:
                    220:             case killone:
                    221:                 jnl_ent_write (JNLA_KILL, key, data);
                    222:                 break;
                    223:                 
                    224:         }
                    225:     }
                    226: 
                    227:     /* If we are writing to a global in a transaction but not committing it,
                    228:        queue up the operation at the current transaction level.*/
                    229:     if ((tp_level > 0) && (action == set_sym ||
                    230:                            action == kill_sym ||
                    231:                            action == killone ||
                    232:                            action == merge_sym) && (tp_committing == FALSE)) {        
                    233:         
                    234:         if (key[1] != '$') {
                    235:             tp_add_op (FALSE, action, key, data);
                    236: 
                    237:             merr_raise (OK);
                    238:             return;
                    239:         }
                    240:         
                    241:     }
                    242: 
                    243:     /* in a transaction and retrieving */
                    244:     if ((tp_level > 0) && (action == get_sym)) {
                    245: 
                    246:         /* check transactions-in-flight symbol table */
                    247:         ift = iftab_retrieve (key, tmpd);
                    248: 
                    249:         if (ift != NULL) {
                    250: 
                    251:             if (ift->killed == TRUE) {
                    252:                 merr_raise (M7);
                    253:             }
                    254:             else {
                    255:                 stcpy (data, ift->data);
                    256:                 merr_raise (OK);
                    257:             }
                    258: 
                    259:             return;
                    260:         }
                    261: 
                    262:         /* if we got here, the node referenced by "key" has not been
                    263:            modified in the current transaction, so we can proceed to
                    264:            the normal disk block retrieval. */
                    265:     }
                    266: 
                    267:     
                    268:     mref_init (r, MREF_RT_GLOBAL, "^DUMMY");
                    269:     internal_to_mref (r, key);
                    270: 
                    271:     if (rtn_dialect () == D_M77) {
                    272: 
                    273:         for (i = 0; i < r->subscript_count; i++) {
                    274:             for (j = 0; j < strlen (r->subscripts[i]); j++) {
                    275:                 
                    276:                 ch = r->subscripts[i][j];
                    277:                 
                    278:                 if (!isdigit (ch)) {
                    279:                     merr_raise (NOSTAND);
                    280:                     return;
                    281:                 }
                    282:                 
                    283:             }
                    284:         }
                    285:         
                    286:     }
                    287: 
                    288:     
1.2       snw       289:     if (r->name[1] == '|') {
1.1       snw       290: 
                    291:         /* this is an mdc-style extended reference */
                    292:         
                    293:         char old_code[512];
                    294:         char *old_codptr;
                    295:         char newns[256];       
                    296:         register int i = 0;
                    297:         char *nsstart;
                    298:         char *nssave;
                    299:         char ch;
                    300:         char *subprt;
                    301:         extref_flg = TRUE;
                    302: 
                    303:         /* save off current interpreter state (code and codptr)
                    304:            so we can call expr() without losing the plot */        
                    305:         stcpy (old_code, code);
                    306:         old_codptr = codptr;
                    307: 
                    308:         /* save off the current namespace */
                    309:         strncpy (old_ns, nsname, STRLEN - 1);
                    310:                 
                    311:         nsstart = r->name + 2;
                    312:         nssave = nsstart;
                    313: 
                    314:         /* grab everything between the vertical bars */
                    315:         while ((ch = *(nsstart++)) != '|') {
                    316:             newns[i++] = ch;
                    317:         }
                    318: 
                    319:         newns[i] = '\0';
                    320: 
                    321:         /* load up the namespace expression into the code buffer */
                    322:         strcpy (code, newns);
                    323:         strcat (code, " ");        
                    324:         stcnv_c2m (code);
                    325: 
                    326:         /* point the code pointer at the beginning of code */
                    327:         codptr = code;
                    328: 
                    329:         /* parse a string expression */
                    330:         expr (STRING);
                    331: 
                    332:         /* expr (STRING) stores its result in argptr */
                    333:         stcpy (newns, argptr);
                    334:         stcnv_m2c (newns);
                    335: 
                    336:         /* restore interpreter state */
                    337:         stcpy (code, old_code);
                    338:         codptr = old_codptr;
                    339: 
                    340:         /* grab the rest of the gvn */
                    341:         subprt = nssave + i + 1;
1.10      snw       342:         sprintf (r->name, "^%s", subprt);
1.1       snw       343: 
                    344:         /* get a fully-formed key */
                    345:         key = mref_to_internal (r);
                    346: 
                    347:         /* switch to the namespace specified in the extended reference */
                    348:         set_namespace (newns, 0);
                    349:         if (merr () > OK) {
                    350:             
                    351:             if (merr () == M26) {
                    352:                 /* if namespace doesn't exist, go back to the
                    353:                    original one and raise M26 */
                    354:                 set_namespace (old_ns, 0);
                    355:                 merr_raise (M26);
                    356:             }
                    357:             
                    358:             return;
                    359:         }
                    360:     }
                    361: 
                    362:     switch (r->name[1]) {
                    363: 
                    364:         case '%':
                    365:         case '$':
                    366:             
                    367:             if ((action % 2) == 0) {
                    368:                 (*gbl_s)(get_sym, tk_buf, old_value);
                    369:                 stcpy (new_value, data);
                    370:                 merr_raise (OK);
                    371:             }
                    372:                       
                    373:             (*gbl_s)(action, key, data);
                    374:             ierr_sav = ierr;
                    375:             break;
                    376: 
                    377:         default:
                    378: 
                    379:             if ((action % 2) == 0) {
                    380:                 (*gbl_u)(get_sym, tk_buf, old_value);
                    381:                 stcpy (new_value, data);
                    382:                 merr_raise (OK);
                    383:             }
                    384:             
                    385:             (*gbl_u)(action, key, data);
                    386:             ierr_sav = ierr;
                    387:             break;
                    388: 
                    389:     }
                    390: 
                    391:     if ((extref_flg == TRUE) || (mapped_flg == TRUE)) {
                    392: 
                    393:         if (mapped_flg == TRUE) {
                    394:             strncpy (gloplib, old_gloplib, PATHLEN - 1);
                    395:         }
                    396: 
                    397:         set_namespace (old_ns, 0);
                    398: 
                    399:     }
                    400:     
                    401:     if (evt_async_enabled && r->reftype == MREF_RT_GLOBAL) {
                    402:         char an[20];
                    403:         char ev_id[512];
                    404: 
                    405:         char *k_buf = (char *) malloc (STRLEN * sizeof (char));
                    406:         char *d_buf = (char *) malloc (STRLEN * sizeof (char));
                    407:         NULLPTRCHK(k_buf,"global");
                    408:         NULLPTRCHK(d_buf,"global");
                    409: 
                    410:         mref_to_external (r, d_buf);
                    411:         stcnv_c2m (d_buf);
                    412:         
                    413:         switch (action) {
                    414:             case set_sym:
                    415:                 sprintf (an, "SET");
                    416:                 break;
                    417:             case kill_sym:
                    418:             case kill_all:
                    419:             case killexcl:
                    420:             case killone:
                    421:                 sprintf (an, "KILL");
                    422:                 break;
                    423:             case get_sym:
                    424:                 sprintf (an, "GET");
                    425:                 break;
1.5       snw       426:             case fra_dat:
1.1       snw       427:                 sprintf (an, "DATA");
                    428:                 break;
                    429:             case fra_order:
                    430:                 sprintf (an, "ORDER");
                    431:                 break;
                    432:             case fra_query:
                    433:             case bigquery:
                    434:                 sprintf (an, "QUERY");
                    435:                 break;
                    436:             case getinc:
                    437:                 sprintf (an, "INCREMENT");
                    438:                 break;
                    439:             case getnext:
                    440:                 sprintf (an, "NEXT");
                    441:                 break;
                    442:             case zdata:
                    443:                 sprintf (an, "ZDATA");
                    444:                 break;
                    445:         }
                    446: 
                    447:         /* NEW ^$EVENT */
                    448:         symtab (new_sym, "^$EVENT\201", "\201");
                    449:         
                    450:         /* populate ^$EVENT("GLVN") with the key */
                    451:         snprintf (k_buf, STRLEN - 1, "^$EVENT\202GLOBAL\201");
                    452:         symtab (set_sym, k_buf, d_buf);
                    453: 
                    454:         if ((action % 2) == 0) {
                    455: 
                    456:             snprintf (k_buf, STRLEN - 1, "^$EVENT\202OLD_VALUE\201");
                    457:             symtab (set_sym, k_buf, old_value);
                    458: 
                    459:             snprintf (k_buf, STRLEN - 1, "^$EVENT\202NEW_VALUE\201");
                    460:             symtab (set_sym, k_buf, new_value);
                    461: 
                    462:         }
                    463:         
                    464:         sprintf (ev_id, "%s:%s", an, r->name);
                    465:         evt_enqueue (ev_id, EVT_CLS_TRIGGER, 0);
                    466: 
                    467:         free (k_buf);
1.6       snw       468:         /* free (d_buf); */
1.1       snw       469:     }  
                    470:     
                    471:     free (old_value);
                    472:     free (new_value);
                    473:     free (r);
                    474:     free (tk_buf);
                    475:     free (old_ns);
                    476:     free (mapk_buf);
                    477:     free (mapd_buf);
                    478:     
                    479:     merr_raise (ierr_sav);
                    480:     
                    481: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>