Print this page
    
OS-5642 containerbuddy unable to fork while using syslog driver, causing container services to hang
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Patrick Mooney <patrick.mooney@joyent.com>
OS-4818 contract template disappears on exec
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/man/man4/process.4
          +++ new/usr/src/man/man4/process.4
   1    1  '\" te
   2    2  .\" Copyright (c) 2008, Sun Microsystems, Inc. All Rights Reserved.
        3 +.\" Copyright 2016, Joyent, Inc.
   3    4  .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License").  You may not use this file except in compliance with the License.
   4    5  .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.  See the License for the specific language governing permissions and limitations under the License.
   5    6  .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE.  If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
   6      -.TH PROCESS 4 "Mar 25, 2008"
        7 +.TH PROCESS 4 "Sept 6, 2016"
   7    8  .SH NAME
   8    9  process \- process contract type
   9   10  .SH SYNOPSIS
  10   11  .LP
  11   12  .nf
  12   13  \fB/system/contract/process\fR
  13   14  .fi
  14   15  
  15   16  .SH DESCRIPTION
  16   17  .sp
  17   18  .LP
  18   19  Process contracts allow processes to create a fault boundary around a set of
  19   20  subprocesses and observe events which occur within that boundary.
  20   21  .sp
  21   22  .LP
  22   23  Process contracts are managed using the \fBcontract\fR(4) file system and the
  23   24  \fBlibcontract\fR(3LIB) library. The process contract type directory is
  24   25  \fB/system/contract/process\fR.
  25   26  .SS "CREATION"
  26   27  .sp
  27   28  .LP
  28   29  A process contract is created when an LWP that has an active process contract
  29   30  template calls \fBfork\fR(2). Initially, the child process created by
  30   31  \fBfork()\fR is the only resource managed by the contract. When an LWP that
  31   32  does not have an active process contract template calls \fBfork()\fR, the child
  32   33  process created by \fBfork()\fR is added as a resource to the process contract
  33   34  of which the parent was a member.
  34   35  .SS "EVENT TYPES"
  35   36  .sp
  36   37  .LP
  37   38  The following events types are defined:
  38   39  .sp
  39   40  .ne 2
  40   41  .na
  41   42  \fB\fBCT_PR_EV_EMPTY\fR\fR
  42   43  .ad
  43   44  .sp .6
  44   45  .RS 4n
  45   46  The last member of the process contract exited.
  46   47  .RE
  47   48  
  48   49  .sp
  49   50  .ne 2
  50   51  .na
  51   52  \fB\fBCT_PR_EV_FORK\fR\fR
  52   53  .ad
  53   54  .sp .6
  54   55  .RS 4n
  55   56  A new process has been added to the process contract.
  56   57  .RE
  57   58  
  58   59  .sp
  59   60  .ne 2
  60   61  .na
  61   62  \fB\fBCT_PR_EV_EXIT\fR\fR
  62   63  .ad
  63   64  .sp .6
  64   65  .RS 4n
  65   66  A member of the process contract exited.
  66   67  .RE
  67   68  
  68   69  .sp
  69   70  .ne 2
  70   71  .na
  71   72  \fB\fBCT_PR_EV_CORE\fR\fR
  72   73  .ad
  73   74  .sp .6
  74   75  .RS 4n
  75   76  A process failed and dumped core. This could also occur if the process would
  76   77  have dumped core had appropriate \fBcoreadm\fR(1M) options been enabled and
  77   78  core file size was unlimited.
  78   79  .RE
  79   80  
  80   81  .sp
  81   82  .ne 2
  82   83  .na
  83   84  \fB\fBCT_PR_EV_SIGNAL\fR\fR
  84   85  .ad
  85   86  .sp .6
  86   87  .RS 4n
  87   88  A process received a fatal signal from a process, other than the owner of the
  88   89  process contract, that is a member of a different process contract.
  89   90  .RE
  90   91  
  91   92  .sp
  92   93  .ne 2
  93   94  .na
  94   95  \fB\fBCT_PR_EV_HWERR\fR\fR
  95   96  .ad
  96   97  .sp .6
  97   98  .RS 4n
  98   99  A process was killed because of an uncorrectable hardware error.
  99  100  .RE
 100  101  
 101  102  .SS "TERMS"
 102  103  .sp
 103  104  .LP
 104  105  The following common contract terms, defined in \fBcontract\fR(4), have
 105  106  process-contract specific attributes:
 106  107  .sp
 107  108  .ne 2
 108  109  .na
 109  110  \fBcritical event set\fR
 110  111  .ad
 111  112  .sp .6
 112  113  .RS 4n
 113  114  The default value for the critical event set is \fB(CT_PR_EV_EMPTY |
 114  115  CT_PR_EV_HWERR)\fR.
 115  116  .sp
 116  117  An attempt by a user without the \fB{PRIV_CONTRACT_EVENT}\fR privilege in its
 117  118  effective set to add an event, other than \fBCT_PR_EV_EMPTY\fR, to the critical
 118  119  event set which is not present in the fatal set, or if the \fBCT_PR_PGONLY\fR
 119  120  parameter is set and the same user attempts to add any event, other than
 120  121  \fBCT_PR_EV_EMPTY\fR, to the critical event set, fails.
 121  122  .RE
 122  123  
 123  124  .sp
 124  125  .ne 2
 125  126  .na
 126  127  \fBinformative event set\fR
 127  128  .ad
 128  129  .sp .6
 129  130  .RS 4n
 130  131  The default value for the informative event set is \fB(CT_PR_EV_CORE |
 131  132  CT_PR_EV_SIGNAL)\fR.
 132  133  .RE
 133  134  
 134  135  .sp
 135  136  .LP
 136  137  The following contract terms can be read from or written to a process contract
 137  138  template using the named \fBlibcontract\fR(3LIB) interfaces. These contract
 138  139  terms are in addition to those described in \fBcontract\fR(4).
 139  140  .sp
 140  141  .ne 2
 141  142  .na
 142  143  \fBcreator's aux\fR
 143  144  .ad
 144  145  .sp .6
 145  146  .RS 4n
 146  147  Auxiliary contract description. The purpose of this field is to provide the
 147  148  contract creator with a way to differentiate process contracts it creates under
 148  149  the same service FMRI. Use ct_pr_tmpl_set_svc_aux(3CONTRACT) to set this term.
 149  150  The default value is an empty string. The contents of this field should be
 150  151  limited to 7-bit ASCII values.
 151  152  .RE
 152  153  
 153  154  .sp
 154  155  .ne 2
 155  156  .na
 156  157  \fBfatal event set\fR
 157  158  .ad
 158  159  .sp .6
 159  160  .RS 4n
 160  161  Defines a set of events which, when generated, causes all members of the
 161  162  process contract to be killed with \fBSIGKILL\fR, or the intersection of the
 162  163  contract and the containing process group if the \fBCT_PR_PGRPONLY\fR parameter
 163  164  is set. Set this term with \fBct_pr_tmpl_set_fatal\fR(3CONTRACT). The fatal
 164  165  event set is restricted to \fBCT_PR_EV_CORE\fR, \fBCT_PR_EV_SIGNAL\fR, and
 165  166  \fBCT_PR_EV_HWERR\fR. For \fBCT_PR_EV_CORE\fR and \fBCT_PR_EV_SIGNAL\fR events,
 166  167  the scope of \fBSIGKILL\fR is limited to those processes which the contract
 167  168  author or the event source could have normally sent signals to.
 168  169  .sp
 169  170  The default value for the fatal event set is \fBCT_PR_EV_HWERR\fR.
 170  171  .sp
 171  172  If a user without the \fB{PRIV_CONTRACT_EVENT}\fR privilege in its effective
 172  173  set removes an event from the fatal event set which is present in the critical
 173  174  event set, the corresponding event is automatically removed from the critical
 174  175  event set and added to the informative event set.
 175  176  .RE
 176  177  
 177  178  .sp
 178  179  .ne 2
 179  180  .na
 180  181  \fBparameter set\fR
 181  182  .ad
 182  183  .sp .6
 183  184  .RS 4n
 184  185  Defines miscellaneous other settings. Use \fBct_pr_tmpl_set_param\fR(3CONTRACT)
 185  186  to set this term.
 186  187  .sp
 187  188  The default parameter set is empty.
 188  189  .sp
 189  190  The value is a bit vector comprised of some or all of:
 190  191  .sp
 191  192  .ne 2
 192  193  .na
 193  194  \fB\fBCT_PR_INHERIT\fR\fR
 194  195  .ad
  
    | 
      ↓ open down ↓ | 
    178 lines elided | 
    
      ↑ open up ↑ | 
  
 195  196  .sp .6
 196  197  .RS 4n
 197  198  If set, indicates that the process contract is to be inherited by the process
 198  199  contract the contract owner is a member of if the contract owner exits before
 199  200  explicitly abandoning the process contract.
 200  201  .sp
 201  202  If not set, the process contract is automatically abandoned when the owner
 202  203  exits.
 203  204  .RE
 204  205  
      206 +.sp
      207 +.ne 2
      208 +.na
      209 +\fB\fBCT_PR_KEEP_EXEC\fR\fR
      210 +.ad
      211 +.sp .6
      212 +.RS 4n
      213 +If set, the process contract template remains active across \fBexec\fR(2).
      214 +This can be used to setup a contract for children of an application which
      215 +is not contract-aware. If this is not set then the system clears the active
      216 +template when the process execs. Because this option is intended for an
      217 +application which is not contract-aware, new child process contracts will be
      218 +automatically abandoned by the parent.
      219 +.RE
      220 +
 205  221  .sp
 206  222  .ne 2
 207  223  .na
 208  224  \fB\fBCT_PR_NOORPHAN\fR\fR
 209  225  .ad
 210  226  .sp .6
 211  227  .RS 4n
 212  228  If set, all processes in a process contract are sent \fBSIGKILL\fR if the
 213  229  process contract is abandoned, either explicitly or because the holder died and
 214  230  \fBCT_PR_INHERIT\fR was not set. The scope of \fBSIGKILL\fR is limited to those
 215  231  processes which the contract author or the event source could have normally
 216  232  sent signals to.
 217  233  .sp
 218  234  If this is not set and the process contract is abandoned, the process contract
 219  235  is orphaned, that is, continues to exist without owner.
 220  236  .RE
 221  237  
 222  238  .sp
 223  239  .ne 2
 224  240  .na
 225  241  \fB\fBCT_PR_PGRPONLY\fR\fR
 226  242  .ad
 227  243  .sp .6
 228  244  .RS 4n
 229  245  If set, only those processes within the same process group and process contract
 230  246  as a fatal error-generating process are killed.
 231  247  .sp
 232  248  If not set, all processes within the process contract are killed if a member
 233  249  process encounters an error specified in the fatal set.
 234  250  .sp
 235  251  If a user without the \fB{PRIV_CONTRACT_EVENT}\fR privilege in its effective
 236  252  set adds \fBCT_PR_PGRPONLY\fR to a template's parameter set, any events other
 237  253  than \fBCT_PR_EV_EMPTY\fR are automatically removed from the critical event set
 238  254  and added to the informative event set.
 239  255  .RE
 240  256  
 241  257  .sp
 242  258  .ne 2
 243  259  .na
 244  260  \fB\fBCT_PR_REGENT\fR\fR
 245  261  .ad
 246  262  .sp .6
 247  263  .RS 4n
 248  264  If set, the process contract can inherit unabandoned contracts left by exiting
 249  265  member processes.
 250  266  .sp
 251  267  If not set, indicates that the process contract should not inherit contracts
 252  268  from member processes. If a process exits before abandoning a contract it owns
 253  269  and is a member of a process contract which does not have \fBCT_PR_REGENT\fR
 254  270  set, the system automatically abandons the contract.
 255  271  .sp
 256  272  If a regent process contract has inherited contracts and is abandoned by its
 257  273  owner, its inherited contracts are abandoned.
 258  274  .RE
 259  275  
 260  276  .RE
 261  277  
 262  278  .sp
 263  279  .ne 2
 264  280  .na
 265  281  \fBservice FMRI\fR
 266  282  .ad
 267  283  .sp .6
 268  284  .RS 4n
 269  285  Specifies the service FMRI associated with the process contract. Use
 270  286  \fBct_pr_tmpl_set_svc_fmri\fR(3CONTRACT) to set this term. The default is to
 271  287  inherit the value from the creator's process contract. When this term is
 272  288  uninitialized, \fBct_pr_tmpl_get_svc_fmri\fR(3CONTRACT) returns the token
 273  289  string \fBinherited:\fR to indicate the value has not been set and is
 274  290  inherited. Setting the service FMRI to \fBinherited\fR: clears the current
 275  291  (\fBB\fR value and the \fBterm\fR is inherited from the creator's process
 276  292  contract. To set this term a process must have \fB{PRIV_CONTRACT_IDENTITY}\fR
 277  293  in its effective set.
 278  294  .RE
 279  295  
 280  296  .sp
 281  297  .ne 2
 282  298  .na
 283  299  \fBtransfer contract\fR
 284  300  .ad
 285  301  .sp .6
 286  302  .RS 4n
 287  303  Specifies the ID of an empty process contract held by the caller whose
 288  304  inherited process contracts are to be transferred to the newly created
 289  305  contract. Use \fBct_pr_tmpl_set_transfer\fR(3CONTRACT) to set the tranfer
 290  306  contract. Attempts to specify a contract not held by the calling process, or a
 291  307  contract which still has processes in it, fail.
 292  308  .sp
 293  309  The default transfer term is \fB0\fR, that is, no contract.
 294  310  .RE
 295  311  
 296  312  .SS "STATUS"
 297  313  .sp
 298  314  .LP
 299  315  In addition to the standard items, the status object read from a status file
 300  316  descriptor contains the following items to obtain this information
 301  317  respectively:
 302  318  .sp
 303  319  .ne 2
 304  320  .na
 305  321  \fBservice contract ID\fR
 306  322  .ad
 307  323  .sp .6
 308  324  .RS 4n
 309  325  Specifies the process contract id which defined the service FMRI term. Use
 310  326  \fBct_pr_status_get_svc_ctid\fR(3CONTRACT) to read the term's value. It can be
 311  327  used to determine if the service FMRI was inherited as in the example below.
 312  328  .sp
 313  329  .in +2
 314  330  .nf
 315  331  ctid_t ctid;           /* our contract id */
 316  332  int fd;       /* fd of ctid's status file */
 317  333  
 318  334  ct_stathdl_(Bt status;
 319  335  ctid_t svc_ctid;
 320  336  
 321  337  if (ct_status_read(fd, CTD_FIXED, &status) == 0) {
 322  338        if (ct_pr_status_get_svc_ctid(status, &svc_ctid) == 0) {
 323  339              if (svc_ctid == ctid)
 324  340                  /* not inherited */
 325  341              else
 326  342                  /* inherited */
 327  343        }
 328  344        ct_status_free(status);
 329  345  }
 330  346  .fi
 331  347  .in -2
 332  348  .sp
 333  349  
 334  350  .RE
 335  351  
 336  352  .sp
 337  353  .LP
 338  354  If \fBCTD_ALL\fR is specified, the following items are also available:
 339  355  .sp
 340  356  .ne 2
 341  357  .na
 342  358  \fBMember list\fR
 343  359  .ad
 344  360  .sp .6
 345  361  .RS 4n
 346  362  The PIDs of processes which are members of the process contract. Use
 347  363  \fBct_pr_status_get_members\fR(3CONTRACT) for this information.
 348  364  .RE
 349  365  
 350  366  .sp
 351  367  .ne 2
 352  368  .na
 353  369  \fBInherited contract list\fR
 354  370  .ad
 355  371  .sp .6
 356  372  .RS 4n
 357  373  The IDs of contracts which have been inherited by the process contract. Use
 358  374  \fBct_pr_status_get_contracts\fR(3CONTRACT) to obtain this information.
 359  375  .RE
 360  376  
 361  377  .sp
 362  378  .ne 2
 363  379  .na
 364  380  \fBService FMRI (term)\fR
 365  381  .ad
 366  382  .sp .6
 367  383  .RS 4n
 368  384  Values equal to the terms used when the contract was written. The Service FMRI
 369  385  term of the process contract of a process en(\fBBtering\fR a zone has  the
 370  386  value \fBsvc:/system/zone_enter:default\fR when read from the non-global zone.
 371  387  .RE
 372  388  
 373  389  .sp
 374  390  .ne 2
 375  391  .na
 376  392  \fBcontract creator\fR
 377  393  .ad
 378  394  .sp .6
 379  395  .RS 4n
 380  396  Specifies the process that created the process contract. Use
 381  397  \fBct_pr_status_get_svc_creator\fR(3CONTRACT) to read the term's value.
 382  398  .RE
 383  399  
 384  400  .sp
 385  401  .ne 2
 386  402  .na
 387  403  \fBcreator's aux (term)\fR
 388  404  .ad
 389  405  .sp .6
 390  406  .RS 4n
 391  407  Values equal to the terms used when the contract was written.
 392  408  .RE
 393  409  
 394  410  .sp
 395  411  .LP
 396  412  The following standard status items have different meanings in some situations:
 397  413  .sp
 398  414  .ne 2
 399  415  .na
 400  416  \fBOwnership state\fR
 401  417  .ad
 402  418  .sp .6
 403  419  .RS 4n
 404  420  If the process contract has a state of \fBCTS_OWNED\fR or \fBCTS_INHERITED\fR
 405  421  and is held by an entity in the global zone, but contains processes in a
 406  422  non-global zone, it appears to have the state \fBCTS_OWNED\fR when observed by
 407  423  processes in the non-global zone.
 408  424  .RE
 409  425  
 410  426  .sp
 411  427  .ne 2
 412  428  .na
 413  429  \fBContract holder\fR
 414  430  .ad
 415  431  .sp .6
 416  432  .RS 4n
 417  433  If the process contract has a state of \fBCTS_OWNED\fR or \fBCTS_INHERITED\fR
 418  434  and is held by an entity in the global zone, but contains processes in a
 419  435  non-global zone, it appears to be held by the non-global zone's \fBzsched\fR
 420  436  when observed by processes in the non-global zone.
 421  437  .RE
 422  438  
 423  439  .SS "EVENTS"
 424  440  .sp
 425  441  .LP
 426  442  In addition to the standard items, an event generated by a process contract
 427  443  contains the following information:
 428  444  .sp
 429  445  .ne 2
 430  446  .na
 431  447  \fBGenerating PID\fR
 432  448  .ad
 433  449  .sp .6
 434  450  .RS 4n
 435  451  The process ID of the member process which experienced the event, or caused the
 436  452  contract event to be generated (in the case of \fBCT_PR_EV_EMPTY\fR). Use
 437  453  \fBct_pr_event_get_pid\fR(3CONTRACT) to obtain this information.
 438  454  .RE
 439  455  
 440  456  .sp
 441  457  .LP
 442  458  If the event type is \fBCT_PR_EV_FORK\fR, the event contains:
 443  459  .sp
 444  460  .ne 2
 445  461  .na
 446  462  \fBParent PID\fR
 447  463  .ad
 448  464  .sp .6
 449  465  .RS 4n
 450  466  The process ID which forked [Generating PID]. Use
 451  467  \fBct_pr_event_get_ppid\fR(3CONTRACT) to obtain this information.
 452  468  .RE
 453  469  
 454  470  .sp
 455  471  .LP
 456  472  If the event type is \fBCT_PR_EV_EXIT\fR, the event contains:
 457  473  .sp
 458  474  .ne 2
 459  475  .na
 460  476  \fBExit status\fR
 461  477  .ad
 462  478  .sp .6
 463  479  .RS 4n
 464  480  The exit status of the process. Use \fBct_pr_event_get_exitstatus\fR(3CONTRACT)
 465  481  to obtain this information.
 466  482  .RE
 467  483  
 468  484  .sp
 469  485  .LP
 470  486  If the event type is \fBCT_PR_EV_CORE\fR, the event can contain:
 471  487  .sp
 472  488  .ne 2
 473  489  .na
 474  490  \fBProcess core name\fR
 475  491  .ad
 476  492  .sp .6
 477  493  .RS 4n
 478  494  The name of the per-process core file. Use
 479  495  \fBct_pr_event_get_pcorefile\fR(3CONTRACT) to obtain this information.
 480  496  .RE
 481  497  
 482  498  .sp
 483  499  .ne 2
 484  500  .na
 485  501  \fBGlobal core name\fR
 486  502  .ad
 487  503  .sp .6
 488  504  .RS 4n
 489  505  The name of the process's zone's global core file. Use
 490  506  \fBct_pr_event_get_gcorefile\fR(3CONTRACT) to obtain this information.
 491  507  .RE
 492  508  
 493  509  .sp
 494  510  .ne 2
 495  511  .na
 496  512  \fBZone core name\fR
 497  513  .ad
 498  514  .sp .6
 499  515  .RS 4n
 500  516  The name of the system-wide core file in the global zone. Use
 501  517  \fBct_pr_event_get_zcorefile\fR(3CONTRACT) to obtain this information.
 502  518  .RE
 503  519  
 504  520  .sp
 505  521  .LP
 506  522  See \fBcoreadm\fR(1M) for more information about per-process, global, and
 507  523  system-wide core files.
 508  524  .sp
 509  525  .LP
 510  526  If the event type is \fBCT_PR_EV_SIGNAL\fR, the event contains:
 511  527  .sp
 512  528  .ne 2
 513  529  .na
 514  530  \fBSignal\fR
 515  531  .ad
 516  532  .sp .6
 517  533  .RS 4n
 518  534  The number of the signal which killed the process. Use
 519  535  \fBct_pr_event_get_signal\fR(3CONTRACT) to obtain this information.
 520  536  .RE
 521  537  
 522  538  .sp
 523  539  .LP
 524  540  It can contain:
 525  541  .sp
 526  542  .ne 2
 527  543  .na
 528  544  \fBsender\fR
 529  545  .ad
 530  546  .sp .6
 531  547  .RS 4n
 532  548  The PID of the process which sent the signal. Use
 533  549  \fBct_pr_event_get_sender\fR(3CONTRACT) to obtain this information.
 534  550  .RE
 535  551  
 536  552  .SH FILES
 537  553  .sp
 538  554  .ne 2
 539  555  .na
 540  556  \fB\fB/usr/include/sys/contract/process.h\fR\fR
 541  557  .ad
 542  558  .sp .6
 543  559  .RS 4n
 544  560  Contains definitions of event-type macros.
 545  561  .RE
 546  562  
 547  563  .SH SEE ALSO
 548  564  .sp
 549  565  .LP
 550  566  \fBctrun\fR(1), \fBctstat\fR(1), \fBctwatch\fR(1), \fBcoreadm\fR(1M),
 551  567  \fBclose\fR(2), \fBfork\fR(2), \fBioctl\fR(2), \fBopen\fR(2), \fBpoll\fR(2),
 552  568  \fBct_pr_event_get_exitstatus\fR(3CONTRACT),
 553  569  \fBct_pr_event_get_gcorefile\fR(3CONTRACT),
 554  570  \fBct_pr_event_get_pcorefile\fR(3CONTRACT),
 555  571  \fBct_pr_event_get_pid\fR(3CONTRACT), \fBct_pr_event_get_ppid\fR(3CONTRACT),
 556  572  \fBct_pr_event_get_signal\fR(3CONTRACT),
 557  573  \fBct_pr_event_get_zcorefile\fR(3CONTRACT),
 558  574  \fBct_pr_status_get_contracts\fR(3CONTRACT),
 559  575  \fBct_pr_status_get_members\fR(3CONTRACT),
 560  576  \fBct_pr_status_get_param\fR(3CONTRACT), \fBct_pr_tmpl_set_fatal\fR(3CONTRACT),
 561  577  \fBct_pr_tmpl_set_param\fR(3CONTRACT),
 562  578  \fBct_pr_tmpl_set_transfer\fR(3CONTRACT), \fBct_tmpl_set_cookie\fR(3CONTRACT),
 563  579  \fBct_tmpl_set_critical\fR(3CONTRACT),
 564  580  \fBct_tmpl_set_informative\fR(3CONTRACT), \fBlibcontract\fR(3LIB),
 565  581  \fBcontract\fR(4), \fBprivileges\fR(5)
  
    | 
      ↓ open down ↓ | 
    351 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX