@@ -30,7 +30,6 @@ import (
3030 "github.com/docker/docker/libcontainerd"
3131 "github.com/docker/docker/pkg/idtools"
3232 "github.com/docker/docker/pkg/ioutils"
33- "github.com/docker/docker/pkg/promise"
3433 "github.com/docker/docker/pkg/signal"
3534 "github.com/docker/docker/pkg/symlink"
3635 "github.com/docker/docker/restartmanager"
5857 errInvalidNetwork = fmt .Errorf ("invalid network settings while building port map info" )
5958)
6059
61- // DetachError is special error which returned in case of container detach.
62- type DetachError struct {}
63-
64- func (DetachError ) Error () string {
65- return "detached from container"
66- }
67-
6860// CommonContainer holds the fields for a container which are
6961// applicable across all platforms supported by the daemon.
7062type CommonContainer struct {
@@ -366,185 +358,6 @@ func (container *Container) GetExecIDs() []string {
366358 return container .ExecCommands .List ()
367359}
368360
369- // Attach connects to the container's TTY, delegating to standard
370- // streams or websockets depending on the configuration.
371- func (container * Container ) Attach (stdin io.ReadCloser , stdout io.Writer , stderr io.Writer , keys []byte ) chan error {
372- ctx := container .InitAttachContext ()
373- return AttachStreams (ctx , container .StreamConfig , container .Config .OpenStdin , container .Config .StdinOnce , container .Config .Tty , stdin , stdout , stderr , keys )
374- }
375-
376- // AttachStreams connects streams to a TTY.
377- // Used by exec too. Should this move somewhere else?
378- func AttachStreams (ctx context.Context , streamConfig * stream.Config , openStdin , stdinOnce , tty bool , stdin io.ReadCloser , stdout io.Writer , stderr io.Writer , keys []byte ) chan error {
379- var (
380- cStdout , cStderr io.ReadCloser
381- cStdin io.WriteCloser
382- wg sync.WaitGroup
383- errors = make (chan error , 3 )
384- )
385-
386- if stdin != nil && openStdin {
387- cStdin = streamConfig .StdinPipe ()
388- wg .Add (1 )
389- }
390-
391- if stdout != nil {
392- cStdout = streamConfig .StdoutPipe ()
393- wg .Add (1 )
394- }
395-
396- if stderr != nil {
397- cStderr = streamConfig .StderrPipe ()
398- wg .Add (1 )
399- }
400-
401- // Connect stdin of container to the http conn.
402- go func () {
403- if stdin == nil || ! openStdin {
404- return
405- }
406- logrus .Debug ("attach: stdin: begin" )
407-
408- var err error
409- if tty {
410- _ , err = copyEscapable (cStdin , stdin , keys )
411- } else {
412- _ , err = io .Copy (cStdin , stdin )
413- }
414- if err == io .ErrClosedPipe {
415- err = nil
416- }
417- if err != nil {
418- logrus .Errorf ("attach: stdin: %s" , err )
419- errors <- err
420- }
421- if stdinOnce && ! tty {
422- cStdin .Close ()
423- } else {
424- // No matter what, when stdin is closed (io.Copy unblock), close stdout and stderr
425- if cStdout != nil {
426- cStdout .Close ()
427- }
428- if cStderr != nil {
429- cStderr .Close ()
430- }
431- }
432- logrus .Debug ("attach: stdin: end" )
433- wg .Done ()
434- }()
435-
436- attachStream := func (name string , stream io.Writer , streamPipe io.ReadCloser ) {
437- if stream == nil {
438- return
439- }
440-
441- logrus .Debugf ("attach: %s: begin" , name )
442- _ , err := io .Copy (stream , streamPipe )
443- if err == io .ErrClosedPipe {
444- err = nil
445- }
446- if err != nil {
447- logrus .Errorf ("attach: %s: %v" , name , err )
448- errors <- err
449- }
450- // Make sure stdin gets closed
451- if stdin != nil {
452- stdin .Close ()
453- }
454- streamPipe .Close ()
455- logrus .Debugf ("attach: %s: end" , name )
456- wg .Done ()
457- }
458-
459- go attachStream ("stdout" , stdout , cStdout )
460- go attachStream ("stderr" , stderr , cStderr )
461-
462- return promise .Go (func () error {
463- done := make (chan struct {})
464- go func () {
465- wg .Wait ()
466- close (done )
467- }()
468- select {
469- case <- done :
470- case <- ctx .Done ():
471- // close all pipes
472- if cStdin != nil {
473- cStdin .Close ()
474- }
475- if cStdout != nil {
476- cStdout .Close ()
477- }
478- if cStderr != nil {
479- cStderr .Close ()
480- }
481- <- done
482- }
483- close (errors )
484- for err := range errors {
485- if err != nil {
486- return err
487- }
488- }
489- return nil
490- })
491- }
492-
493- // Code c/c from io.Copy() modified to handle escape sequence
494- func copyEscapable (dst io.Writer , src io.ReadCloser , keys []byte ) (written int64 , err error ) {
495- if len (keys ) == 0 {
496- // Default keys : ctrl-p ctrl-q
497- keys = []byte {16 , 17 }
498- }
499- buf := make ([]byte , 32 * 1024 )
500- for {
501- nr , er := src .Read (buf )
502- if nr > 0 {
503- // ---- Docker addition
504- preservBuf := []byte {}
505- for i , key := range keys {
506- preservBuf = append (preservBuf , buf [0 :nr ]... )
507- if nr != 1 || buf [0 ] != key {
508- break
509- }
510- if i == len (keys )- 1 {
511- src .Close ()
512- return 0 , DetachError {}
513- }
514- nr , er = src .Read (buf )
515- }
516- var nw int
517- var ew error
518- if len (preservBuf ) > 0 {
519- nw , ew = dst .Write (preservBuf )
520- nr = len (preservBuf )
521- } else {
522- // ---- End of docker
523- nw , ew = dst .Write (buf [0 :nr ])
524- }
525- if nw > 0 {
526- written += int64 (nw )
527- }
528- if ew != nil {
529- err = ew
530- break
531- }
532- if nr != nw {
533- err = io .ErrShortWrite
534- break
535- }
536- }
537- if er == io .EOF {
538- break
539- }
540- if er != nil {
541- err = er
542- break
543- }
544- }
545- return written , err
546- }
547-
548361// ShouldRestart decides whether the daemon should restart the container or not.
549362// This is based on the container's restart policy.
550363func (container * Container ) ShouldRestart () bool {
0 commit comments