1: /*
2: * $Id: gcompact.c,v 1.4 2025/04/02 03:02:42 snw Exp $
3: * global compactor
4: *
5: *
6: * Author: Serena Willis <snw@coherent-logic.com>
7: * Copyright (C) 1998 MUG Deutschland
8: * Copyright (C) 2020, 2025 Coherent Logic Development LLC
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: *
26: * $Log: gcompact.c,v $
27: * Revision 1.4 2025/04/02 03:02:42 snw
28: * Stop requiring users to pass -e to fmadm when -u or -g are passed
29: *
30: * Revision 1.3 2025/03/09 19:14:25 snw
31: * First phase of REUSE compliance and header reformat
32: *
33: *
34: * SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
35: * SPDX-License-Identifier: AGPL-3.0-or-later
36: **/
37:
38: /* compacts mumps globals.
39: * it is essential that the global structure is ok.
40: * because on certain errors (e.g. empty data block)
41: * large parts of data may be lost. errors in pointer
42: * blocks may be ignored, as long as the path to the first
43: * data block is ok.
44: */
45: #include <string.h>
46: #include <sys/types.h>
47: #include <sys/stat.h>
48: #include <sys/wait.h>
49: #include <fcntl.h>
50: #include <unistd.h>
51: #include <stdlib.h>
52:
53: #include <stddef.h>
54: #include "mpsdef0.h"
55: #include "errmsg.h"
56: #include <signal.h>
57: #include <setjmp.h>
58: #include <stdio.h>
59:
60:
61: /* needed if byte data are to be interpreted as unsigned integer */
62: #define UNSIGN(A) ((A)&0377)
63:
64: #define g_EOL 30
65: #define POINT 28
66: #define MINUS 26
67:
68: #define ROOT 0L
69: /* length of blocks. status bytes defined as offset to blocklength */
70: #define DATALIM (BLOCKLEN-11)
71: #define LLPTR (BLOCKLEN-10)
72: #define NRBLK LLPTR
73: #define RLPTR (BLOCKLEN- 6)
74: #define FREE RLPTR
75: #define BTYP (BLOCKLEN- 3)
76: #define OFFS (BLOCKLEN- 2)
77:
78: #define EMPTY 0
79: #define FBLK 1
80: #define POINTER 2
81: #define BOTTOM 6
82: #define DATA 8
83: /* error code */
84: #define PROTECT 30
85:
86: #ifndef SYSFIVE
87: #define FreeM_timezone -3600
88: #else
89:
90: #ifdef __CYGWIN__
91: #define FreeM_timezone _timezone
92: #else
93: extern long FreeM_timezone;
94: #endif /* __CYGWIN__ */
95:
96: #endif /* SYSFIVE */
97:
98:
99: /* mumps commands */
100: #define BREAK 'b'
101: #define CLOSE 'c'
102: #define DO 'd'
103: #define DO_BLOCK 2
104: #define ELSE 'e'
105: #define FOR 'f'
106: #define GOTO 'g'
107: #define HA 'h'
108: #define HALT '0'
109: #define HANG '1'
110: #define IF 'i'
111: #define JOB 'j'
112: #define KILL 'k'
113: #define LOCK 'l'
114: #define NEW 'n'
115: #define OPEN 'o'
116: #define QUIT 'q'
117: #define READ 'r'
118: #define SET 's'
119: #define USE 'u'
120: #define VIEW 'v'
121: #define WRITE 'w'
122: #define XECUTE 'x'
123:
124: #define ZBREAK 'B'
125: #define ZGO 'G'
126: #define ZHALT 'H'
127: #define ZINSERT 'I'
128: #define ZJOB 'J'
129: #define ZLOAD 'L'
130: #define ZNEW 'N'
131: #define ZPRINT 'P'
132: #define ZQUIT 'Q'
133: #define ZREMOVE 'R'
134: #define ZSAVE 'S'
135: #define ZTRAP 'T'
136: #define ZWRITE 'W'
137: #define PRIVATE SP
138:
139: extern short ierr;
140:
141:
142: int main (int argc, char **argv)
143: {
144:
145: char filnam[40]; /* global to be restored */
146: static char savnam[512] = "^/usr/tmp/"; /* intermediate storage */
147: static char unlnam[40] = "/usr/tmp/^"; /* "unlink" filename */
148: short fildes; /* file descriptor to filnam */
149: char block[BLOCKLEN];
150: char key[512];
151: char data[512];
152: unsigned long blknbr;
153: long offset;
154: long type;
155: long length;
156: long koffs;
157:
158: register int i;
159: register int j;
160: register int k;
161: register int ch;
162:
163: umask (0); /* protection bits mask to full rights */
164: filnam[0] = '^';
165: filnam[1] = 0;
166:
167: if (argc > 1) {
168:
169: j = 0;
170:
171: while (--argc > 0) {
172:
173: j++;
174:
175: if (**(argv + j) == '-') {
176: printf ("usage is: %s [^]global\012\015", *argv);
177: exit (0);
178: }
179:
180: strcpy (&filnam[1], *(argv + j));
181:
182: }
183:
184: }
185: else {
186: printf ("\012\015%s global ^", *argv);
187: scanf ("%s", &filnam[1]);
188: }
189:
190: j = filnam[1];
191:
192: if (j == '.' || j == '/' || j == '^') {
193:
194: j = 0;
195:
196: while ((filnam[j] = filnam[j + 1])) j++;
197:
198: }
199:
200: if ((fildes = open (filnam, 0)) == -1) {
201: printf ("cannot open file %s\007\012\015", filnam);
202: exit (1);
203: }
204:
205: strcpy (&savnam[10], &filnam[1]);
206:
207: koffs = 10 + strlen (&filnam[1]);
208:
209: strcpy (&unlnam[10], &filnam[1]);
210: unlink (unlnam); /* kill previous tmp_file */
211:
212: blknbr = ROOT;
213:
214: for (;;) {
215:
216: lseek (fildes, blknbr * BLOCKLEN, 0);
217:
218: if (read (fildes, block, BLOCKLEN) == 0) {
219: printf ("\015*** something wrong ***\033[K\012\015");
220: exit (0);
221: }
222:
223: if (block[BTYP] == DATA) goto first;
224:
225: i = UNSIGN (block[0]) + 2;
226:
227: blknbr = UNSIGN (block[i]) * 65536 + UNSIGN (block[i + 1]) * 256 + UNSIGN (block[i + 2]);
228:
229: }
230:
231:
232: again:
233:
234: if (blknbr == 0) {
235:
236: printf ("\015*** done ***\033[K\012\015");
237:
238: strcpy (block, "mv /usr/tmp/\\^");
239: strcat (block, &filnam[1]);
240: strcat (block, " .");
241:
242: system (block);
243:
244: exit (0);
245:
246: }
247:
248: lseek (fildes, blknbr * BLOCKLEN, 0);
249:
250: if (read (fildes, block, BLOCKLEN) == 0) {
251:
252: strcpy (block, "mv /usr/tmp/\\^");
253: strcat (block, &filnam[1]);
254: strcat (block, " .");
255:
256: system (block);
257:
258: exit (0);
259:
260: }
261:
262:
263: first: /* entry point for first DATA block */
264:
265: type = block[BTYP];
266:
267: blknbr = UNSIGN (block[RLPTR]) * 65536 +
268: UNSIGN (block[RLPTR + 1]) * 256 +
269: UNSIGN (block[RLPTR + 2]);
270:
271: if (type != DATA) goto again;
272:
273: offset = UNSIGN (block[OFFS]) * 256 + UNSIGN (block[OFFS + 1]);
274:
275: i = 0;
276:
277: while (i < offset) {
278:
279: length = UNSIGN (block[i++]);
280: k = UNSIGN (block[i++]);
281:
282: if ((i + length) > offset) break;
283:
284: for (j = 0; j < length; j++) key[k++] = block[i++];
285:
286: key[k] = g_EOL;
287:
288: {
289:
290: long ch0;
291: long i;
292: long j;
293: long k;
294:
295: j = 0;
296: i = 0;
297:
298: data[j++] = DELIM;
299:
300: k = 1;
301:
302: while ((ch = UNSIGN (key[i++])) != g_EOL) {
303:
304: if (k) k = 0;
305:
306: ch0 = (ch >= SP ? (ch >> 1) : /* 'string' chars */
307: (ch < 20 ? (ch >> 1) + '0' : /* 0...9 */
308: (ch >> 1) + SP)); /* '.' or '-' */
309:
310: if (ch0 == DEL) {
311:
312: if (((ch = UNSIGN (key[i++])) >> 1) == DEL) {
313:
314: ch0 += DEL;
315: ch0 = UNSIGN (key[i++]);
316:
317: }
318:
319: ch0 += (ch >> 1);
320:
321: }
322:
323: data[j++] = ch0;
324:
325: if (ch & 01) {
326: data[j++] = DELIM;
327: k = 1;
328: }
329:
330: }
331:
332: data[j--] = EOL;
333:
334: if (j == 0) {
335: data[0] = EOL;
336: }
337: else if (data[j] == DELIM) {
338: data[j] = EOL;
339: }
340:
341: while (j >= 0) {
342: if ((UNSIGN (ch = data[--j]) < SP) && (ch != DELIM)) break;
343: }
344:
345: if (j < 0) {
346: stcpy (&savnam[koffs], data);
347: }
348: else {
349: goto again;
350: } /* illegal subscipt */
351:
352: }
353:
354: length = UNSIGN (block[i++]);
355: k = 0;
356:
357: if ((i + length) > offset) break;
358:
359: stcpy0 (data, &block[i], length);
360:
361: i += length;
362: data[length] = EOL;
363:
364: global (0, savnam, data); /* call original global */
365:
366: if (merr () == PROTECT) {
367: printf ("\012cannot open intermediate file in /usr/tmp\012");
368: exit (1);
369: }
370:
371: }
372:
373: if (i != offset) printf ("\012wrong offset %ld vs. %d\012", offset, i);
374:
375: goto again;
376: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>