github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/cmd/snap-bootstrap/cmd_recovery_chooser_trigger.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2020 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package main 21 22 import ( 23 "fmt" 24 "os" 25 "time" 26 27 "github.com/jessevdk/go-flags" 28 29 "github.com/snapcore/snapd/cmd/snap-bootstrap/triggerwatch" 30 "github.com/snapcore/snapd/logger" 31 ) 32 33 func init() { 34 const ( 35 short = "Detect Ubuntu Core recovery chooser trigger" 36 long = "" 37 ) 38 39 addCommandBuilder(func(parser *flags.Parser) { 40 if _, err := parser.AddCommand("recovery-chooser-trigger", short, long, &cmdRecoveryChooserTrigger{}); err != nil { 41 panic(err) 42 } 43 }) 44 } 45 46 var ( 47 triggerwatchWait = triggerwatch.Wait 48 49 // default trigger wait timeout 50 defaultTimeout = 10 * time.Second 51 52 // default marker file location 53 defaultMarkerFile = "/run/snapd-recovery-chooser-triggered" 54 ) 55 56 type cmdRecoveryChooserTrigger struct { 57 MarkerFile string `long:"marker-file" value-name:"filename" description:"trigger marker file location"` 58 WaitTimeout string `long:"wait-timeout" value-name:"duration" description:"trigger wait timeout"` 59 } 60 61 func (c *cmdRecoveryChooserTrigger) Execute(args []string) error { 62 // TODO:UC20: check in the gadget if there is a hook or some binary we 63 // should run for trigger detection. This will require some design work 64 // and also thinking if/how such a hook can be confined. 65 66 timeout := defaultTimeout 67 markerFile := defaultMarkerFile 68 69 if c.WaitTimeout != "" { 70 userTimeout, err := time.ParseDuration(c.WaitTimeout) 71 if err != nil { 72 logger.Noticef("cannot parse duration %q, using default", c.WaitTimeout) 73 } else { 74 timeout = userTimeout 75 } 76 } 77 if c.MarkerFile != "" { 78 markerFile = c.MarkerFile 79 } 80 logger.Noticef("trigger wait timeout %v", timeout) 81 logger.Noticef("marker file %v", markerFile) 82 83 _, err := os.Stat(markerFile) 84 if err == nil { 85 logger.Noticef("marker already present") 86 return nil 87 } 88 89 err = triggerwatchWait(timeout) 90 if err != nil { 91 switch err { 92 case triggerwatch.ErrTriggerNotDetected: 93 logger.Noticef("trigger not detected") 94 return nil 95 case triggerwatch.ErrNoMatchingInputDevices: 96 logger.Noticef("no matching input devices") 97 return nil 98 default: 99 return err 100 } 101 } 102 103 // got the trigger, try to create the marker file 104 m, err := os.Create(markerFile) 105 if err != nil { 106 return fmt.Errorf("cannot create the marker file: %q", err) 107 } 108 m.Close() 109 110 return nil 111 }