hangman(6): Update to augmented version from OpenBSD.
[dragonfly.git] / games / hangman / getsym.c
1 /*      $OpenBSD: ksyms.c,v 1.8 2015/02/07 03:26:20 tedu Exp $  */
2
3 /*
4  * Copyright (c) 2008 Miodrag Vallat.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18
19 #include <unistd.h>
20 #include <ctype.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <string.h>
24
25 #include <sys/exec.h>
26 #include <sys/elf64.h>
27
28 #include "hangman.h"
29
30 typedef Elf64_Ehdr Elf_Ehdr;
31 typedef Elf64_Shdr Elf_Shdr;
32
33 static int ksyms_elf_parse(void);
34
35 void
36 sym_getword(void)
37 {
38         uint tries;
39         off_t pos;
40         int buflen;
41         char symbuf[1 + BUFSIZ], *sym, *end;
42         size_t symlen;
43
44         for (tries = 0; tries < MAXBADWORDS; tries++) {
45                 pos = arc4random_uniform(symsize);
46                 if (lseek(symfd, pos + symoffs, SEEK_SET) == -1)
47                         continue;
48                 buflen = read(symfd, symbuf, BUFSIZ);
49                 if (buflen < 0)
50                         continue;
51
52                 /*
53                  * The buffer is hopefully large enough to hold at least
54                  * a complete symbol, i.e. two occurences of NUL, or
55                  * one occurence of NUL and the buffer containing the end
56                  * of the string table. We make sure the buffer will be
57                  * NUL terminated in all cases.
58                  */
59                 if (buflen + pos >= symsize)
60                         buflen = symsize - pos;
61                 *(end = symbuf + buflen) = '\0';
62
63                 for (sym = symbuf; *sym != '\0'; sym++)
64                         ;
65                 if (sym == end)
66                         continue;
67
68                 symlen = strlen(++sym);
69                 if (symlen < MINLEN || symlen > MAXLEN)
70                         continue;
71
72                 /* ignore symbols containing dots or dollar signs */
73                 if (strchr(sym, '.') != NULL || strchr(sym, '$') != NULL)
74                         continue;
75
76                 break;
77         }
78
79         if (tries >= MAXBADWORDS) {
80                 mvcur(0, COLS - 1, LINES -1, 0);
81                 endwin();
82                 errx(1, "can't seem a suitable symbol in %s",
83                     Dict_name);
84         }
85
86         strlcpy(Word, sym, sizeof(Word));
87         strlcpy(Known, sym, sizeof(Known));
88         for (sym = Known; *sym != '\0'; sym++) {
89                 if (*sym == '-')
90                         *sym = '_';     /* try not to confuse player */
91                 if (isalnum((unsigned char)*sym))
92                         *sym = '-';
93         }
94 }
95
96 int
97 sym_setup(void)
98 {
99         if ((symfd = open(Dict_name, O_RDONLY)) < 0)
100                 return -1;
101
102         if (ksyms_elf_parse() == 0)
103                 return 0;
104
105         close(symfd);
106         errno = ENOEXEC;
107         return -1;
108 }
109
110 int
111 ksyms_elf_parse(void)
112 {
113         Elf_Ehdr eh;
114         Elf_Shdr sh;
115         uint s;
116
117         if (lseek(symfd, 0, SEEK_SET) == -1)
118                 return -1;
119
120         if (read(symfd, &eh, sizeof(eh)) != sizeof(eh))
121                 return -1;
122
123         if (!IS_ELF(eh))
124                 return -1;
125
126         if (lseek(symfd, eh.e_shoff, SEEK_SET) == -1)
127                 return -1;
128
129         symoffs = 0;
130         symsize = 0;
131
132         for (s = 0; s < eh.e_shnum; s++) {
133                 if (read(symfd, &sh, sizeof(sh)) != sizeof(sh))
134                         return -1;
135
136                 /*
137                  * There should be two string table sections, one with the
138                  * name of the sections themselves, and one with the symbol
139                  * names. Just pick the largest one.
140                  */
141                 if (sh.sh_type == SHT_STRTAB) {
142                         if (symsize > (off_t)sh.sh_size)
143                                 continue;
144
145                         symoffs = (off_t)sh.sh_offset;
146                         symsize = (off_t)sh.sh_size;
147                 }
148         }
149
150         if (symsize == 0)
151                 return -1;
152
153         return 0;
154 }