github.com/bugraaydogar/snapd@v0.0.0-20210315170335-8c70bb858939/cmd/snapd/main.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2015-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 "os/signal" 26 "syscall" 27 "time" 28 29 "github.com/snapcore/snapd/daemon" 30 "github.com/snapcore/snapd/errtracker" 31 "github.com/snapcore/snapd/logger" 32 "github.com/snapcore/snapd/osutil" 33 "github.com/snapcore/snapd/sandbox" 34 "github.com/snapcore/snapd/sanity" 35 "github.com/snapcore/snapd/snapdenv" 36 "github.com/snapcore/snapd/snapdtool" 37 "github.com/snapcore/snapd/systemd" 38 ) 39 40 var ( 41 sanityCheck = sanity.Check 42 ) 43 44 func init() { 45 err := logger.SimpleSetup() 46 if err != nil { 47 fmt.Fprintf(os.Stderr, "WARNING: failed to activate logging: %s\n", err) 48 } 49 // set here to avoid accidental submits in e.g. unit tests 50 errtracker.CrashDbURLBase = "https://daisy.ubuntu.com/" 51 errtracker.SnapdVersion = snapdtool.Version 52 } 53 54 func main() { 55 // When preseeding re-exec is not used 56 if snapdenv.Preseeding() { 57 logger.Noticef("running for preseeding") 58 } else { 59 snapdtool.ExecInSnapdOrCoreSnap() 60 } 61 62 ch := make(chan os.Signal, 2) 63 signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM) 64 if err := run(ch); err != nil { 65 if err == daemon.ErrRestartSocket { 66 // Note that we don't prepend: "error: " here because 67 // ErrRestartSocket is not an error as such. 68 fmt.Fprintf(os.Stdout, "%v\n", err) 69 // the exit code must be in sync with 70 // data/systemd/snapd.service.in:SuccessExitStatus= 71 os.Exit(42) 72 } 73 fmt.Fprintf(os.Stderr, "cannot run daemon: %v\n", err) 74 os.Exit(1) 75 } 76 } 77 78 func runWatchdog(d *daemon.Daemon) (*time.Ticker, error) { 79 // not running under systemd 80 if os.Getenv("WATCHDOG_USEC") == "" { 81 return nil, nil 82 } 83 usec := osutil.GetenvInt64("WATCHDOG_USEC") 84 if usec == 0 { 85 return nil, fmt.Errorf("cannot parse WATCHDOG_USEC: %q", os.Getenv("WATCHDOG_USEC")) 86 } 87 dur := time.Duration(usec/2) * time.Microsecond 88 logger.Debugf("Setting up sd_notify() watchdog timer every %s", dur) 89 wt := time.NewTicker(dur) 90 91 go func() { 92 for { 93 select { 94 case <-wt.C: 95 // TODO: poke the snapd API here and 96 // only report WATCHDOG=1 if it 97 // replies with valid data 98 systemd.SdNotify("WATCHDOG=1") 99 case <-d.Dying(): 100 return 101 } 102 } 103 }() 104 105 return wt, nil 106 } 107 108 var checkRunningConditionsRetryDelay = 300 * time.Second 109 110 func run(ch chan os.Signal) error { 111 t0 := time.Now().Truncate(time.Millisecond) 112 snapdenv.SetUserAgentFromVersion(snapdtool.Version, sandbox.ForceDevMode) 113 114 d, err := daemon.New() 115 if err != nil { 116 return err 117 } 118 if err := d.Init(); err != nil { 119 return err 120 } 121 122 // Run sanity check now, if anything goes wrong with the 123 // check we go into "degraded" mode where we always report 124 // the given error to any snap client. 125 var checkTicker <-chan time.Time 126 var tic *time.Ticker 127 if err := sanityCheck(); err != nil { 128 degradedErr := fmt.Errorf("system does not fully support snapd: %s", err) 129 logger.Noticef("%s", degradedErr) 130 d.SetDegradedMode(degradedErr) 131 tic = time.NewTicker(checkRunningConditionsRetryDelay) 132 checkTicker = tic.C 133 } 134 135 d.Version = snapdtool.Version 136 137 if err := d.Start(); err != nil { 138 return err 139 } 140 141 watchdog, err := runWatchdog(d) 142 if err != nil { 143 return fmt.Errorf("cannot run software watchdog: %v", err) 144 } 145 if watchdog != nil { 146 defer watchdog.Stop() 147 } 148 149 logger.Debugf("activation done in %v", time.Now().Truncate(time.Millisecond).Sub(t0)) 150 151 out: 152 for { 153 select { 154 case sig := <-ch: 155 logger.Noticef("Exiting on %s signal.\n", sig) 156 break out 157 case <-d.Dying(): 158 // something called Stop() 159 break out 160 case <-checkTicker: 161 if err := sanityCheck(); err == nil { 162 d.SetDegradedMode(nil) 163 tic.Stop() 164 } 165 } 166 } 167 168 return d.Stop(ch) 169 }