func fetchFile(l *log.Logger, f types.File) ([]byte, error) { switch f.Contents.Source.Scheme { case "http": client := util.NewHttpClient(l) data, status, err := client.Get(f.Contents.Source.String()) if err != nil { return nil, err } l.Debug("GET result: %s", http.StatusText(status)) if status != http.StatusOK { return nil, ErrStatusBad } return data, nil case "data": url, err := dataurl.DecodeString(f.Contents.Source.String()) if err != nil { return nil, err } return url.Data, nil default: return nil, ErrSchemeUnsupported } }
func RenderFile(l *log.Logger, f types.File) *File { var contents []byte var err error fetch := func() error { contents, err = util.FetchResource(l, url.URL(f.Contents.Source)) return err } validate := func() error { return util.AssertValid(f.Contents.Verification, contents) } decompress := func() error { contents, err = decompressFile(l, f, contents) return err } if l.LogOp(fetch, "fetching file %q", f.Path) != nil { return nil } if l.LogOp(validate, "validating file contents") != nil { return nil } if l.LogOp(decompress, "decompressing file contents") != nil { return nil } return &File{ Path: f.Path, Contents: []byte(contents), Mode: os.FileMode(f.Mode), Uid: f.User.Id, Gid: f.Group.Id, } }
// mountOEM waits for the presence of and mounts the oem partition at oemMountPath. func mountOEM(l *log.Logger) error { dev := []string{oemDevicePath} if err := systemd.WaitOnDevices(dev, "oem-cmdline"); err != nil { l.Err("failed to wait for oem device: %v", err) return err } if err := os.MkdirAll(oemMountPath, 0700); err != nil { l.Err("failed to create oem mount point: %v", err) return err } if err := l.LogOp( func() error { return syscall.Mount(dev[0], oemMountPath, "ext4", 0, "") }, "mounting %q at %q", oemDevicePath, oemMountPath, ); err != nil { return fmt.Errorf("failed to mount device %q at %q: %v", oemDevicePath, oemMountPath, err) } return nil }
// FetchResource fetches a resource given a URL. The supported schemes are http, data, and oem. func FetchResource(l *log.Logger, u url.URL) ([]byte, error) { switch u.Scheme { case "http", "https": client := NewHttpClient(l) data, status, err := client.Get(u.String()) if err != nil { return nil, err } l.Debug("GET result: %s", http.StatusText(status)) switch status { case http.StatusOK, http.StatusNoContent: return data, nil case http.StatusNotFound: return nil, ErrNotFound default: return nil, ErrFailed } case "data": url, err := dataurl.DecodeString(u.String()) if err != nil { return nil, err } return url.Data, nil case "oem": path := filepath.Clean(u.Path) if !filepath.IsAbs(path) { l.Err("oem path is not absolute: %q", u.Path) return nil, ErrPathNotAbsolute } // check if present under oemDirPath, if so use it. absPath := filepath.Join(oemDirPath, path) data, err := ioutil.ReadFile(absPath) if os.IsNotExist(err) { l.Info("oem config not found in %q, trying %q", oemDirPath, oemMountPath) // try oemMountPath, requires mounting it. err := mountOEM(l) if err != nil { l.Err("failed to mount oem partition: %v", err) return nil, ErrFailed } absPath := filepath.Join(oemMountPath, path) data, err = ioutil.ReadFile(absPath) umountOEM(l) } else if err != nil { l.Err("failed to read oem config: %v", err) return nil, ErrFailed } return data, nil default: return nil, ErrSchemeUnsupported } }
// umountOEM unmounts the oem partition at oemMountPath. func umountOEM(l *log.Logger) { l.LogOp( func() error { return syscall.Unmount(oemMountPath, 0) }, "unmounting %q", oemMountPath, ) }