1.\" $OpenBSD: pkg_create.1,v 1.103 2016/09/06 10:41:51 espie Exp $ 2.\" 3.\" Documentation and design originally from FreeBSD. All the code has 4.\" been rewritten since. We keep the documentation's notice: 5.\" 6.\" Redistribution and use in source and binary forms, with or without 7.\" modification, are permitted provided that the following conditions 8.\" are met: 9.\" 1. Redistributions of source code must retain the above copyright 10.\" notice, this list of conditions and the following disclaimer. 11.\" 2. Redistributions in binary form must reproduce the above copyright 12.\" notice, this list of conditions and the following disclaimer in the 13.\" documentation and/or other materials provided with the distribution. 14.\" 15.\" Jordan K. Hubbard 16.\" 17.\" 18.\" hacked up by John Kohl for NetBSD--fixed a few bugs, extended keywords, 19.\" added dependency tracking, etc. 20.\" 21.\" [jkh] Took John's changes back and made some additional extensions for 22.\" better integration with FreeBSD's new ports collection. 23.\" 24.Dd $Mdocdate: September 6 2016 $ 25.Dt PKG_CREATE 1 26.Os 27.Sh NAME 28.Nm pkg_create 29.Nd create binary software package for distribution 30.Sh SYNOPSIS 31.Nm pkg_create 32.Bk -words 33.Op Fl mnQqvx 34.Op Fl A Ar arches 35.Op Fl B Ar pkg-destdir 36.Op Fl D Ar name Ns Op = Ns Ar value 37.Op Fl L Ar localbase 38.Op Fl M Ar displayfile 39.Op Fl P Ar pkgpath : Ns Ar pkgspec : Ns Ar default 40.Op Fl U Ar undisplayfile 41.Op Fl W Ar libspec 42.Fl d Ar desc 43.Fl D Ar COMMENT Ns = Ns Ar value 44.Fl D Ar PORTSDIR Ns = Ns Ar value 45.Fl f Ar packinglist 46.Fl p Ar prefix 47.Ar pkg-name 48.Ek 49.Nm pkg_create 50.Fl f Ar packinglist 51.Sh DESCRIPTION 52The 53.Nm 54command is normally used to create a binary package named 55.Ar pkg-name , 56for subsequent use with 57.Xr pkg_add 1 , 58.Xr pkg_delete 1 59and 60.Xr pkg_info 1 . 61.Ar pkg-name 62will traditionally have a 63.Dq .tgz 64extension, to denote the underlying binary format. 65.Ar pkg-name 66must follow 67.Xr packages-specs 7 . 68.Pp 69Use of the 70.Xr ports 7 71infrastructure instead of manual 72.Nm 73invocation is strongly recommended. 74.Pp 75.Nm 76can also be used to recreate a binary package from an existing installation. 77.Pp 78During package creation, 79.Nm 80replaces too long file names with smaller equivalents 81.Po 82see 83.Xr package 5 84.Pc , 85records extra information in the packing-list, such as the existence 86of symlinks and hard links, computes and stores file checksums, and 87verifies that all special objects are properly annotated in the packing-list. 88.Pp 89It will also check all required shared libraries 90for reachability, by looking into all installed dependencies. 91It may also ask the ports tree for extra dependencies, 92provided some other dependency refers to the same 93.Ev BASE_PKGPATH 94.Po 95see 96.Xr bsd.port.mk 5 97.Pc . 98The rationale is that those libraries must already be present for 99the package to build correctly, and thus be reachable through the 100subset of dependencies that are not pure 101.Ev RUN_DEPENDS . 102.Pp 103The options are as follows: 104.Bl -tag -width Ds 105.It Fl A Ar arches 106Register a list of architectures for which this package should install. 107.Ar arches 108is a comma-separated list of architectures. 109Use 110.Sq * 111to mean any architecture (e.g., arch-independent packages). 112.It Fl B Ar pkg-destdir 113Set 114.Ar pkg-destdir 115as the prefix to prepend to any file to select for the package. 116.It Fl D Ar name Ns Op = Ns Ar value 117Define 118.Ar name 119to 120.Ar value 121(or just define it) 122for substitution and fragment inclusion purposes. 123Some specific 124.Ar names 125have extra meaning, see 126.Xr bsd.port.mk 5 127for details: 128.Pp 129.Bl -tag -width FULLPKGPATH -compact 130.It Ar CDROM 131Set to the port's Makefile 132.Ar PERMIT_PACKAGE_CDROM . 133.It Ar COMMENT 134Set package 135.Dq one line description 136(mandatory). 137.It Ar HISTORY_DIR 138Record checksums of files in permanent location 139.Pa ${HISTORY_DIR}/${FULLPKGPATH:S,/,./g} . 140.It Ar FTP 141Set to the port's Makefile 142.Ar PERMIT_PACKAGE_FTP . 143.It Ar FULLPKGPATH 144Strongly recommended, otherwise updates won't work. 145.It Ar HOMEPAGE 146If defined, appended to the description. 147.It Ar MAINTAINER 148If defined, appended to the description. 149.It Ar USE_GROFF 150Set to 1 to have groff format manpages behind the scenes during 151package creation. 152.El 153.It Fl d No [-] Ns Ar desc 154Fetch long description for package from file 155.Ar desc 156or, if preceded by 157.Sq - , 158the argument itself. 159.It Fl f Ar packinglist 160Fetch 161.Dq packing-list 162for package from the file 163.Ar packinglist . 164Several packing-lists can be mentioned, in which case they will be 165concatenated together. 166.It Fl L Ar localbase 167Record 168.Ar localbase 169as the localbase used in the package 170.Po 171By default, 172.Pa /usr/local 173.Pc . 174Packages built with another localbase can only be installed by using 175the same localbase in 176.Xr pkg_add 1 , 177to prevent errors. 178.It Fl M Ar displayfile 179Display the file (using 180.Xr more 1 ) 181after installing the package. 182Useful for things like 183legal notices on almost-free software, etc. 184.It Fl m 185Causes 186.Nm 187to always display the progress meter in cases it would not do so by default. 188.It Fl n 189Don't actually create a package. 190.It Fl P Ar pkgpath : Ns Ar pkgspec : Ns Ar default 191Declare a dependency on a package matching 192.Ar pkgspec 193.Pq see Xr packages-specs 7 . 194An appropriate package must be installed before this package may be 195installed, and that package must be deinstalled before this package 196is deinstalled. 197The dependency also contains a 198.Ar pkgpath 199.Po 200see 201.Xr pkgpath 7 202.Pc 203and a 204.Ar default 205package name, in case there is no listing of available packages. 206.It Fl p Ar prefix 207Set 208.Ar prefix 209as the initial directory 210.Dq base 211to start from in selecting files for 212the package, and to record as the base for installing the package. 213.It Fl Q 214Print out the files in the actual packing-list of the package being 215generated, with explicit typing 216.Pq e.g. Cm @file , @lib , ... . 217.It Fl q 218Print out the actual packing-list of the package being generated 219(query mode). 220Most often used in combination with 221.Fl n . 222.It Fl U Ar undisplayfile 223Display the file (using 224.Xr more 1 ) 225when deinstalling the package. 226Useful for reminders about stuff to clean up. 227.It Fl v 228Turn on verbose output. 229.It Fl W Ar libspec 230Package needs a shared library to work. 231.Ar libspec 232is 233.Sq name.major.minor 234or 235.Sq path/name.major.minor . 236The package won't be installed unless a library with the same name, 237the exact same major number and at least the same minor number can 238be located. 239A library without path is searched through dependent packages under the 240same 241.Ar localbase , 242then in the system libraries under 243.Pa /usr/lib 244and 245.Pa /usr/X11R6/lib . 246A library with a path is only searched through dependent packages, 247that path being relative to 248.Ar localbase . 249.It Fl x 250Disable progress meter. 251.El 252.Pp 253.Nm 254can also be invoked with only the packing-list from an installed package. 255It will recreate the corresponding binary package in the current directory 256from the installation, or error out if any problem is found. 257For example, 258the following will recreate a 259.Pa kdelibs-3.4.3.tgz 260package: 261.Bd -literal -offset indent 262pkg_create -f /var/db/pkg/kdelibs-3.4.3/+CONTENTS 263.Ed 264.Sh PACKING-LIST DETAILS 265The 266.Dq packing-list 267format (see 268.Fl f ) 269is fairly simple, being basically a list of filenames and directory names 270to include in the package. 271.Pp 272Substitution of variables and inclusion of fragments is documented in the 273next section. 274.Pp 275Directory names are denoted by a trailing slash. 276.Pp 277There are some annotations that can be inserted for better control. 278All these commands start with an 279.Sq @ . 280The following annotations can be inserted manually: 281.Pp 282.Bl -tag -width Ds -compact 283.It Cm @ask-update Ar pkgspec Ar message 284Mechanism to prevent unwanted updates. 285If the new package is installed as part of an update matching 286.Ar pkgspec , 287the 288.Ar message 289will be displayed to the user. 290In non-interactive mode, the update will abort. 291Otherwise, the user will have a chance to proceed. 292Automated updates can be done by using 293.Fl D Ar update_stem , 294with 295.Ar stem 296the stem of the 297.Ar pkgspec . 298Classical use case for postgresql: 299.Bd -literal -offset 3n 300@ask-update postgresql-server-<8 Make sure your existing database is backed up 301.Ed 302.Pp 303Use very sparingly. 304Most cases that seem to require manual updates just require a bit more thought. 305.Pp 306.It Cm @bin Ar filename 307Describe the file as an 308.Ox 309binary executable (not a script). 310.Pp 311.It Cm @comment Ar string 312Place a comment in the packing-list. 313Useful in trying to document some particularly hairy sequence that 314may trip someone up later. 315Can also be used to comment out elements that update-plist 316.Pq see Xr bsd.port.mk 5 317will insist in inserting in a packing-list. 318.Pp 319The special comment 320.Cm @comment Ar "no checksum" 321can be used to tag the next file as special: even though its characteristics 322will be recorded in the package, it can be altered after installation, and 323.Xr pkg_delete 1 324will still delete it. 325.Pp 326.It Cm @conflict Ar pkgspec 327Declare a conflict with packages matching 328.Ar pkgspec 329.Pq see Xr packages-specs 7 . 330The 331.Ar pkgname 332package can 333.Em not 334be installed if a package 335matching 336.Ar pkgspec 337has been installed because they install the same files and thus conflict. 338.Pp 339.It Cm @cwd Ar pathname 340Set the package current directory. 341All subsequent filenames will be assumed relative to 342.Ar pathname . 343.Pp 344.It Cm @dir Ar directoryname 345Create directory 346.Ar directoryname 347at 348.Xr pkg_add 1 349time, taking 350.Cm @mode , 351.Cm @group , 352and 353.Cm @owner 354into account, and remove it during 355.Xr pkg_delete 1 . 356Directories to remove can be shared between packages. 357If 358.Ar name 359does not begin with an @, same as 360.Dl name/ 361.Pp 362.It Cm @exec Ar command 363Execute 364.Ar command 365during 366.Xr pkg_add 1 . 367Note that 368.Cm @exec 369commands are executed relative to their location in the packing-list, 370so they can rely on any data that have already been extracted, 371but not on anything that is listed after them. 372Some special elements, such as new users and new groups, are always 373created first, so that 374.Cm @exec 375can rely on them. 376.Pp 377.Xr pkg_add 1 378and 379.Xr pkg_delete 1 380set the 381.Ev PATH 382to a predictable value: 383.Bd -literal -offset indent 384/bin:/sbin:/usr/bin:/usr/sbin:/usr/X11R6/bin:${LOCALBASE}/bin:${LOCALBASE}/sbin 385.Ed 386.Pp 387during execution. 388.Pp 389If 390.Ar command 391contains any of the following sequences somewhere in it, they will 392be expanded inline. 393For the following examples, assume that 394.Cm @cwd 395is set to 396.Pa /usr/local 397and the last extracted file was 398.Pa bin/emacs . 399.Bl -tag -width indent 400.It Cm "\&%B" 401Expands to the 402.Dq basename 403of the fully qualified filename, that 404is the current directory prefix, plus the last filespec, minus 405the trailing filename. 406In the example case, that would be 407.Pa /usr/local/bin . 408.It Cm "\&%D" 409Expands to the current directory prefix, as set with 410.Cm @cwd ; 411in the example case 412.Pa /usr/local . 413.It Cm "\&%F" 414Expands to the last filename extracted (as specified); in the example case, 415.Pa bin/emacs . 416.It Cm "\&%f" 417Expands to the 418.Dq filename 419part of the fully qualified name, or 420the converse of 421.Cm \&%B ; 422in the example case, 423.Pa emacs . 424.El 425.Pp 426.It Cm @exec-always Ar command 427Synonym of 428.Cm @exec . 429.Pp 430.It Cm @exec-add Ar command 431Similar to 432.Cm @exec , 433except it only gets executed during new installations, 434and not during updates. 435.Pp 436.It Cm @exec-update Ar command 437Similar to 438.Cm @exec , 439except it only gets executed during updates, 440and not during new installations. 441.Pp 442.It Cm @extra Ar filename 443Declare extra file 444.Ar filename 445to be deleted at deinstall time, if user sets the 446.Fl c 447option. 448Those files are extra configuration files that are normally not deleted. 449.Ar filename 450can be an absolute path. 451If 452.Ar filename 453ends with a slash, it is a directory. 454.Pp 455.It Cm @extraunexec Ar command 456Extra 457.Ar command 458to execute when removing extra files. 459.Pp 460.It Cm @file Ar filename 461Default annotation, to use if 462.Ar filename 463begins with @. 464.Ar filename 465is always a relative path, relative to the current 466.Cm @cwd . 467.Pp 468.It Cm @fontdir Ar directoryname 469Specialized version of 470.Cm @dir , 471to handle font directories: create 472.Pa font.alias 473from 474.Pa font.alias-* 475fragments, execute 476.Xr mkfontdir 1 , 477.Xr mkfontscale 1 478and 479.Xr fc-cache 1 480when needed. 481Delete extra files at 482.Xr pkg_delete 1 483time. 484.Pp 485.It Cm @group Ar group 486Set default group ownership for all subsequently extracted files to 487.Ar group . 488Use without an arg to set back to default (extraction) 489group ownership. 490.Pp 491.It Cm @info Ar filename 492Specialized version of 493.Cm @file , 494to handle GNU info files. 495Automatically grab 496.Ar filename Ns -* 497chapter files, run 498.Xr install-info 1 499as needed. 500.Pp 501.It Cm @lib Ar filename 502Specialized version of 503.Cm @file , 504to handle shared libraries. 505Satisfy LIB_DEPENDS and WANTLIB, 506run 507.Xr ldconfig 8 508as needed. 509See 510.Sq VARIABLE SUBSTITUTION AND FRAGMENT INCLUSION 511for some details. 512.Pp 513.It Cm @man Ar filename 514Specialized version of 515.Cm @file , 516to handle manual pages. 517.Pp 518.It Cm @mandir Ar directoryname 519Specialized version of 520.Cm @dir , 521to handle manual directories: instruct user to add/remove the 522directory to 523.Xr man.conf 5 , 524remove 525.Xr apropos 1 526database when needed. 527.Pp 528.It Cm @mode Ar mode 529Set default permission for all subsequently extracted files to 530.Ar mode . 531Format is the same as that used by the 532.Xr chmod 1 533command. 534Use without an arg to set back to default (extraction) permissions. 535.Pp 536.It Cm @newgroup Ar name : Ns Ar gid 537During 538.Xr pkg_add 1 , 539create a new group, using 540.Xr groupadd 8 . 541Happens before file and user creations. 542.Ar gid 543can be prefixed with a 544.Sq !\& 545to ensure group has the correct GID. 546During 547.Xr pkg_delete 1 , 548groups will be deleted if extra clean-up has been requested, and if 549other installed packages don't list the same group. 550.Pp 551.It Xo 552.Cm @newuser 553.Sm off 554.Ar name : 555.Ar uid : 556.Ar group : 557.Ar loginclass : 558.Ar comment : 559.Ar home : 560.Ar shell 561.Sm on 562.Xc 563During 564.Xr pkg_add 1 , 565create a new user. 566Happens before any file creation. 567All fields correspond to 568.Xr useradd 8 569parameters. 570Some fields are optional and can be left empty. 571If the user already exists, no action is taken. 572Individual fields can be prefixed by a 573.Sq !\& 574to make sure an existing 575user matches. 576For instance, the directive 577.Li @newuser foo:!42 578will make sure user foo has UID 42. 579During 580.Xr pkg_delete 1 , 581users will be deleted if extra clean-up has been requested, and if 582other installed packages don't list the same user. 583.Pp 584.It Cm @option Ar name 585Effects vary depending on 586.Ar name . 587These are the user settable options 588.Bl -tag -width indent 589.It Ar always-update 590By default, 591.Xr pkg_add 1 592uses some simplified information to decide whether an installed package 593needs updating. 594With this option, the package is updated whenever anything changes. 595To be used sparingly, as this is more expensive. 596.It Ar is-branch 597Annotate the few rare ports where several branches are present in the 598ports tree (such as autoconf), to help 599.Xr pkg_info 1 600produce 601.Ar stem Ns % Ns Ar branch 602annotations when needed. 603.It Ar no-default-conflict 604By default, a package conflicts with other versions of the same package. 605With this option, the older package version will still be noticed, but the 606installation will proceed anyway. 607.El 608.Pp 609.It Cm @owner Ar user 610Set default ownership for all subsequently extracted files to 611.Ar user . 612Use without an arg to set back to default (extraction) 613ownership. 614.Pp 615.It Cm @pkgpath Ar pkgpath 616Declare a secondary 617.Ar pkgpath 618for the package. 619This is used for updates: 620.Nm pkg_add 621.Fl u 622normally checks that the 623.Ar pkgpath 624embedded in the package corresponds to the old package, 625to solve ambiguities when packages with similar names are involved. 626When ports get renamed, or flavors change, extra 627.Cm @pkgpath 628annotations can help 629.Nm pkg_add 630get a sense of continuity. 631Note that these 632.Ar pkgpath 633can take extra optional components, to allow the matching of several 634flavors at once, and are order independent. 635For instance, 636.Bd -literal -offset indent 637@pkgpath some/dir,f1,f2 638.Ed 639.Pp 640and 641.Bd -literal -offset indent 642@pkgpath some/dir,f2,f2,f1 643.Ed 644.Pp 645are equivalent. 646.Bd -literal -offset indent 647@pkgpath some/dir,f1[,f2,f3][,f4] 648.Ed 649.Pp 650will match all pkgpaths to some/dir with flavor f1, and optionally f4, and 651optionally both f2 and f3, e.g., 652.Ar some/dir,f1,f4 , 653.Ar some/dir,f1,f2,f3 , 654.Ar some/dir,f1,f2,f3,f4 , 655.Ar some/dir,f1 656would match, 657but 658.Ar some/dir,f1,f5 , 659.Ar some/dir,f2,f3 , 660.Ar some/dir,f1,f2,f4 661would not. 662.Pp 663Each binary package contains a set of pkgpaths: the primary pkgpath that 664was used to build the package, recorded as 665.Cm @comment Ar pkgpath=some/path , 666and secondary pkgpaths as recorded through 667.Cm @pkgpath . 668.Pp 669In order for two packages to match, their primary pkgpaths must match, or 670a secondary pkgpath must match the other package's primary pkgpath. 671.Pp 672.It Cm @rcscript Ar filename 673Script for the 674.Pa /etc/rc.d 675framework. 676Contrary to 677.Cm @file , 678absolute paths are okay, e.g., 679.Bd -literal -offset indent 680@rcscript ${RCDIR}/ballsd 681.Ed 682.Pp 683In this case, performs an implicit 684.Cm @cwd 685to 686.Pa ${RCDIR} . 687.Pp 688.It Cm @sample Ar filename 689Last preceding 690.Cm @file 691item is a sample configuration file, to be copied to 692.Ar filename 693at 694.Xr pkg_add 1 695time and to be removed at 696.Xr pkg_delete 1 697time. 698During installation, existing configuration files are untouched. 699During deinstallation, configuration files are only removed if unchanged. 700.Ar filename 701can be an absolute path. 702If 703.Ar filename 704ends with a slash, 705it refers to a configuration directory instead. 706.Pp 707.It Cm @shell Ar filename 708Specialized version of 709.Cm @file , 710to handle shells. 711See 712.Xr shells 5 . 713.Pp 714.It Cm @sysctl Ar var Ns = Ns Ar val 715.It Cm @sysctl Ar var Ns \*(Ge Ns Ar val 716During 717.Xr pkg_add 1 , 718check that 719.Xr sysctl 8 720variable 721.Ar var 722is set to exactly/at least a given value 723.Ar val . 724Adjust it otherwise. 725.Pp 726.It Cm @unexec Ar command 727Execute 728.Ar command 729during 730.Xr pkg_delete 1 . 731.Ev PATH 732and expansion of special 733.Cm \&% 734sequences are the same as for 735.Cm @exec . 736Note that 737.Cm @unexec 738commands are executed relative to their location in the packing-list, 739so they cannot rely on any data that has already been deleted, 740thus they should occur before the files they need to function. 741Some special elements, such as new users and new groups, are always 742deleted last, so that 743.Cm @unexec 744can rely on them. 745.Pp 746.It Cm @unexec-always Ar command 747Synonym of 748.Cm @unexec . 749.Pp 750.It Cm @unexec-delete Ar command 751Similar to 752.Cm @unexec , 753except it only gets executed during true deletions 754and not while removing an old package during updates. 755.Pp 756.It Cm @unexec-update Ar command 757Similar to 758.Cm @unexec , 759except it only gets executed while removing an old package during updates, 760and not during true deletions. 761.El 762.Pp 763See 764.Xr package 5 765for other internal annotations that are automatically added by the 766package tools. 767.Sh VARIABLE SUBSTITUTION AND FRAGMENT INCLUSION 768In packing-lists, installation, deinstallation and requirement scripts, 769description and message files, 770constructs like 771.Li ${VAR} 772will be replaced with the variable value, according to 773.Fl D Ar name Ns = Ns Ar value 774options. 775.Pp 776In particular, shared library versions should never be mentioned explicitly 777in a packing-list. 778Shared library 779.Sq foo 780will take its version number from 781.Ev LIBfoo_VERSION . 782The ports framework normally takes care of all details, see 783.Ev SHARED_LIBS 784in 785.Xr bsd.port.mk 5 . 786.Pp 787Constructs like 788.Li %%VAR%% 789and 790.Li !%%VAR%% 791trigger fragment inclusion. 792If such a line is encountered in a packing-list, the corresponding variable 793must be defined to 0 or 1. 794If the variable's value is 1, 795.Li %%VAR%% 796will be replaced by the corresponding positive fragment, and 797.Li !%%VAR%% 798will be ignored. 799If the variable's value is 0, 800.Li %%VAR%% 801will be ignored, and 802.Li !%%VAR%% 803will be replaced by the corresponding positive fragment. 804.Pp 805A fragment is an auxiliary packing-list file, whose name is derived from the 806current packing-list, and the variable name 807.Va VAR 808triggering the inclusion: 809.Pa pkg/PLIST 810yields a positive fragment 811.Pa pkg/PFRAG.VAR 812and a negative fragment 813.Pa pkg/PFRAG.no-VAR , 814.Pa pkg/PLIST-FOO 815yields a positive fragment 816.Pa pkg/PFRAG.VAR-foo 817and a negative fragment 818.Pa pkg/PFRAG.no-VAR-foo . 819.Pp 820Fragments can be included inside fragments, so that 821.Li %%VAR2%% 822inside 823.Pa pkg/PFRAG.VAR 824triggers the inclusion of 825.Pa pkg/PFRAG.VAR2-VAR 826and 827.Li !%%VAR2%% 828triggers the inclusion of 829.Pa pkg/PFRAG.no-VAR2-VAR . 830.Pp 831If a positive or a negative fragment file does not exist, the corresponding 832inclusion will be ignored. 833However, if both the positive and negative fragment files do not exist, 834.Nm 835will error out, to make it easier to spot fragment names errors. 836.Sh ENVIRONMENT 837.Bl -tag -width PKG_DESTDIR 838.It Ev PKG_DESTDIR 839Default value for 840.Ar pkg-destdir , 841if no 842.Fl B 843option is specified. 844.El 845.Sh SEE ALSO 846.Xr pkg_add 1 , 847.Xr pkg_delete 1 , 848.Xr pkg_info 1 , 849.Xr pkg_sign 1 , 850.Xr tar 1 , 851.Xr bsd.port.mk 5 , 852.Xr package 5 , 853.Xr pkg.conf 5 , 854.Xr packages-specs 7 , 855.Xr pkgpath 7 , 856.Xr ports 7 857.Sh HISTORY 858The 859.Nm 860command first appeared in 861.Fx . 862.Sh AUTHORS 863.Bl -tag -width indent -compact 864.It An Jordan Hubbard 865initial design 866.It An Marc Espie 867complete rewrite. 868.El 869