1 /* $NetBSD: term.c,v 1.4 2010/02/05 19:21:02 roy Exp $ */ 2 3 /* 4 * Copyright (c) 2009 The NetBSD Foundation, Inc. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Roy Marples. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __RCSID("$NetBSD: term.c,v 1.4 2010/02/05 19:21:02 roy Exp $"); 32 33 #include <sys/stat.h> 34 35 #include <assert.h> 36 #include <ctype.h> 37 #include <errno.h> 38 #include <fcntl.h> 39 #include <limits.h> 40 #include <ndbm.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <term_private.h> 45 #include <term.h> 46 47 #define TERMINFO_DIRS "/usr/share/misc/terminfo" 48 #define TERMINFO_RESCUE "/rescue/terminfo" 49 50 static char database[PATH_MAX]; 51 static char pathbuf[PATH_MAX]; 52 const char *_ti_database; 53 54 static int 55 _ti_readterm(TERMINAL *term, char *cap, size_t caplen, int flags) 56 { 57 uint8_t ver; 58 uint16_t ind, num; 59 size_t len; 60 TERMUSERDEF *ud; 61 62 ver = *cap++; 63 /* Only read version 1 and 2 structures */ 64 if (ver != 1 && ver != 2) { 65 errno = EINVAL; 66 return -1; 67 } 68 69 term->flags = calloc(TIFLAGMAX + 1, sizeof(char)); 70 if (term->flags == NULL) 71 goto err; 72 term->nums = malloc((TINUMMAX + 1) * sizeof(short)); 73 if (term->nums == NULL) 74 goto err; 75 memset(term->nums, (short)-1, (TINUMMAX + 1) * sizeof(short)); 76 term->strs = calloc(TISTRMAX + 1, sizeof(char *)); 77 if (term->strs == NULL) 78 goto err; 79 term->_area = malloc(caplen); 80 if (term->_area == NULL) 81 goto err; 82 memcpy(term->_area, cap, caplen); 83 84 cap = term->_area; 85 len = le16dec(cap); 86 cap += sizeof(uint16_t); 87 term->name = cap; 88 cap += len; 89 if (ver == 1) 90 term->_alias = NULL; 91 else { 92 len = le16dec(cap); 93 cap += sizeof(uint16_t); 94 if (len == 0) 95 term->_alias = NULL; 96 else { 97 term->_alias = cap; 98 cap += len; 99 } 100 } 101 len = le16dec(cap); 102 cap += sizeof(uint16_t); 103 term->desc = cap; 104 cap += len; 105 106 num = le16dec(cap); 107 cap += sizeof(uint16_t); 108 if (num != 0) { 109 num = le16dec(cap); 110 cap += sizeof(uint16_t); 111 for (; num != 0; num--) { 112 ind = le16dec(cap); 113 cap += sizeof(uint16_t); 114 term->flags[ind] = *cap++; 115 if (flags == 0 && !VALID_BOOLEAN(term->flags[ind])) 116 term->flags[ind] = 0; 117 } 118 } 119 120 num = le16dec(cap); 121 cap += sizeof(uint16_t); 122 if (num != 0) { 123 num = le16dec(cap); 124 cap += sizeof(uint16_t); 125 for (; num != 0; num--) { 126 ind = le16dec(cap); 127 cap += sizeof(uint16_t); 128 term->nums[ind] = le16dec(cap); 129 if (flags == 0 && !VALID_NUMERIC(term->nums[ind])) 130 term->nums[ind] = ABSENT_NUMERIC; 131 cap += sizeof(uint16_t); 132 } 133 } 134 135 num = le16dec(cap); 136 cap += sizeof(uint16_t); 137 if (num != 0) { 138 num = le16dec(cap); 139 cap += sizeof(uint16_t); 140 for (; num != 0; num--) { 141 ind = le16dec(cap); 142 cap += sizeof(uint16_t); 143 len = le16dec(cap); 144 cap += sizeof(uint16_t); 145 if (len > 0) 146 term->strs[ind] = cap; 147 else if (flags == 0) 148 term->strs[ind] = ABSENT_STRING; 149 else 150 term->strs[ind] = CANCELLED_STRING; 151 cap += len; 152 } 153 } 154 155 num = le16dec(cap); 156 cap += sizeof(uint16_t); 157 if (num != 0) { 158 term->_nuserdefs = le16dec(cap); 159 term->_userdefs = malloc(sizeof(*term->_userdefs) * num); 160 cap += sizeof(uint16_t); 161 for (num = 0; num < term->_nuserdefs; num++) { 162 ud = &term->_userdefs[num]; 163 len = le16dec(cap); 164 cap += sizeof(uint16_t); 165 ud->id = cap; 166 cap += len; 167 ud->type = *cap++; 168 switch (ud->type) { 169 case 'f': 170 ud->flag = *cap++; 171 if (flags == 0 && 172 !VALID_BOOLEAN(ud->flag)) 173 ud->flag = 0; 174 ud->num = ABSENT_NUMERIC; 175 ud->str = ABSENT_STRING; 176 break; 177 case 'n': 178 ud->flag = ABSENT_BOOLEAN; 179 ud->num = le16dec(cap); 180 if (flags == 0 && 181 !VALID_NUMERIC(ud->num)) 182 ud->num = ABSENT_NUMERIC; 183 ud->str = ABSENT_STRING; 184 cap += sizeof(uint16_t); 185 break; 186 case 's': 187 ud->flag = ABSENT_BOOLEAN; 188 ud->num = ABSENT_NUMERIC; 189 len = le16dec(cap); 190 cap += sizeof(uint16_t); 191 if (len > 0) 192 ud->str = cap; 193 else if (flags == 0) 194 ud->str = ABSENT_STRING; 195 else 196 ud->str = CANCELLED_STRING; 197 cap += len; 198 break; 199 default: 200 errno = EINVAL; 201 goto err; 202 } 203 } 204 } 205 return 1; 206 207 err: 208 _ti_freeterm(term); 209 return -1; 210 } 211 212 static int 213 _ti_dbgetterm(TERMINAL *term, const char *path, const char *name, int flags) 214 { 215 DBM *db; 216 datum dt; 217 char *p; 218 int r; 219 220 db = dbm_open(path, O_RDONLY, 0644); 221 if (db == NULL) 222 return -1; 223 strlcpy(database, path, sizeof(database)); 224 _ti_database = database; 225 dt.dptr = (void *)__UNCONST(name); 226 dt.dsize = strlen(name); 227 dt = dbm_fetch(db, dt); 228 if (dt.dptr == NULL) { 229 dbm_close(db); 230 return 0; 231 } 232 233 for (;;) { 234 p = (char *)dt.dptr; 235 if (*p++ != 0) /* not alias */ 236 break; 237 dt.dsize = le16dec(p) - 1; 238 p += sizeof(uint16_t); 239 dt.dptr = p; 240 dt = dbm_fetch(db, dt); 241 if (dt.dptr == NULL) { 242 dbm_close(db); 243 return 0; 244 } 245 } 246 247 r = _ti_readterm(term, (char *)dt.dptr, dt.dsize, flags); 248 dbm_close(db); 249 return r; 250 } 251 252 static int 253 _ti_dbgettermp(TERMINAL *term, const char *path, const char *name, int flags) 254 { 255 const char *p; 256 size_t l; 257 int r, e; 258 259 e = -1; 260 r = 0; 261 do { 262 for (p = path; *path != '\0' && *path != ':'; path++) 263 continue; 264 l = path - p; 265 if (l != 0 && l + 1 < sizeof(pathbuf)) { 266 memcpy(pathbuf, p, l); 267 pathbuf[l] = '\0'; 268 r = _ti_dbgetterm(term, pathbuf, name, flags); 269 if (r == 1) 270 return 1; 271 if (r == 0) 272 e = 0; 273 } 274 } while (*path++ == ':'); 275 return e; 276 } 277 278 int 279 _ti_getterm(TERMINAL *term, const char *name, int flags) 280 { 281 int r; 282 char *e, h[PATH_MAX]; 283 284 _DIAGASSERT(term != NULL); 285 _DIAGASSERT(name != NULL); 286 287 database[0] = '\0'; 288 _ti_database = NULL; 289 e = getenv("TERMINFO"); 290 if (e != NULL) 291 return _ti_dbgetterm(term, e, name, flags); 292 293 e = getenv("HOME"); 294 if (e != NULL) { 295 snprintf(h, sizeof(h), "%s/.terminfo", e); 296 r = _ti_dbgetterm(term, h, name, flags); 297 if (r == 1) 298 return 1; 299 } 300 301 r = _ti_dbgettermp(term, TERMINFO_DIRS, name, flags); 302 if (r == 1) 303 return 1; 304 305 /* If we don't find the term in the rescue db and there is 306 * no error, then report the last database accessed. */ 307 strlcpy(h, database, sizeof(h)); 308 r = _ti_dbgetterm(term, TERMINFO_RESCUE, name, flags); 309 if (r == 0 && h[0] != '\0') 310 strlcpy(database, h, sizeof(h)); 311 return r; 312 } 313 314 void 315 _ti_freeterm(TERMINAL *term) 316 { 317 318 _DIAGASSERT(term != NULL); 319 320 free(term->_area); 321 term->_area = NULL; 322 free(term->strs); 323 term->strs = NULL; 324 free(term->nums); 325 term->nums = NULL; 326 free(term->flags); 327 term->flags = NULL; 328 free(term->_userdefs); 329 term->_userdefs = NULL; 330 } 331