func getManifestData(dataType, manifestFile string) string { // This is where Yocto stores buid information manifest, err := os.Open(manifestFile) if err != nil { log.Error("Can not read manifest data.") return "" } scanner := bufio.NewScanner(manifest) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) log.Debug("Read data from device manifest file: ", line) if strings.HasPrefix(line, dataType) { log.Debug("Found needed line: ", line) lineID := strings.Split(line, "=") if len(lineID) != 2 { log.Errorf("Broken device manifest file: (%v)", lineID) return "" } log.Debug("Current manifest data: ", strings.TrimSpace(lineID[1])) return strings.TrimSpace(lineID[1]) } } if err := scanner.Err(); err != nil { log.Error(err) } return "" }
// Returns a byte stream which is a download of the given link. func (u *UpdateClient) FetchUpdate(api ApiRequester, url string) (io.ReadCloser, int64, error) { req, err := makeUpdateFetchRequest(url) if err != nil { return nil, -1, errors.Wrapf(err, "failed to create update fetch request") } r, err := api.Do(req) if err != nil { log.Error("Can not fetch update image: ", err) return nil, -1, errors.Wrapf(err, "update fetch request failed") } log.Debugf("Received fetch update response %v+", r) if r.StatusCode != http.StatusOK { r.Body.Close() log.Errorf("Error fetching shcheduled update info: code (%d)", r.StatusCode) return nil, -1, errors.New("Error receiving scheduled update information.") } if r.ContentLength < 0 { r.Body.Close() return nil, -1, errors.New("Will not continue with unknown image size.") } else if r.ContentLength < u.minImageSize { r.Body.Close() log.Errorf("Image smaller than expected. Expected: %d, received: %d", u.minImageSize, r.ContentLength) return nil, -1, errors.New("Image size is smaller than expected. Aborting.") } return r.Body, r.ContentLength, nil }
func getBootEnvActivePartition(env BootEnvReadWriter) (string, error) { bootEnv, err := env.ReadEnv("mender_boot_part") if err != nil { log.Error(err) return "", ErrorNoMatchBootPartRootPart } return bootEnv["mender_boot_part"], nil }
func getRootDevice(sc StatCommander) *syscall.Stat_t { rootStat, err := sc.Stat("/") if err != nil { // Seriously?? // Something is *very* wrong. log.Error("Can not stat root device.") return nil } return rootStat.Sys().(*syscall.Stat_t) }
func (e *uBootEnv) WriteEnv(vars BootVars) error { //TODO: try to make this atomic later for k, v := range vars { setEnvCmd := e.Command("fw_setenv", k, v) if _, err := getOrSetEnvironmentVariable(setEnvCmd); err != nil { log.Error("Error setting U-Boot variable: ", err) return err } } return nil }
func (m *mender) UploadLog(update client.UpdateResponse, logs []byte) menderError { s := client.NewLog() err := s.Upload(m.api.Request(m.authToken), m.config.ServerURL, client.LogData{ DeploymentID: update.ID, Messages: logs, }) if err != nil { log.Error("error uploading logs: ", err) return NewTransientError(err) } return nil }
func (m *mender) ReportUpdateStatus(update client.UpdateResponse, status string) menderError { s := client.NewStatus() err := s.Report(m.api.Request(m.authToken), m.config.ServerURL, client.StatusReport{ DeploymentID: update.ID, Status: status, }) if err != nil { log.Error("error reporting update status: ", err) return NewTransientError(err) } return nil }
func (p *partitions) getAndCacheActivePartition(rootChecker func(StatCommander, string, *syscall.Stat_t) bool, getMountedDevices func(string) ([]string, error)) (string, error) { mountData, err := p.Command("mount").Output() if err != nil { return "", err } mountCandidate := getRootCandidateFromMount(mountData) rootDevice := getRootDevice(p) if rootDevice == nil { return "", errors.New("Can not find root device") } // First check if mountCandidate matches rootDevice if mountCandidate != "" { if rootChecker(p, mountCandidate, rootDevice) { p.active = mountCandidate log.Debugf("Setting active partition from mount candidate: %s", p.active) return p.active, nil } // If not see if we are lucky somewhere else } const devDir string = "/dev" mountedDevices, err := getMountedDevices(devDir) if err != nil { return "", err } activePartition, err := getRootFromMountedDevices(p, rootChecker, mountedDevices, rootDevice) if err != nil { return "", err } bootEnvBootPart, err := getBootEnvActivePartition(p.BootEnvReadWriter) if err != nil { return "", err } if checkBootEnvAndRootPartitionMatch(bootEnvBootPart, activePartition) { p.active = activePartition log.Debug("Setting active partition: ", activePartition) return p.active, nil } log.Error("Mounted root '" + activePartition + "' does not match boot environment mender_boot_part: " + bootEnvBootPart) return "", ErrorNoMatchBootPartRootPart }
func getOrSetEnvironmentVariable(cmd *exec.Cmd) (BootVars, error) { cmdReader, err := cmd.StdoutPipe() if err != nil { log.Errorln("Error creating StdoutPipe: ", err) return nil, err } scanner := bufio.NewScanner(cmdReader) err = cmd.Start() if err != nil { return nil, err } var env_variables = make(BootVars) for scanner.Scan() { log.Debug("Have U-Boot variable: ", scanner.Text()) splited_line := strings.Split(scanner.Text(), "=") //we are having empty line (usually at the end of output) if scanner.Text() == "" { continue } //we have some malformed data or Warning/Error if len(splited_line) != 2 { log.Error("U-Boot variable malformed or error occured") return nil, errors.New("Invalid U-Boot variable or error: " + scanner.Text()) } env_variables[splited_line[0]] = splited_line[1] } err = cmd.Wait() if err != nil { return nil, err } if len(env_variables) > 0 { log.Debug("List of U-Boot variables:", env_variables) } return env_variables, err }
// Report status information to the backend func (i *InventoryClient) Submit(api ApiRequester, url string, data interface{}) error { req, err := makeInventorySubmitRequest(url, data) if err != nil { return errors.Wrapf(err, "failed to prepare inventory submit request") } r, err := api.Do(req) if err != nil { log.Error("failed to submit inventory data: ", err) return errors.Wrapf(err, "inventory submit failed") } defer r.Body.Close() if r.StatusCode != http.StatusOK { log.Errorf("got unexpected HTTP status when submitting to inventory: %v", r.StatusCode) return errors.Errorf("inventory submit failed, bad status %v", r.StatusCode) } log.Debugf("inventory update sent, response %v", r) return nil }
// Report status information to the backend func (u *StatusClient) Report(api ApiRequester, url string, report StatusReport) error { req, err := makeStatusReportRequest(url, report) if err != nil { return errors.Wrapf(err, "failed to prepare status report request") } r, err := api.Do(req) if err != nil { log.Error("failed to report status: ", err) return errors.Wrapf(err, "reporting status failed") } defer r.Body.Close() // HTTP 204 No Content if r.StatusCode != http.StatusNoContent { log.Errorf("got unexpected HTTP status when reporting status: %v", r.StatusCode) return errors.Errorf("reporting status failed, bad status %v", r.StatusCode) } log.Debugf("status reported, response %v", r) return nil }
// Report status information to the backend func (u *LogUploadClient) Upload(api ApiRequester, url string, logs LogData) error { req, err := makeLogUploadRequest(url, &logs) if err != nil { return errors.Wrapf(err, "failed to prepare log upload request") } r, err := api.Do(req) if err != nil { log.Error("failed to upload logs: ", err) return errors.Wrapf(err, "uploading logs failed") } defer r.Body.Close() // HTTP 204 No Content if r.StatusCode != http.StatusNoContent { log.Errorf("got unexpected HTTP status when uploading log: %v", r.StatusCode) return errors.Errorf("uploading logs failed, bad status %v", r.StatusCode) } log.Debugf("logs uploaded, response %v", r) return nil }
// Check if new update is available. In case of errors, returns nil and error // that occurred. If no update is available *UpdateResponse is nil, otherwise it // contains update information. func (m *mender) CheckUpdate() (*client.UpdateResponse, menderError) { currentImageID := m.GetCurrentImageID() //TODO: if currentImageID == "" { // return errors.New("") // } haveUpdate, err := m.updater.GetScheduledUpdate(m.api.Request(m.authToken), m.config.ServerURL) if err != nil { // remove authentication token if device is not authorized if err == client.ErrNotAuthorized { if remErr := m.authMgr.RemoveAuthToken(); remErr != nil { log.Warn("can not remove rejected authentication token") } } log.Error("Error receiving scheduled update data: ", err) return nil, NewTransientError(err) } if haveUpdate == nil { log.Debug("no updates available") return nil, nil } update, ok := haveUpdate.(client.UpdateResponse) if !ok { return nil, NewTransientError(errors.Errorf("not an update response?")) } log.Debugf("received update response: %v", update) if update.Image.YoctoID == currentImageID { log.Info("Attempting to upgrade to currently installed image ID, not performing upgrade.") return &update, NewTransientError(os.ErrExist) } return &update, nil }