Software / code / prosody
Comparison
util-src/pposix.c @ 7889:b8d694646597
util-src/*.c: Attach pointer * to name instead of type
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Sun, 12 Feb 2017 16:42:29 +0100 |
| parent | 7835:a809dcfd0c5b |
| child | 7919:251bf68922d9 |
comparison
equal
deleted
inserted
replaced
| 7888:74187ee6ed55 | 7889:b8d694646597 |
|---|---|
| 62 #define fork() rfork(RFPROC) | 62 #define fork() rfork(RFPROC) |
| 63 #endif | 63 #endif |
| 64 | 64 |
| 65 /* Daemonization support */ | 65 /* Daemonization support */ |
| 66 | 66 |
| 67 static int lc_daemonize(lua_State* L) { | 67 static int lc_daemonize(lua_State *L) { |
| 68 | 68 |
| 69 pid_t pid; | 69 pid_t pid; |
| 70 | 70 |
| 71 if(getppid() == 1) { | 71 if(getppid() == 1) { |
| 72 lua_pushboolean(L, 0); | 72 lua_pushboolean(L, 0); |
| 116 return 2; | 116 return 2; |
| 117 } | 117 } |
| 118 | 118 |
| 119 /* Syslog support */ | 119 /* Syslog support */ |
| 120 | 120 |
| 121 const char* const facility_strings[] = { | 121 const char *const facility_strings[] = { |
| 122 "auth", | 122 "auth", |
| 123 #if !(defined(sun) || defined(__sun)) | 123 #if !(defined(sun) || defined(__sun)) |
| 124 "authpriv", | 124 "authpriv", |
| 125 #endif | 125 #endif |
| 126 "cron", | 126 "cron", |
| 178 prepending the changed string, and if the string it points to ceases to | 178 prepending the changed string, and if the string it points to ceases to |
| 179 exist, the results are undefined. Most portable is to use a string | 179 exist, the results are undefined. Most portable is to use a string |
| 180 constant. | 180 constant. |
| 181 " -- syslog manpage | 181 " -- syslog manpage |
| 182 */ | 182 */ |
| 183 char* syslog_ident = NULL; | 183 char *syslog_ident = NULL; |
| 184 | 184 |
| 185 int lc_syslog_open(lua_State* L) { | 185 int lc_syslog_open(lua_State *L) { |
| 186 int facility = luaL_checkoption(L, 2, "daemon", facility_strings); | 186 int facility = luaL_checkoption(L, 2, "daemon", facility_strings); |
| 187 facility = facility_constants[facility]; | 187 facility = facility_constants[facility]; |
| 188 | 188 |
| 189 luaL_checkstring(L, 1); | 189 luaL_checkstring(L, 1); |
| 190 | 190 |
| 196 | 196 |
| 197 openlog(syslog_ident, LOG_PID, facility); | 197 openlog(syslog_ident, LOG_PID, facility); |
| 198 return 0; | 198 return 0; |
| 199 } | 199 } |
| 200 | 200 |
| 201 const char* const level_strings[] = { | 201 const char *const level_strings[] = { |
| 202 "debug", | 202 "debug", |
| 203 "info", | 203 "info", |
| 204 "notice", | 204 "notice", |
| 205 "warn", | 205 "warn", |
| 206 "error", | 206 "error", |
| 212 LOG_NOTICE, | 212 LOG_NOTICE, |
| 213 LOG_WARNING, | 213 LOG_WARNING, |
| 214 LOG_CRIT, | 214 LOG_CRIT, |
| 215 -1 | 215 -1 |
| 216 }; | 216 }; |
| 217 int lc_syslog_log(lua_State* L) { | 217 int lc_syslog_log(lua_State *L) { |
| 218 int level = level_constants[luaL_checkoption(L, 1, "notice", level_strings)]; | 218 int level = level_constants[luaL_checkoption(L, 1, "notice", level_strings)]; |
| 219 | 219 |
| 220 if(lua_gettop(L) == 3) { | 220 if(lua_gettop(L) == 3) { |
| 221 syslog(level, "%s: %s", luaL_checkstring(L, 2), luaL_checkstring(L, 3)); | 221 syslog(level, "%s: %s", luaL_checkstring(L, 2), luaL_checkstring(L, 3)); |
| 222 } else { | 222 } else { |
| 224 } | 224 } |
| 225 | 225 |
| 226 return 0; | 226 return 0; |
| 227 } | 227 } |
| 228 | 228 |
| 229 int lc_syslog_close(lua_State* L) { | 229 int lc_syslog_close(lua_State *L) { |
| 230 closelog(); | 230 closelog(); |
| 231 | 231 |
| 232 if(syslog_ident) { | 232 if(syslog_ident) { |
| 233 free(syslog_ident); | 233 free(syslog_ident); |
| 234 syslog_ident = NULL; | 234 syslog_ident = NULL; |
| 235 } | 235 } |
| 236 | 236 |
| 237 return 0; | 237 return 0; |
| 238 } | 238 } |
| 239 | 239 |
| 240 int lc_syslog_setmask(lua_State* L) { | 240 int lc_syslog_setmask(lua_State *L) { |
| 241 int level_idx = luaL_checkoption(L, 1, "notice", level_strings); | 241 int level_idx = luaL_checkoption(L, 1, "notice", level_strings); |
| 242 int mask = 0; | 242 int mask = 0; |
| 243 | 243 |
| 244 do { | 244 do { |
| 245 mask |= LOG_MASK(level_constants[level_idx]); | 245 mask |= LOG_MASK(level_constants[level_idx]); |
| 249 return 0; | 249 return 0; |
| 250 } | 250 } |
| 251 | 251 |
| 252 /* getpid */ | 252 /* getpid */ |
| 253 | 253 |
| 254 int lc_getpid(lua_State* L) { | 254 int lc_getpid(lua_State *L) { |
| 255 lua_pushinteger(L, getpid()); | 255 lua_pushinteger(L, getpid()); |
| 256 return 1; | 256 return 1; |
| 257 } | 257 } |
| 258 | 258 |
| 259 /* UID/GID functions */ | 259 /* UID/GID functions */ |
| 260 | 260 |
| 261 int lc_getuid(lua_State* L) { | 261 int lc_getuid(lua_State *L) { |
| 262 lua_pushinteger(L, getuid()); | 262 lua_pushinteger(L, getuid()); |
| 263 return 1; | 263 return 1; |
| 264 } | 264 } |
| 265 | 265 |
| 266 int lc_getgid(lua_State* L) { | 266 int lc_getgid(lua_State *L) { |
| 267 lua_pushinteger(L, getgid()); | 267 lua_pushinteger(L, getgid()); |
| 268 return 1; | 268 return 1; |
| 269 } | 269 } |
| 270 | 270 |
| 271 int lc_setuid(lua_State* L) { | 271 int lc_setuid(lua_State *L) { |
| 272 int uid = -1; | 272 int uid = -1; |
| 273 | 273 |
| 274 if(lua_gettop(L) < 1) { | 274 if(lua_gettop(L) < 1) { |
| 275 return 0; | 275 return 0; |
| 276 } | 276 } |
| 277 | 277 |
| 278 if(!lua_isnumber(L, 1) && lua_tostring(L, 1)) { | 278 if(!lua_isnumber(L, 1) && lua_tostring(L, 1)) { |
| 279 /* Passed UID is actually a string, so look up the UID */ | 279 /* Passed UID is actually a string, so look up the UID */ |
| 280 struct passwd* p; | 280 struct passwd *p; |
| 281 p = getpwnam(lua_tostring(L, 1)); | 281 p = getpwnam(lua_tostring(L, 1)); |
| 282 | 282 |
| 283 if(!p) { | 283 if(!p) { |
| 284 lua_pushboolean(L, 0); | 284 lua_pushboolean(L, 0); |
| 285 lua_pushstring(L, "no-such-user"); | 285 lua_pushstring(L, "no-such-user"); |
| 301 | 301 |
| 302 switch(errno) { | 302 switch(errno) { |
| 303 case EINVAL: | 303 case EINVAL: |
| 304 lua_pushstring(L, "invalid-uid"); | 304 lua_pushstring(L, "invalid-uid"); |
| 305 break; | 305 break; |
| 306 | |
| 306 case EPERM: | 307 case EPERM: |
| 307 lua_pushstring(L, "permission-denied"); | 308 lua_pushstring(L, "permission-denied"); |
| 308 break; | 309 break; |
| 310 | |
| 309 default: | 311 default: |
| 310 lua_pushstring(L, "unknown-error"); | 312 lua_pushstring(L, "unknown-error"); |
| 311 } | 313 } |
| 312 | 314 |
| 313 return 2; | 315 return 2; |
| 322 lua_pushboolean(L, 0); | 324 lua_pushboolean(L, 0); |
| 323 lua_pushstring(L, "invalid-uid"); | 325 lua_pushstring(L, "invalid-uid"); |
| 324 return 2; | 326 return 2; |
| 325 } | 327 } |
| 326 | 328 |
| 327 int lc_setgid(lua_State* L) { | 329 int lc_setgid(lua_State *L) { |
| 328 int gid = -1; | 330 int gid = -1; |
| 329 | 331 |
| 330 if(lua_gettop(L) < 1) { | 332 if(lua_gettop(L) < 1) { |
| 331 return 0; | 333 return 0; |
| 332 } | 334 } |
| 333 | 335 |
| 334 if(!lua_isnumber(L, 1) && lua_tostring(L, 1)) { | 336 if(!lua_isnumber(L, 1) && lua_tostring(L, 1)) { |
| 335 /* Passed GID is actually a string, so look up the GID */ | 337 /* Passed GID is actually a string, so look up the GID */ |
| 336 struct group* g; | 338 struct group *g; |
| 337 g = getgrnam(lua_tostring(L, 1)); | 339 g = getgrnam(lua_tostring(L, 1)); |
| 338 | 340 |
| 339 if(!g) { | 341 if(!g) { |
| 340 lua_pushboolean(L, 0); | 342 lua_pushboolean(L, 0); |
| 341 lua_pushstring(L, "no-such-group"); | 343 lua_pushstring(L, "no-such-group"); |
| 357 | 359 |
| 358 switch(errno) { | 360 switch(errno) { |
| 359 case EINVAL: | 361 case EINVAL: |
| 360 lua_pushstring(L, "invalid-gid"); | 362 lua_pushstring(L, "invalid-gid"); |
| 361 break; | 363 break; |
| 364 | |
| 362 case EPERM: | 365 case EPERM: |
| 363 lua_pushstring(L, "permission-denied"); | 366 lua_pushstring(L, "permission-denied"); |
| 364 break; | 367 break; |
| 368 | |
| 365 default: | 369 default: |
| 366 lua_pushstring(L, "unknown-error"); | 370 lua_pushstring(L, "unknown-error"); |
| 367 } | 371 } |
| 368 | 372 |
| 369 return 2; | 373 return 2; |
| 378 lua_pushboolean(L, 0); | 382 lua_pushboolean(L, 0); |
| 379 lua_pushstring(L, "invalid-gid"); | 383 lua_pushstring(L, "invalid-gid"); |
| 380 return 2; | 384 return 2; |
| 381 } | 385 } |
| 382 | 386 |
| 383 int lc_initgroups(lua_State* L) { | 387 int lc_initgroups(lua_State *L) { |
| 384 int ret; | 388 int ret; |
| 385 gid_t gid; | 389 gid_t gid; |
| 386 struct passwd* p; | 390 struct passwd *p; |
| 387 | 391 |
| 388 if(!lua_isstring(L, 1)) { | 392 if(!lua_isstring(L, 1)) { |
| 389 lua_pushnil(L); | 393 lua_pushnil(L); |
| 390 lua_pushstring(L, "invalid-username"); | 394 lua_pushstring(L, "invalid-username"); |
| 391 return 2; | 395 return 2; |
| 405 | 409 |
| 406 switch(lua_type(L, 2)) { | 410 switch(lua_type(L, 2)) { |
| 407 case LUA_TNIL: | 411 case LUA_TNIL: |
| 408 gid = p->pw_gid; | 412 gid = p->pw_gid; |
| 409 break; | 413 break; |
| 414 | |
| 410 case LUA_TNUMBER: | 415 case LUA_TNUMBER: |
| 411 gid = lua_tointeger(L, 2); | 416 gid = lua_tointeger(L, 2); |
| 412 break; | 417 break; |
| 418 | |
| 413 default: | 419 default: |
| 414 lua_pushnil(L); | 420 lua_pushnil(L); |
| 415 lua_pushstring(L, "invalid-gid"); | 421 lua_pushstring(L, "invalid-gid"); |
| 416 return 2; | 422 return 2; |
| 417 } | 423 } |
| 422 switch(errno) { | 428 switch(errno) { |
| 423 case ENOMEM: | 429 case ENOMEM: |
| 424 lua_pushnil(L); | 430 lua_pushnil(L); |
| 425 lua_pushstring(L, "no-memory"); | 431 lua_pushstring(L, "no-memory"); |
| 426 break; | 432 break; |
| 433 | |
| 427 case EPERM: | 434 case EPERM: |
| 428 lua_pushnil(L); | 435 lua_pushnil(L); |
| 429 lua_pushstring(L, "permission-denied"); | 436 lua_pushstring(L, "permission-denied"); |
| 430 break; | 437 break; |
| 438 | |
| 431 default: | 439 default: |
| 432 lua_pushnil(L); | 440 lua_pushnil(L); |
| 433 lua_pushstring(L, "unknown-error"); | 441 lua_pushstring(L, "unknown-error"); |
| 434 } | 442 } |
| 435 } else { | 443 } else { |
| 438 } | 446 } |
| 439 | 447 |
| 440 return 2; | 448 return 2; |
| 441 } | 449 } |
| 442 | 450 |
| 443 int lc_umask(lua_State* L) { | 451 int lc_umask(lua_State *L) { |
| 444 char old_mode_string[7]; | 452 char old_mode_string[7]; |
| 445 mode_t old_mode = umask(strtoul(luaL_checkstring(L, 1), NULL, 8)); | 453 mode_t old_mode = umask(strtoul(luaL_checkstring(L, 1), NULL, 8)); |
| 446 | 454 |
| 447 snprintf(old_mode_string, sizeof(old_mode_string), "%03o", old_mode); | 455 snprintf(old_mode_string, sizeof(old_mode_string), "%03o", old_mode); |
| 448 old_mode_string[sizeof(old_mode_string) - 1] = 0; | 456 old_mode_string[sizeof(old_mode_string) - 1] = 0; |
| 449 lua_pushstring(L, old_mode_string); | 457 lua_pushstring(L, old_mode_string); |
| 450 | 458 |
| 451 return 1; | 459 return 1; |
| 452 } | 460 } |
| 453 | 461 |
| 454 int lc_mkdir(lua_State* L) { | 462 int lc_mkdir(lua_State *L) { |
| 455 int ret = mkdir(luaL_checkstring(L, 1), S_IRUSR | S_IWUSR | S_IXUSR | 463 int ret = mkdir(luaL_checkstring(L, 1), S_IRUSR | S_IWUSR | S_IXUSR |
| 456 | S_IRGRP | S_IWGRP | S_IXGRP | 464 | S_IRGRP | S_IWGRP | S_IXGRP |
| 457 | S_IROTH | S_IXOTH); /* mode 775 */ | 465 | S_IROTH | S_IXOTH); /* mode 775 */ |
| 458 | 466 |
| 459 lua_pushboolean(L, ret == 0); | 467 lua_pushboolean(L, ret == 0); |
| 474 * Any negative limit will be replace with the current limit by an additional call of getrlimit(). | 482 * Any negative limit will be replace with the current limit by an additional call of getrlimit(). |
| 475 * | 483 * |
| 476 * Example usage: | 484 * Example usage: |
| 477 * pposix.setrlimit("NOFILE", 1000, 2000) | 485 * pposix.setrlimit("NOFILE", 1000, 2000) |
| 478 */ | 486 */ |
| 479 int string2resource(const char* s) { | 487 int string2resource(const char *s) { |
| 480 if(!strcmp(s, "CORE")) { | 488 if(!strcmp(s, "CORE")) { |
| 481 return RLIMIT_CORE; | 489 return RLIMIT_CORE; |
| 482 } | 490 } |
| 483 | 491 |
| 484 if(!strcmp(s, "CPU")) { | 492 if(!strcmp(s, "CPU")) { |
| 524 | 532 |
| 525 #endif | 533 #endif |
| 526 return -1; | 534 return -1; |
| 527 } | 535 } |
| 528 | 536 |
| 529 unsigned long int arg_to_rlimit(lua_State* L, int idx, rlim_t current) { | 537 unsigned long int arg_to_rlimit(lua_State *L, int idx, rlim_t current) { |
| 530 switch(lua_type(L, idx)) { | 538 switch(lua_type(L, idx)) { |
| 531 case LUA_TSTRING: | 539 case LUA_TSTRING: |
| 532 | 540 |
| 533 if(strcmp(lua_tostring(L, idx), "unlimited") == 0) { | 541 if(strcmp(lua_tostring(L, idx), "unlimited") == 0) { |
| 534 return RLIM_INFINITY; | 542 return RLIM_INFINITY; |
| 535 } | 543 } |
| 536 | 544 |
| 537 case LUA_TNUMBER: | 545 case LUA_TNUMBER: |
| 538 return lua_tointeger(L, idx); | 546 return lua_tointeger(L, idx); |
| 547 | |
| 539 case LUA_TNONE: | 548 case LUA_TNONE: |
| 540 case LUA_TNIL: | 549 case LUA_TNIL: |
| 541 return current; | 550 return current; |
| 551 | |
| 542 default: | 552 default: |
| 543 return luaL_argerror(L, idx, "unexpected type"); | 553 return luaL_argerror(L, idx, "unexpected type"); |
| 544 } | 554 } |
| 545 } | 555 } |
| 546 | 556 |
| 547 int lc_setrlimit(lua_State* L) { | 557 int lc_setrlimit(lua_State *L) { |
| 548 struct rlimit lim; | 558 struct rlimit lim; |
| 549 int arguments = lua_gettop(L); | 559 int arguments = lua_gettop(L); |
| 550 int rid = -1; | 560 int rid = -1; |
| 551 | 561 |
| 552 if(arguments < 1 || arguments > 3) { | 562 if(arguments < 1 || arguments > 3) { |
| 581 | 591 |
| 582 lua_pushboolean(L, 1); | 592 lua_pushboolean(L, 1); |
| 583 return 1; | 593 return 1; |
| 584 } | 594 } |
| 585 | 595 |
| 586 int lc_getrlimit(lua_State* L) { | 596 int lc_getrlimit(lua_State *L) { |
| 587 int arguments = lua_gettop(L); | 597 int arguments = lua_gettop(L); |
| 588 const char* resource = NULL; | 598 const char *resource = NULL; |
| 589 int rid = -1; | 599 int rid = -1; |
| 590 struct rlimit lim; | 600 struct rlimit lim; |
| 591 | 601 |
| 592 if(arguments != 1) { | 602 if(arguments != 1) { |
| 593 lua_pushboolean(L, 0); | 603 lua_pushboolean(L, 0); |
| 626 } | 636 } |
| 627 | 637 |
| 628 return 3; | 638 return 3; |
| 629 } | 639 } |
| 630 | 640 |
| 631 int lc_abort(lua_State* L) { | 641 int lc_abort(lua_State *L) { |
| 632 abort(); | 642 abort(); |
| 633 return 0; | 643 return 0; |
| 634 } | 644 } |
| 635 | 645 |
| 636 int lc_uname(lua_State* L) { | 646 int lc_uname(lua_State *L) { |
| 637 struct utsname uname_info; | 647 struct utsname uname_info; |
| 638 | 648 |
| 639 if(uname(&uname_info) != 0) { | 649 if(uname(&uname_info) != 0) { |
| 640 lua_pushnil(L); | 650 lua_pushnil(L); |
| 641 lua_pushstring(L, strerror(errno)); | 651 lua_pushstring(L, strerror(errno)); |
| 658 lua_setfield(L, -2, "domainname"); | 668 lua_setfield(L, -2, "domainname"); |
| 659 #endif | 669 #endif |
| 660 return 1; | 670 return 1; |
| 661 } | 671 } |
| 662 | 672 |
| 663 int lc_setenv(lua_State* L) { | 673 int lc_setenv(lua_State *L) { |
| 664 const char* var = luaL_checkstring(L, 1); | 674 const char *var = luaL_checkstring(L, 1); |
| 665 const char* value; | 675 const char *value; |
| 666 | 676 |
| 667 /* If the second argument is nil or nothing, unset the var */ | 677 /* If the second argument is nil or nothing, unset the var */ |
| 668 if(lua_isnoneornil(L, 2)) { | 678 if(lua_isnoneornil(L, 2)) { |
| 669 if(unsetenv(var) != 0) { | 679 if(unsetenv(var) != 0) { |
| 670 lua_pushnil(L); | 680 lua_pushnil(L); |
| 687 lua_pushboolean(L, 1); | 697 lua_pushboolean(L, 1); |
| 688 return 1; | 698 return 1; |
| 689 } | 699 } |
| 690 | 700 |
| 691 #ifdef WITH_MALLINFO | 701 #ifdef WITH_MALLINFO |
| 692 int lc_meminfo(lua_State* L) { | 702 int lc_meminfo(lua_State *L) { |
| 693 struct mallinfo info = mallinfo(); | 703 struct mallinfo info = mallinfo(); |
| 694 lua_newtable(L); | 704 lua_newtable(L); |
| 695 /* This is the total size of memory allocated with sbrk by malloc, in bytes. */ | 705 /* This is the total size of memory allocated with sbrk by malloc, in bytes. */ |
| 696 lua_pushinteger(L, info.arena); | 706 lua_pushinteger(L, info.arena); |
| 697 lua_setfield(L, -2, "allocated"); | 707 lua_setfield(L, -2, "allocated"); |
| 715 /* File handle extraction blatantly stolen from | 725 /* File handle extraction blatantly stolen from |
| 716 * https://github.com/rrthomas/luaposix/blob/master/lposix.c#L631 | 726 * https://github.com/rrthomas/luaposix/blob/master/lposix.c#L631 |
| 717 * */ | 727 * */ |
| 718 | 728 |
| 719 #if _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L || defined(_GNU_SOURCE) | 729 #if _XOPEN_SOURCE >= 600 || _POSIX_C_SOURCE >= 200112L || defined(_GNU_SOURCE) |
| 720 int lc_fallocate(lua_State* L) { | 730 int lc_fallocate(lua_State *L) { |
| 721 int ret; | 731 int ret; |
| 722 off_t offset, len; | 732 off_t offset, len; |
| 723 FILE* f = *(FILE**) luaL_checkudata(L, 1, LUA_FILEHANDLE); | 733 FILE *f = *(FILE **) luaL_checkudata(L, 1, LUA_FILEHANDLE); |
| 724 | 734 |
| 725 if(f == NULL) { | 735 if(f == NULL) { |
| 726 return luaL_error(L, "attempt to use a closed file"); | 736 return luaL_error(L, "attempt to use a closed file"); |
| 727 } | 737 } |
| 728 | 738 |
| 761 lua_pushboolean(L, 1); | 771 lua_pushboolean(L, 1); |
| 762 return 1; | 772 return 1; |
| 763 } else { | 773 } else { |
| 764 lua_pushnil(L); | 774 lua_pushnil(L); |
| 765 lua_pushstring(L, strerror(ret)); | 775 lua_pushstring(L, strerror(ret)); |
| 776 | |
| 766 /* posix_fallocate() can leave a bunch of NULs at the end, so we cut that | 777 /* posix_fallocate() can leave a bunch of NULs at the end, so we cut that |
| 767 * this assumes that offset == length of the file */ | 778 * this assumes that offset == length of the file */ |
| 768 if(ftruncate(fileno(f), offset) != 0) { | 779 if(ftruncate(fileno(f), offset) != 0) { |
| 769 lua_pushstring(L, strerror(errno)); | 780 lua_pushstring(L, strerror(errno)); |
| 770 return 3; | 781 return 3; |
| 771 } | 782 } |
| 783 | |
| 772 return 2; | 784 return 2; |
| 773 } | 785 } |
| 774 } | 786 } |
| 775 #endif | 787 #endif |
| 776 | 788 |
| 777 /* Register functions */ | 789 /* Register functions */ |
| 778 | 790 |
| 779 int luaopen_util_pposix(lua_State* L) { | 791 int luaopen_util_pposix(lua_State *L) { |
| 780 #if (LUA_VERSION_NUM > 501) | 792 #if (LUA_VERSION_NUM > 501) |
| 781 luaL_checkversion(L); | 793 luaL_checkversion(L); |
| 782 #endif | 794 #endif |
| 783 luaL_Reg exports[] = { | 795 luaL_Reg exports[] = { |
| 784 { "abort", lc_abort }, | 796 { "abort", lc_abort }, |