package zfs import ( "context" "fmt" ) type DatasetFilter interface { Filter(p *DatasetPath) (pass bool, err error) } // Returns a DatasetFilter that does not filter (passes all paths) func NoFilter() DatasetFilter { return noFilter{} } type noFilter struct{} var _ DatasetFilter = noFilter{} func (noFilter) Filter(p *DatasetPath) (pass bool, err error) { return true, nil } func ZFSListMapping(ctx context.Context, filter DatasetFilter) (datasets []*DatasetPath, err error) { res, err := ZFSListMappingProperties(ctx, filter, nil) if err != nil { return nil, err } datasets = make([]*DatasetPath, len(res)) for i, r := range res { datasets[i] = r.Path } return datasets, nil } type ZFSListMappingPropertiesResult struct { Path *DatasetPath // Guaranteed to have the same length as properties in the originating call Fields []string } // properties must not contain 'name' func ZFSListMappingProperties(ctx context.Context, filter DatasetFilter, properties []string) (datasets []ZFSListMappingPropertiesResult, err error) { if filter == nil { panic("filter must not be nil") } for _, p := range properties { if p == "name" { panic("properties must not contain 'name'") } } newProps := make([]string, len(properties)+1) newProps[0] = "name" copy(newProps[1:], properties) properties = newProps ctx, cancel := context.WithCancel(ctx) defer cancel() rchan := make(chan ZFSListResult) go ZFSListChan(ctx, rchan, properties, "-r", "-t", "filesystem,volume") datasets = make([]ZFSListMappingPropertiesResult, 0) for r := range rchan { if r.Err != nil { err = r.Err return } var path *DatasetPath if path, err = NewDatasetPath(r.Fields[0]); err != nil { return } pass, filterErr := filter.Filter(path) if filterErr != nil { return nil, fmt.Errorf("error calling filter: %s", filterErr) } if pass { datasets = append(datasets, ZFSListMappingPropertiesResult{ Path: path, Fields: r.Fields[1:], }) } } return }