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