1 /*        $NetBSD: hack.save.c,v 1.16 2011/08/06 20:42:43 dholland Exp $        */
2 
3 /*
4  * Copyright (c) 1985, Stichting Centrum voor Wiskunde en Informatica,
5  * Amsterdam
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are
10  * met:
11  *
12  * - Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * - Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in the
17  * documentation and/or other materials provided with the distribution.
18  *
19  * - Neither the name of the Stichting Centrum voor Wiskunde en
20  * Informatica, nor the names of its contributors may be used to endorse or
21  * promote products derived from this software without specific prior
22  * written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
25  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
27  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
28  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
29  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
30  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
33  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36 
37 /*
38  * Copyright (c) 1982 Jay Fenlason <hack@gnu.org>
39  * All rights reserved.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. The name of the author may not be used to endorse or promote products
50  *    derived from this software without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
53  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
54  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
55  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
56  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
57  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
58  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
59  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
60  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
61  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62  */
63 
64 #include <sys/cdefs.h>
65 #ifndef lint
66 __RCSID("$NetBSD: hack.save.c,v 1.16 2011/08/06 20:42:43 dholland Exp $");
67 #endif                                  /* not lint */
68 
69 #include <signal.h>
70 #include <stdlib.h>
71 #include <unistd.h>
72 #include <fcntl.h>
73 #include "hack.h"
74 #include "extern.h"
75 
76 static int dosave0(int);
77 
78 int
dosave(void)79 dosave(void)
80 {
81           if (dosave0(0)) {
82                     settty("Be seeing you ...\n");
83                     exit(0);
84           }
85           return (0);
86 }
87 
88 #ifndef NOSAVEONHANGUP
89 void
hang_up(int n __unused)90 hang_up(int n __unused)
91 {
92           (void) dosave0(1);
93           exit(1);
94 }
95 #endif    /* NOSAVEONHANGUP */
96 
97 /* returns 1 if save successful */
98 static int
dosave0(int hu)99 dosave0(int hu)
100 {
101           int                 fd, ofd;
102           int             tmp;          /* not ! */
103 
104           (void) signal(SIGHUP, SIG_IGN);
105           (void) signal(SIGINT, SIG_IGN);
106           if ((fd = creat(SAVEF, FMASK)) < 0) {
107                     if (!hu)
108                               pline("Cannot open save file. (Continue or Quit)");
109                     (void) unlink(SAVEF);         /* ab@unido */
110                     return (0);
111           }
112           if (flags.moonphase == FULL_MOON)       /* ut-sally!fletcher */
113                     u.uluck--;          /* and unido!ab */
114           savelev(fd, dlevel);
115           saveobjchn(fd, invent);
116           saveobjchn(fd, fcobj);
117           savemonchn(fd, fallen_down);
118           tmp = getuid();
119           bwrite(fd, &tmp, sizeof tmp);
120           bwrite(fd, &flags, sizeof(struct flag));
121           bwrite(fd, &dlevel, sizeof dlevel);
122           bwrite(fd, &maxdlevel, sizeof maxdlevel);
123           bwrite(fd, &moves, sizeof moves);
124           bwrite(fd, &u, sizeof(struct you));
125           if (u.ustuck)
126                     bwrite(fd, &(u.ustuck->m_id), sizeof u.ustuck->m_id);
127           bwrite(fd, pl_character, sizeof pl_character);
128           bwrite(fd, genocided, sizeof genocided);
129           bwrite(fd, fut_geno, sizeof fut_geno);
130           savenames(fd);
131           for (tmp = 1; tmp <= maxdlevel; tmp++) {
132 
133                     if (tmp == dlevel || !level_exists[tmp])
134                               continue;
135                     glo(tmp);
136                     if ((ofd = open(lock, O_RDONLY)) < 0) {
137                               if (!hu)
138                                         pline("Error while saving: cannot read %s.", lock);
139                               (void) close(fd);
140                               (void) unlink(SAVEF);
141                               if (!hu)
142                                         done("tricked");
143                               return (0);
144                     }
145                     getlev(ofd, hackpid, tmp);
146                     (void) close(ofd);
147                     bwrite(fd, &tmp, sizeof tmp); /* level number */
148                     savelev(fd, tmp);   /* actual level */
149                     (void) unlink(lock);
150           }
151           (void) close(fd);
152           glo(dlevel);
153           (void) unlink(lock);          /* get rid of current level --jgm */
154           glo(0);
155           (void) unlink(lock);
156           return (1);
157 }
158 
159 int
dorecover(int fd)160 dorecover(int fd)
161 {
162           int nfd;
163           int             tmp;          /* not a ! */
164           unsigned        mid;          /* idem */
165           struct obj     *otmp;
166 
167           restoring = TRUE;
168           getlev(fd, 0, 0);
169           invent = restobjchn(fd);
170           for (otmp = invent; otmp; otmp = otmp->nobj)
171                     if (otmp->owornmask)
172                               setworn(otmp, otmp->owornmask);
173           fcobj = restobjchn(fd);
174           fallen_down = restmonchn(fd);
175           mread(fd, &tmp, sizeof tmp);
176           if (tmp != (int) getuid()) {  /* strange ... */
177                     (void) close(fd);
178                     (void) unlink(SAVEF);
179                     puts("Saved game was not yours.");
180                     restoring = FALSE;
181                     return (0);
182           }
183           mread(fd, &flags, sizeof(struct flag));
184           mread(fd, &dlevel, sizeof dlevel);
185           mread(fd, &maxdlevel, sizeof maxdlevel);
186           mread(fd, &moves, sizeof moves);
187           mread(fd, &u, sizeof(struct you));
188           if (u.ustuck)
189                     mread(fd, &mid, sizeof mid);
190           mread(fd, pl_character, sizeof pl_character);
191           mread(fd, genocided, sizeof genocided);
192           mread(fd, fut_geno, sizeof fut_geno);
193           restnames(fd);
194           while (1) {
195                     if (read(fd, &tmp, sizeof tmp) != sizeof tmp)
196                               break;
197                     getlev(fd, 0, tmp);
198                     glo(tmp);
199                     if ((nfd = creat(lock, FMASK)) < 0)
200                               panic("Cannot open temp file %s!\n", lock);
201                     savelev(nfd, tmp);
202                     (void) close(nfd);
203           }
204           (void) lseek(fd, (off_t) 0, SEEK_SET);
205           getlev(fd, 0, 0);
206           (void) close(fd);
207           (void) unlink(SAVEF);
208           if (Punished) {
209                     for (otmp = fobj; otmp; otmp = otmp->nobj)
210                               if (otmp->olet == CHAIN_SYM)
211                                         goto chainfnd;
212                     panic("Cannot find the iron chain?");
213 chainfnd:
214                     uchain = otmp;
215                     if (!uball) {
216                               for (otmp = fobj; otmp; otmp = otmp->nobj)
217                                         if (otmp->olet == BALL_SYM && otmp->spe)
218                                                   goto ballfnd;
219                               panic("Cannot find the iron ball?");
220           ballfnd:
221                               uball = otmp;
222                     }
223           }
224           if (u.ustuck) {
225                     struct monst   *mtmp;
226 
227                     for (mtmp = fmon; mtmp; mtmp = mtmp->nmon)
228                               if (mtmp->m_id == mid)
229                                         goto monfnd;
230                     panic("Cannot find the monster ustuck.");
231 monfnd:
232                     u.ustuck = mtmp;
233           }
234 #ifndef QUEST
235           setsee();           /* only to recompute seelx etc. - these
236                                          * weren't saved */
237 #endif    /* QUEST */
238           docrt();
239           restoring = FALSE;
240           return (1);
241 }
242 
243 struct obj     *
restobjchn(int fd)244 restobjchn(int fd)
245 {
246           struct obj     *otmp, *otmp2 = NULL;
247           struct obj     *first = 0;
248           int             xl;
249           while (1) {
250                     mread(fd, &xl, sizeof(xl));
251                     if (xl == -1)
252                               break;
253                     otmp = newobj(xl);
254                     if (!first)
255                               first = otmp;
256                     else
257                               otmp2->nobj = otmp;
258                     mread(fd, otmp, (unsigned) xl + sizeof(struct obj));
259                     if (!otmp->o_id)
260                               otmp->o_id = flags.ident++;
261                     otmp2 = otmp;
262           }
263           if (first && otmp2->nobj) {
264                     impossible("Restobjchn: error reading objchn.");
265                     otmp2->nobj = 0;
266           }
267           return (first);
268 }
269 
270 struct monst   *
restmonchn(int fd)271 restmonchn(int fd)
272 {
273           struct monst   *mtmp, *mtmp2 = NULL;
274           struct monst   *first = 0;
275           int             xl;
276 
277           struct permonst *monbegin;
278           long            differ;
279 
280           mread(fd, &monbegin, sizeof(monbegin));
281           differ = (const char *) (&mons[0]) - (const char *) (monbegin);
282 
283 #ifdef lint
284           /* suppress "used before set" warning from lint */
285           mtmp2 = 0;
286 #endif    /* lint */
287           while (1) {
288                     mread(fd, &xl, sizeof(xl));
289                     if (xl == -1)
290                               break;
291                     mtmp = newmonst(xl);
292                     if (!first)
293                               first = mtmp;
294                     else
295                               mtmp2->nmon = mtmp;
296                     mread(fd, mtmp, (unsigned) xl + sizeof(struct monst));
297                     if (!mtmp->m_id)
298                               mtmp->m_id = flags.ident++;
299                     mtmp->data = (const struct permonst *)
300                               ((const char *) mtmp->data + differ);
301                     if (mtmp->minvent)
302                               mtmp->minvent = restobjchn(fd);
303                     mtmp2 = mtmp;
304           }
305           if (first && mtmp2->nmon) {
306                     impossible("Restmonchn: error reading monchn.");
307                     mtmp2->nmon = 0;
308           }
309           return (first);
310 }
311