Commit | Line | Data |
---|---|---|
76998edb JB |
1 | /* Dumping and loading data areas, for Emacs under AIX. |
2 | (It may also work on other kinds of system V.) | |
3 | Copyright (C) 1990 Free Software Foundation, Inc. | |
4 | ||
5 | This file is part of GNU Emacs. | |
6 | ||
7 | GNU Emacs is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 1, or (at your option) | |
10 | any later version. | |
11 | ||
12 | GNU Emacs is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with GNU Emacs; see the file COPYING. If not, write to | |
19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | ||
21 | /* This is based on a public domain program written by IBM. */ | |
22 | ||
23 | /*************** SYSTEM DEFINES *********************************/ | |
24 | ||
25 | #include "config.h" | |
26 | #include "paths.h" | |
27 | #include <sys/types.h> | |
28 | #include <sys/files.h> | |
29 | #include <fcntl.h> | |
30 | #include <sys/mode.h> | |
31 | #include <sys/ipc.h> | |
32 | #include <sys/shm.h> | |
33 | #include <malloc.h> | |
34 | #include <stdio.h> /* MWW */ | |
35 | #include "lisp.h" | |
36 | ||
37 | /*************** LOCAL DEFINES **********************************/ | |
38 | ||
39 | struct data_header /* saved data header */ | |
40 | { | |
41 | char *start; /* dump _data addr */ | |
42 | char *end; /* dump _end addr */ | |
43 | char *sbrk1; /* dump original sbrk addr */ | |
44 | char *sbrk2; /* dump final sbrk addr */ | |
45 | int puresize; /* size of pure data dumped */ | |
46 | }; | |
47 | ||
48 | #define EMACSSHMKEY "EMACSSHMKEY" | |
49 | #define EMACS_DATA_FILE "EMACS-DATA" | |
50 | #define NEW_SHMGET_FLAGS (IPC_CREAT | S_IWUSR | S_IRUSR \ | |
51 | | S_IWGRP | S_IRGRP | S_IWOTH | S_IROTH) | |
52 | #define OLD_SHMAT_FLAGS SHM_RDONLY | |
53 | #define OLD_SHMGET_FLAGS (S_IRUSR | S_IRGRP | S_IROTH) | |
54 | #define OLD_OPEN_FLAGS O_RDONLY | |
55 | #define NEW_OPEN_FLAGS (O_RDWR | O_CREAT | O_TRUNC) | |
56 | ||
57 | /*************** EXTERNAL / GLOBAL DATA AREA ********************/ | |
58 | ||
59 | extern char _data; /* start of data addr */ | |
60 | extern char _end; /* end of all data + 1 addr */ | |
61 | static char *original_sbrk; /* sbrk when dump first run */ | |
62 | ||
63 | void | |
64 | map_in_data (use_dumped_data) | |
65 | int use_dumped_data; | |
66 | { | |
67 | int bufsize; /* malloc buffer size */ | |
68 | struct data_header dh; /* saved data header */ | |
69 | int fd; /* saved data file descriptor */ | |
70 | char *finaladdr; /* last addr in bucket */ | |
71 | char *ipckey = getenv (EMACSSHMKEY); /* env ipc key string */ | |
72 | int length; /* dumped data lengths */ | |
73 | char *newaddr; /* new malloc buffer addr */ | |
74 | int numblks; /* number of remaining mallocs */ | |
75 | int shmid; /* shared memory id */ | |
76 | key_t shmkey; /* shared memory key */ | |
77 | /* Note that using malloc here may not be safe. */ | |
78 | char name[sizeof (PATH_EXEC) + sizeof (EMACS_DATA_FILE) + 2]; | |
79 | ||
80 | /* Consume remaining malloc space without increasing */ | |
81 | /* the end of data space */ | |
82 | original_sbrk = sbrk (0); | |
83 | for (bufsize = 16; bufsize < getpagesize (); bufsize *= 2) | |
84 | { | |
85 | while ((newaddr = (char *)malloc (bufsize - 8)) < original_sbrk) | |
86 | ; | |
87 | for (numblks = (getpagesize () / bufsize) - 1; numblks > 0; numblks--) | |
88 | malloc (bufsize - 8); | |
89 | finaladdr = sbrk (0); | |
90 | } | |
91 | original_sbrk = sbrk (0); | |
92 | ||
93 | /* If we don't want the dumped data, get an unshared segment. */ | |
94 | if (!use_dumped_data) | |
95 | { | |
96 | shmid = shmget (IPC_PRIVATE, PURESIZE, NEW_SHMGET_FLAGS); | |
97 | if (shmid == -1 | |
98 | || shmat (shmid, (char *)PURE_SEG_BITS, 0) == -1) | |
99 | { | |
100 | fprintf (stderr, "emacs: failure obtaining new unshared memory segment.\n"); | |
101 | exit (1); | |
102 | } | |
103 | return; | |
104 | } | |
105 | ||
106 | /* Compute the file name with the dumped data. */ | |
107 | strcpy (name, PATH_EXEC); | |
108 | strcat (name, "/"); | |
109 | strcat (name, EMACS_DATA_FILE); | |
110 | ||
111 | /* Open the file and make sure the addresses have not changed. */ | |
112 | fd = open (name, OLD_OPEN_FLAGS, 0); | |
113 | if (fd < 0) | |
114 | { | |
115 | fprintf (stderr, "emacs: failure opening `%s'\n", name); | |
116 | exit (1); | |
117 | } | |
118 | if (read (fd, (char *)&dh, sizeof (dh)) != sizeof (dh) | |
119 | || dh.start != &_data | |
120 | || dh.end != &_end | |
121 | || dh.sbrk1 != original_sbrk | |
122 | || dh.puresize != PURESIZE) | |
123 | { | |
124 | fprintf (stderr, "emacs: header mismatch in `%s'\n", name); | |
125 | exit (1); | |
126 | } | |
127 | ||
128 | /* Load in the unshared contents. */ | |
129 | if (!(length = dh.end - dh.start) | |
130 | || read (fd, (char *)&_data, length) != length | |
131 | || !(length = dh.sbrk2 - dh.sbrk1) | |
132 | || brk (dh.sbrk2) == -1 | |
133 | || read (fd, dh.sbrk1, length) != length) | |
134 | { | |
135 | fprintf (stderr, "emacs: failure loading unshared data.\n"); | |
136 | exit (1); | |
137 | } | |
138 | ||
139 | /* Determine ipc key from environment or default */ | |
140 | if (ipckey && *ipckey) | |
141 | shmkey = atoi (ipckey); | |
142 | else | |
143 | shmkey = SHMKEY; | |
144 | ||
145 | /* Attach to "pure data" shared memory segment */ | |
146 | if ((shmid = shmget (shmkey, 0, 0)) == -1 | |
147 | || (newaddr = shmat (shmid, (char *)PURE_SEG_BITS, OLD_SHMAT_FLAGS)) == -1) | |
148 | { | |
149 | /* We were unable to open an existing segment. Make a new one. */ | |
150 | struct shmid_ds buf; | |
151 | ||
152 | /* First get rid of the one we tried to get. */ | |
153 | shmdt ((char *)PURE_SEG_BITS); | |
154 | shmctl (shmid, IPC_RMID, 0); | |
155 | ||
156 | /* If we could not write the data file, | |
157 | don't make a shared segment that we could write. | |
158 | Make an unshared segment instead. */ | |
159 | if (access (name, W_OK) == 0) | |
160 | { | |
161 | shmid = shmget (IPC_PRIVATE, PURESIZE, NEW_SHMGET_FLAGS); | |
162 | if (shmid == -1 | |
163 | || shmat (shmid, (char *)PURE_SEG_BITS, 0) == -1) | |
164 | { | |
165 | fprintf (stderr, "emacs: failure obtaining new unshared memory segment.\n"); | |
166 | exit (1); | |
167 | } | |
168 | ||
169 | /* Load the proper data into it. */ | |
170 | if (read (fd, PURE_SEG_BITS, PURESIZE) != PURESIZE) | |
171 | { | |
172 | fprintf (stderr, "emacs: failure loading shared memory data.\n"); | |
173 | shmdt ((char *)PURE_SEG_BITS); | |
174 | shmctl (shmid, IPC_RMID, 0); | |
175 | exit (1); | |
176 | } | |
177 | ||
178 | close (fd); | |
179 | return; | |
180 | } | |
181 | ||
182 | /* Allocate the new shared segment and arrange to write it. */ | |
183 | if ((shmid = shmget (shmkey, PURESIZE, NEW_SHMGET_FLAGS)) == -1 | |
184 | || shmat (shmid, (char *)PURE_SEG_BITS, 0) == -1) | |
185 | { | |
186 | fprintf (stderr, "emacs: failure obtaining new shared memory segment.\n"); | |
187 | shmdt ((char *)PURE_SEG_BITS); | |
188 | shmctl (shmid, IPC_RMID, 0); | |
189 | exit (1); | |
190 | } | |
191 | ||
192 | /* Load the proper data into it. */ | |
193 | if (read (fd, PURE_SEG_BITS, PURESIZE) != PURESIZE) | |
194 | { | |
195 | fprintf (stderr, "emacs: failure loading shared memory data.\n"); | |
196 | shmdt ((char *)PURE_SEG_BITS); | |
197 | shmctl (shmid, IPC_RMID, 0); | |
198 | exit (1); | |
199 | } | |
200 | ||
201 | /* Detach from the segment and bring it back readonly. */ | |
202 | shmdt ((char *)PURE_SEG_BITS); | |
203 | ||
204 | shmctl (shmid, IPC_STAT, &buf); | |
205 | buf.shm_perm.mode = OLD_SHMGET_FLAGS; | |
206 | shmctl (shmid, IPC_SET, &buf); | |
207 | ||
208 | newaddr = shmat (shmid, (char *)PURE_SEG_BITS, OLD_SHMAT_FLAGS); | |
209 | if (newaddr == -1) | |
210 | { | |
211 | fprintf (stderr, "emacs: failure reattaching shared memory segment.\n"); | |
212 | shmctl (shmid, IPC_RMID, 0); | |
213 | exit (1); | |
214 | } | |
215 | } | |
216 | ||
217 | close (fd); | |
218 | } | |
219 | ||
220 | /* Dump the appropriate parts of memory into a file named NEW | |
221 | from which the shared segment can be initialized. */ | |
222 | ||
223 | void | |
224 | map_out_data (new) | |
225 | char *new; | |
226 | { | |
227 | struct data_header dh; /* saved data header */ | |
228 | int fd; /* saved data file descriptor */ | |
229 | int length; /* dumped data length; */ | |
230 | ||
231 | ||
232 | /* Create "saved data" file header */ | |
233 | dh.start = &_data; | |
234 | dh.end = &_end; | |
235 | dh.sbrk1 = original_sbrk; | |
236 | dh.sbrk2 = sbrk (0); | |
237 | dh.puresize = PURESIZE; | |
238 | ||
239 | /* Create new "saved data" dump file */ | |
240 | unlink (new); | |
241 | fd = open (new, NEW_OPEN_FLAGS, 0666); | |
242 | if (fd < 0) | |
243 | report_file_error ("Opening dump file", Fcons (build_string (new), Qnil)); | |
244 | ||
245 | /* Write saved header and data */ | |
246 | length = sizeof (dh); | |
247 | if (write (fd, (char *)&dh, length) != length) | |
248 | report_file_error ("Writing dump file header", | |
249 | Fcons (build_string (new), Qnil)); | |
250 | length = dh.end - dh.start; | |
251 | if (write (fd, dh.start, length) != length) | |
252 | report_file_error ("Writing low core in dump file", | |
253 | Fcons (build_string (new), Qnil)); | |
254 | length = dh.sbrk2 - dh.sbrk1; | |
255 | if (write (fd, dh.sbrk1, length) != length) | |
256 | report_file_error ("Writing heap in dump file", | |
257 | Fcons (build_string (new), Qnil)); | |
258 | length = PURESIZE; | |
259 | if (write (fd, PURE_SEG_BITS, length) != length) | |
260 | report_file_error ("Writing pure data in dump file", | |
261 | Fcons (build_string (new), Qnil)); | |
262 | close (fd); | |
263 | } |