1 /* 2 * reentr.c 3 * 4 * Copyright (C) 2002, 2003, by Larry Wall and others 5 * 6 * You may distribute under the terms of either the GNU General Public 7 * License or the Artistic License, as specified in the README file. 8 * 9 * !!!!!!! DO NOT EDIT THIS FILE !!!!!!! 10 * This file is built by reentrl.pl from data in reentr.pl. 11 * 12 * "Saruman," I said, standing away from him, "only one hand at a time can 13 * wield the One, and you know that well, so do not trouble to say we!" 14 * 15 */ 16 17 #include "EXTERN.h" 18 #define PERL_IN_REENTR_C 19 #include "perl.h" 20 #include "reentr.h" 21 22 void 23 Perl_reentrant_size(pTHX) { 24 #ifdef USE_REENTRANT_API 25 #define REENTRANTSMALLSIZE 256 /* Make something up. */ 26 #define REENTRANTUSUALSIZE 4096 /* Make something up. */ 27 #ifdef HAS_ASCTIME_R 28 PL_reentrant_buffer->_asctime_size = REENTRANTSMALLSIZE; 29 #endif /* HAS_ASCTIME_R */ 30 #ifdef HAS_CRYPT_R 31 #endif /* HAS_CRYPT_R */ 32 #ifdef HAS_CTIME_R 33 PL_reentrant_buffer->_ctime_size = REENTRANTSMALLSIZE; 34 #endif /* HAS_CTIME_R */ 35 #ifdef HAS_DRAND48_R 36 #endif /* HAS_DRAND48_R */ 37 #ifdef HAS_GETGRNAM_R 38 # if defined(HAS_SYSCONF) && defined(_SC_GETGR_R_SIZE_MAX) && !defined(__GLIBC__) 39 PL_reentrant_buffer->_grent_size = sysconf(_SC_GETGR_R_SIZE_MAX); 40 if (PL_reentrant_buffer->_grent_size == -1) 41 PL_reentrant_buffer->_grent_size = REENTRANTUSUALSIZE; 42 # else 43 # if defined(__osf__) && defined(__alpha) && defined(SIABUFSIZ) 44 PL_reentrant_buffer->_grent_size = SIABUFSIZ; 45 # else 46 # ifdef __sgi 47 PL_reentrant_buffer->_grent_size = BUFSIZ; 48 # else 49 PL_reentrant_buffer->_grent_size = REENTRANTUSUALSIZE; 50 # endif 51 # endif 52 # endif 53 #endif /* HAS_GETGRNAM_R */ 54 #ifdef HAS_GETHOSTBYNAME_R 55 #if !(GETHOSTBYNAME_R_PROTO == REENTRANT_PROTO_I_CSD) 56 PL_reentrant_buffer->_hostent_size = REENTRANTUSUALSIZE; 57 #endif 58 #endif /* HAS_GETHOSTBYNAME_R */ 59 #ifdef HAS_GETLOGIN_R 60 PL_reentrant_buffer->_getlogin_size = REENTRANTSMALLSIZE; 61 #endif /* HAS_GETLOGIN_R */ 62 #ifdef HAS_GETNETBYNAME_R 63 #if !(GETNETBYNAME_R_PROTO == REENTRANT_PROTO_I_CSD) 64 PL_reentrant_buffer->_netent_size = REENTRANTUSUALSIZE; 65 #endif 66 #endif /* HAS_GETNETBYNAME_R */ 67 #ifdef HAS_GETPROTOBYNAME_R 68 #if !(GETPROTOBYNAME_R_PROTO == REENTRANT_PROTO_I_CSD) 69 PL_reentrant_buffer->_protoent_size = REENTRANTUSUALSIZE; 70 #endif 71 #endif /* HAS_GETPROTOBYNAME_R */ 72 #ifdef HAS_GETPWNAM_R 73 # if defined(HAS_SYSCONF) && defined(_SC_GETPW_R_SIZE_MAX) && !defined(__GLIBC__) 74 PL_reentrant_buffer->_pwent_size = sysconf(_SC_GETPW_R_SIZE_MAX); 75 if (PL_reentrant_buffer->_pwent_size == -1) 76 PL_reentrant_buffer->_pwent_size = REENTRANTUSUALSIZE; 77 # else 78 # if defined(__osf__) && defined(__alpha) && defined(SIABUFSIZ) 79 PL_reentrant_buffer->_pwent_size = SIABUFSIZ; 80 # else 81 # ifdef __sgi 82 PL_reentrant_buffer->_pwent_size = BUFSIZ; 83 # else 84 PL_reentrant_buffer->_pwent_size = REENTRANTUSUALSIZE; 85 # endif 86 # endif 87 # endif 88 #endif /* HAS_GETPWNAM_R */ 89 #ifdef HAS_GETSERVBYNAME_R 90 #if !(GETSERVBYNAME_R_PROTO == REENTRANT_PROTO_I_CCSD) 91 PL_reentrant_buffer->_servent_size = REENTRANTUSUALSIZE; 92 #endif 93 #endif /* HAS_GETSERVBYNAME_R */ 94 #ifdef HAS_GETSPNAM_R 95 # if defined(HAS_SYSCONF) && defined(_SC_GETPW_R_SIZE_MAX) && !defined(__GLIBC__) 96 PL_reentrant_buffer->_spent_size = sysconf(_SC_GETPW_R_SIZE_MAX); 97 if (PL_reentrant_buffer->_spent_size == -1) 98 PL_reentrant_buffer->_spent_size = REENTRANTUSUALSIZE; 99 # else 100 # if defined(__osf__) && defined(__alpha) && defined(SIABUFSIZ) 101 PL_reentrant_buffer->_spent_size = SIABUFSIZ; 102 # else 103 # ifdef __sgi 104 PL_reentrant_buffer->_spent_size = BUFSIZ; 105 # else 106 PL_reentrant_buffer->_spent_size = REENTRANTUSUALSIZE; 107 # endif 108 # endif 109 # endif 110 #endif /* HAS_GETSPNAM_R */ 111 #ifdef HAS_GMTIME_R 112 #endif /* HAS_GMTIME_R */ 113 #ifdef HAS_LOCALTIME_R 114 #endif /* HAS_LOCALTIME_R */ 115 #ifdef HAS_RANDOM_R 116 #endif /* HAS_RANDOM_R */ 117 #ifdef HAS_READDIR_R 118 /* This is the size Solaris recommends. 119 * (though we go static, should use pathconf() instead) */ 120 PL_reentrant_buffer->_readdir_size = sizeof(struct dirent) + MAXPATHLEN + 1; 121 #endif /* HAS_READDIR_R */ 122 #ifdef HAS_READDIR64_R 123 /* This is the size Solaris recommends. 124 * (though we go static, should use pathconf() instead) */ 125 PL_reentrant_buffer->_readdir64_size = sizeof(struct dirent64) + MAXPATHLEN + 1; 126 #endif /* HAS_READDIR64_R */ 127 #ifdef HAS_SETLOCALE_R 128 PL_reentrant_buffer->_setlocale_size = REENTRANTSMALLSIZE; 129 #endif /* HAS_SETLOCALE_R */ 130 #ifdef HAS_STRERROR_R 131 PL_reentrant_buffer->_strerror_size = REENTRANTSMALLSIZE; 132 #endif /* HAS_STRERROR_R */ 133 #ifdef HAS_TTYNAME_R 134 PL_reentrant_buffer->_ttyname_size = REENTRANTSMALLSIZE; 135 #endif /* HAS_TTYNAME_R */ 136 137 #endif /* USE_REENTRANT_API */ 138 } 139 140 void 141 Perl_reentrant_init(pTHX) { 142 #ifdef USE_REENTRANT_API 143 New(31337, PL_reentrant_buffer, 1, REENTR); 144 Perl_reentrant_size(aTHX); 145 #ifdef HAS_ASCTIME_R 146 New(31338, PL_reentrant_buffer->_asctime_buffer, PL_reentrant_buffer->_asctime_size, char); 147 #endif /* HAS_ASCTIME_R */ 148 #ifdef HAS_CRYPT_R 149 #if CRYPT_R_PROTO != REENTRANT_PROTO_B_CCD 150 PL_reentrant_buffer->_crypt_struct_buffer = 0; 151 #endif 152 #endif /* HAS_CRYPT_R */ 153 #ifdef HAS_CTIME_R 154 New(31338, PL_reentrant_buffer->_ctime_buffer, PL_reentrant_buffer->_ctime_size, char); 155 #endif /* HAS_CTIME_R */ 156 #ifdef HAS_DRAND48_R 157 #endif /* HAS_DRAND48_R */ 158 #ifdef HAS_GETGRNAM_R 159 # ifdef USE_GRENT_FPTR 160 PL_reentrant_buffer->_grent_fptr = NULL; 161 # endif 162 New(31338, PL_reentrant_buffer->_grent_buffer, PL_reentrant_buffer->_grent_size, char); 163 #endif /* HAS_GETGRNAM_R */ 164 #ifdef HAS_GETHOSTBYNAME_R 165 #if !(GETHOSTBYNAME_R_PROTO == REENTRANT_PROTO_I_CSD) 166 New(31338, PL_reentrant_buffer->_hostent_buffer, PL_reentrant_buffer->_hostent_size, char); 167 #endif 168 #endif /* HAS_GETHOSTBYNAME_R */ 169 #ifdef HAS_GETLOGIN_R 170 New(31338, PL_reentrant_buffer->_getlogin_buffer, PL_reentrant_buffer->_getlogin_size, char); 171 #endif /* HAS_GETLOGIN_R */ 172 #ifdef HAS_GETNETBYNAME_R 173 #if !(GETNETBYNAME_R_PROTO == REENTRANT_PROTO_I_CSD) 174 New(31338, PL_reentrant_buffer->_netent_buffer, PL_reentrant_buffer->_netent_size, char); 175 #endif 176 #endif /* HAS_GETNETBYNAME_R */ 177 #ifdef HAS_GETPROTOBYNAME_R 178 #if !(GETPROTOBYNAME_R_PROTO == REENTRANT_PROTO_I_CSD) 179 New(31338, PL_reentrant_buffer->_protoent_buffer, PL_reentrant_buffer->_protoent_size, char); 180 #endif 181 #endif /* HAS_GETPROTOBYNAME_R */ 182 #ifdef HAS_GETPWNAM_R 183 # ifdef USE_PWENT_FPTR 184 PL_reentrant_buffer->_pwent_fptr = NULL; 185 # endif 186 New(31338, PL_reentrant_buffer->_pwent_buffer, PL_reentrant_buffer->_pwent_size, char); 187 #endif /* HAS_GETPWNAM_R */ 188 #ifdef HAS_GETSERVBYNAME_R 189 #if !(GETSERVBYNAME_R_PROTO == REENTRANT_PROTO_I_CCSD) 190 New(31338, PL_reentrant_buffer->_servent_buffer, PL_reentrant_buffer->_servent_size, char); 191 #endif 192 #endif /* HAS_GETSERVBYNAME_R */ 193 #ifdef HAS_GETSPNAM_R 194 # ifdef USE_SPENT_FPTR 195 PL_reentrant_buffer->_spent_fptr = NULL; 196 # endif 197 New(31338, PL_reentrant_buffer->_spent_buffer, PL_reentrant_buffer->_spent_size, char); 198 #endif /* HAS_GETSPNAM_R */ 199 #ifdef HAS_GMTIME_R 200 #endif /* HAS_GMTIME_R */ 201 #ifdef HAS_LOCALTIME_R 202 #endif /* HAS_LOCALTIME_R */ 203 #ifdef HAS_RANDOM_R 204 #endif /* HAS_RANDOM_R */ 205 #ifdef HAS_READDIR_R 206 PL_reentrant_buffer->_readdir_struct = (struct dirent*)safemalloc(PL_reentrant_buffer->_readdir_size); 207 #endif /* HAS_READDIR_R */ 208 #ifdef HAS_READDIR64_R 209 PL_reentrant_buffer->_readdir64_struct = (struct dirent64*)safemalloc(PL_reentrant_buffer->_readdir64_size); 210 #endif /* HAS_READDIR64_R */ 211 #ifdef HAS_SETLOCALE_R 212 New(31338, PL_reentrant_buffer->_setlocale_buffer, PL_reentrant_buffer->_setlocale_size, char); 213 #endif /* HAS_SETLOCALE_R */ 214 #ifdef HAS_STRERROR_R 215 New(31338, PL_reentrant_buffer->_strerror_buffer, PL_reentrant_buffer->_strerror_size, char); 216 #endif /* HAS_STRERROR_R */ 217 #ifdef HAS_TTYNAME_R 218 New(31338, PL_reentrant_buffer->_ttyname_buffer, PL_reentrant_buffer->_ttyname_size, char); 219 #endif /* HAS_TTYNAME_R */ 220 221 #endif /* USE_REENTRANT_API */ 222 } 223 224 void 225 Perl_reentrant_free(pTHX) { 226 #ifdef USE_REENTRANT_API 227 #ifdef HAS_ASCTIME_R 228 Safefree(PL_reentrant_buffer->_asctime_buffer); 229 #endif /* HAS_ASCTIME_R */ 230 #ifdef HAS_CRYPT_R 231 #if CRYPT_R_PROTO != REENTRANT_PROTO_B_CCD 232 Safefree(PL_reentrant_buffer->_crypt_struct_buffer); 233 #endif 234 #endif /* HAS_CRYPT_R */ 235 #ifdef HAS_CTIME_R 236 Safefree(PL_reentrant_buffer->_ctime_buffer); 237 #endif /* HAS_CTIME_R */ 238 #ifdef HAS_DRAND48_R 239 #endif /* HAS_DRAND48_R */ 240 #ifdef HAS_GETGRNAM_R 241 Safefree(PL_reentrant_buffer->_grent_buffer); 242 #endif /* HAS_GETGRNAM_R */ 243 #ifdef HAS_GETHOSTBYNAME_R 244 #if !(GETHOSTBYNAME_R_PROTO == REENTRANT_PROTO_I_CSD) 245 Safefree(PL_reentrant_buffer->_hostent_buffer); 246 #endif 247 #endif /* HAS_GETHOSTBYNAME_R */ 248 #ifdef HAS_GETLOGIN_R 249 Safefree(PL_reentrant_buffer->_getlogin_buffer); 250 #endif /* HAS_GETLOGIN_R */ 251 #ifdef HAS_GETNETBYNAME_R 252 #if !(GETNETBYNAME_R_PROTO == REENTRANT_PROTO_I_CSD) 253 Safefree(PL_reentrant_buffer->_netent_buffer); 254 #endif 255 #endif /* HAS_GETNETBYNAME_R */ 256 #ifdef HAS_GETPROTOBYNAME_R 257 #if !(GETPROTOBYNAME_R_PROTO == REENTRANT_PROTO_I_CSD) 258 Safefree(PL_reentrant_buffer->_protoent_buffer); 259 #endif 260 #endif /* HAS_GETPROTOBYNAME_R */ 261 #ifdef HAS_GETPWNAM_R 262 Safefree(PL_reentrant_buffer->_pwent_buffer); 263 #endif /* HAS_GETPWNAM_R */ 264 #ifdef HAS_GETSERVBYNAME_R 265 #if !(GETSERVBYNAME_R_PROTO == REENTRANT_PROTO_I_CCSD) 266 Safefree(PL_reentrant_buffer->_servent_buffer); 267 #endif 268 #endif /* HAS_GETSERVBYNAME_R */ 269 #ifdef HAS_GETSPNAM_R 270 Safefree(PL_reentrant_buffer->_spent_buffer); 271 #endif /* HAS_GETSPNAM_R */ 272 #ifdef HAS_GMTIME_R 273 #endif /* HAS_GMTIME_R */ 274 #ifdef HAS_LOCALTIME_R 275 #endif /* HAS_LOCALTIME_R */ 276 #ifdef HAS_RANDOM_R 277 #endif /* HAS_RANDOM_R */ 278 #ifdef HAS_READDIR_R 279 Safefree(PL_reentrant_buffer->_readdir_struct); 280 #endif /* HAS_READDIR_R */ 281 #ifdef HAS_READDIR64_R 282 Safefree(PL_reentrant_buffer->_readdir64_struct); 283 #endif /* HAS_READDIR64_R */ 284 #ifdef HAS_SETLOCALE_R 285 Safefree(PL_reentrant_buffer->_setlocale_buffer); 286 #endif /* HAS_SETLOCALE_R */ 287 #ifdef HAS_STRERROR_R 288 Safefree(PL_reentrant_buffer->_strerror_buffer); 289 #endif /* HAS_STRERROR_R */ 290 #ifdef HAS_TTYNAME_R 291 Safefree(PL_reentrant_buffer->_ttyname_buffer); 292 #endif /* HAS_TTYNAME_R */ 293 294 Safefree(PL_reentrant_buffer); 295 #endif /* USE_REENTRANT_API */ 296 } 297 298 void* 299 Perl_reentrant_retry(const char *f, ...) 300 { 301 dTHX; 302 void *retptr = NULL; 303 #ifdef USE_REENTRANT_API 304 # if defined(USE_HOSTENT_BUFFER) || defined(USE_GRENT_BUFFER) || defined(USE_NETENT_BUFFER) || defined(USE_PWENT_BUFFER) || defined(USE_PROTOENT_BUFFER) || defined(USE_SERVENT_BUFFER) 305 void *p0; 306 # endif 307 # if defined(USE_SERVENT_BUFFER) 308 void *p1; 309 # endif 310 # if defined(USE_HOSTENT_BUFFER) 311 size_t asize; 312 # endif 313 # if defined(USE_HOSTENT_BUFFER) || defined(USE_NETENT_BUFFER) || defined(USE_PROTOENT_BUFFER) || defined(USE_SERVENT_BUFFER) 314 int anint; 315 # endif 316 va_list ap; 317 318 va_start(ap, f); 319 320 switch (PL_op->op_type) { 321 #ifdef USE_HOSTENT_BUFFER 322 case OP_GHBYADDR: 323 case OP_GHBYNAME: 324 case OP_GHOSTENT: 325 { 326 #ifdef PERL_REENTRANT_MAXSIZE 327 if (PL_reentrant_buffer->_hostent_size <= 328 PERL_REENTRANT_MAXSIZE / 2) 329 #endif 330 { 331 PL_reentrant_buffer->_hostent_size *= 2; 332 Renew(PL_reentrant_buffer->_hostent_buffer, 333 PL_reentrant_buffer->_hostent_size, char); 334 switch (PL_op->op_type) { 335 case OP_GHBYADDR: 336 p0 = va_arg(ap, void *); 337 asize = va_arg(ap, size_t); 338 anint = va_arg(ap, int); 339 retptr = gethostbyaddr(p0, asize, anint); break; 340 case OP_GHBYNAME: 341 p0 = va_arg(ap, void *); 342 retptr = gethostbyname(p0); break; 343 case OP_GHOSTENT: 344 retptr = gethostent(); break; 345 default: 346 SETERRNO(ERANGE, LIB_INVARG); 347 break; 348 } 349 } 350 } 351 break; 352 #endif 353 #ifdef USE_GRENT_BUFFER 354 case OP_GGRNAM: 355 case OP_GGRGID: 356 case OP_GGRENT: 357 { 358 #ifdef PERL_REENTRANT_MAXSIZE 359 if (PL_reentrant_buffer->_grent_size <= 360 PERL_REENTRANT_MAXSIZE / 2) 361 #endif 362 { 363 Gid_t gid; 364 PL_reentrant_buffer->_grent_size *= 2; 365 Renew(PL_reentrant_buffer->_grent_buffer, 366 PL_reentrant_buffer->_grent_size, char); 367 switch (PL_op->op_type) { 368 case OP_GGRNAM: 369 p0 = va_arg(ap, void *); 370 retptr = getgrnam(p0); break; 371 case OP_GGRGID: 372 #if Gid_t_size < INTSIZE 373 gid = (Gid_t)va_arg(ap, int); 374 #else 375 gid = va_arg(ap, Gid_t); 376 #endif 377 retptr = getgrgid(gid); break; 378 case OP_GGRENT: 379 retptr = getgrent(); break; 380 default: 381 SETERRNO(ERANGE, LIB_INVARG); 382 break; 383 } 384 } 385 } 386 break; 387 #endif 388 #ifdef USE_NETENT_BUFFER 389 case OP_GNBYADDR: 390 case OP_GNBYNAME: 391 case OP_GNETENT: 392 { 393 #ifdef PERL_REENTRANT_MAXSIZE 394 if (PL_reentrant_buffer->_netent_size <= 395 PERL_REENTRANT_MAXSIZE / 2) 396 #endif 397 { 398 Netdb_net_t net; 399 PL_reentrant_buffer->_netent_size *= 2; 400 Renew(PL_reentrant_buffer->_netent_buffer, 401 PL_reentrant_buffer->_netent_size, char); 402 switch (PL_op->op_type) { 403 case OP_GNBYADDR: 404 net = va_arg(ap, Netdb_net_t); 405 anint = va_arg(ap, int); 406 retptr = getnetbyaddr(net, anint); break; 407 case OP_GNBYNAME: 408 p0 = va_arg(ap, void *); 409 retptr = getnetbyname(p0); break; 410 case OP_GNETENT: 411 retptr = getnetent(); break; 412 default: 413 SETERRNO(ERANGE, LIB_INVARG); 414 break; 415 } 416 } 417 } 418 break; 419 #endif 420 #ifdef USE_PWENT_BUFFER 421 case OP_GPWNAM: 422 case OP_GPWUID: 423 case OP_GPWENT: 424 { 425 #ifdef PERL_REENTRANT_MAXSIZE 426 if (PL_reentrant_buffer->_pwent_size <= 427 PERL_REENTRANT_MAXSIZE / 2) 428 #endif 429 { 430 Uid_t uid; 431 PL_reentrant_buffer->_pwent_size *= 2; 432 Renew(PL_reentrant_buffer->_pwent_buffer, 433 PL_reentrant_buffer->_pwent_size, char); 434 switch (PL_op->op_type) { 435 case OP_GPWNAM: 436 p0 = va_arg(ap, void *); 437 retptr = getpwnam(p0); break; 438 case OP_GPWUID: 439 #if Uid_t_size < INTSIZE 440 uid = (Uid_t)va_arg(ap, int); 441 #else 442 uid = va_arg(ap, Uid_t); 443 #endif 444 retptr = getpwuid(uid); break; 445 case OP_GPWENT: 446 retptr = getpwent(); break; 447 default: 448 SETERRNO(ERANGE, LIB_INVARG); 449 break; 450 } 451 } 452 } 453 break; 454 #endif 455 #ifdef USE_PROTOENT_BUFFER 456 case OP_GPBYNAME: 457 case OP_GPBYNUMBER: 458 case OP_GPROTOENT: 459 { 460 #ifdef PERL_REENTRANT_MAXSIZE 461 if (PL_reentrant_buffer->_protoent_size <= 462 PERL_REENTRANT_MAXSIZE / 2) 463 #endif 464 { 465 PL_reentrant_buffer->_protoent_size *= 2; 466 Renew(PL_reentrant_buffer->_protoent_buffer, 467 PL_reentrant_buffer->_protoent_size, char); 468 switch (PL_op->op_type) { 469 case OP_GPBYNAME: 470 p0 = va_arg(ap, void *); 471 retptr = getprotobyname(p0); break; 472 case OP_GPBYNUMBER: 473 anint = va_arg(ap, int); 474 retptr = getprotobynumber(anint); break; 475 case OP_GPROTOENT: 476 retptr = getprotoent(); break; 477 default: 478 SETERRNO(ERANGE, LIB_INVARG); 479 break; 480 } 481 } 482 } 483 break; 484 #endif 485 #ifdef USE_SERVENT_BUFFER 486 case OP_GSBYNAME: 487 case OP_GSBYPORT: 488 case OP_GSERVENT: 489 { 490 #ifdef PERL_REENTRANT_MAXSIZE 491 if (PL_reentrant_buffer->_servent_size <= 492 PERL_REENTRANT_MAXSIZE / 2) 493 #endif 494 { 495 PL_reentrant_buffer->_servent_size *= 2; 496 Renew(PL_reentrant_buffer->_servent_buffer, 497 PL_reentrant_buffer->_servent_size, char); 498 switch (PL_op->op_type) { 499 case OP_GSBYNAME: 500 p0 = va_arg(ap, void *); 501 p1 = va_arg(ap, void *); 502 retptr = getservbyname(p0, p1); break; 503 case OP_GSBYPORT: 504 anint = va_arg(ap, int); 505 p0 = va_arg(ap, void *); 506 retptr = getservbyport(anint, p0); break; 507 case OP_GSERVENT: 508 retptr = getservent(); break; 509 default: 510 SETERRNO(ERANGE, LIB_INVARG); 511 break; 512 } 513 } 514 } 515 break; 516 #endif 517 default: 518 /* Not known how to retry, so just fail. */ 519 break; 520 } 521 522 va_end(ap); 523 #endif 524 return retptr; 525 } 526 527