errors/
lib.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use ::routing::error::{ComponentInstanceError, RoutingError};
6use ::routing::policy::PolicyError;
7use ::routing::resolving::ResolverError;
8use anyhow::Error;
9use clonable_error::ClonableError;
10use cm_config::CompatibilityCheckError;
11use cm_rust::UseDecl;
12use cm_types::{Name, Url};
13use component_id_index::InstanceId;
14use fuchsia_fs::directory::WatcherCreateError;
15use moniker::{ChildName, ExtendedMoniker, Moniker, MonikerError};
16use router_error::{Explain, RouterError};
17use sandbox::ConversionError;
18use serve_processargs::BuildNamespaceError;
19use std::sync::Arc;
20use thiserror::Error;
21use {fidl_fuchsia_component as fcomponent, fidl_fuchsia_sys2 as fsys};
22
23/// Errors produced by `Model`.
24#[derive(Debug, Error, Clone)]
25pub enum ModelError {
26    #[error("bad path")]
27    BadPath,
28    #[error(transparent)]
29    MonikerError {
30        #[from]
31        err: MonikerError,
32    },
33    #[error("expected a component instance moniker")]
34    UnexpectedComponentManagerMoniker,
35    #[error(transparent)]
36    RoutingError {
37        #[from]
38        err: RoutingError,
39    },
40    #[error(
41        "opening path `{path}`, in storage directory for `{moniker}` backed by `{source_moniker}`: {err}"
42    )]
43    OpenStorageFailed {
44        source_moniker: ExtendedMoniker,
45        moniker: Moniker,
46        path: String,
47        #[source]
48        err: zx::Status,
49    },
50    #[error(transparent)]
51    StorageError {
52        #[from]
53        err: StorageError,
54    },
55    #[error(transparent)]
56    ComponentInstanceError {
57        #[from]
58        err: ComponentInstanceError,
59    },
60    #[error("service dir VFS for component {moniker}:\n\t{err}")]
61    ServiceDirError {
62        moniker: Moniker,
63
64        #[source]
65        err: VfsError,
66    },
67    #[error("opening directory `{relative_path}` for component `{moniker}` failed")]
68    OpenDirectoryError { moniker: Moniker, relative_path: String },
69    #[error("events: {err}")]
70    EventsError {
71        #[from]
72        err: EventsError,
73    },
74    #[error(transparent)]
75    PolicyError {
76        #[from]
77        err: PolicyError,
78    },
79    #[error("component id index: {err}")]
80    ComponentIdIndexError {
81        #[from]
82        err: component_id_index::IndexError,
83    },
84    #[error(transparent)]
85    ActionError {
86        #[from]
87        err: ActionError,
88    },
89    #[error("resolve: {err}")]
90    ResolveActionError {
91        #[from]
92        err: ResolveActionError,
93    },
94    #[error("start: {err}")]
95    StartActionError {
96        #[from]
97        err: StartActionError,
98    },
99    #[error("open outgoing dir: {err}")]
100    OpenOutgoingDirError {
101        #[from]
102        err: OpenOutgoingDirError,
103    },
104    #[error("router: {err}")]
105    RouterError {
106        #[from]
107        err: RouterError,
108    },
109    #[error("capability provider: {err}")]
110    CapabilityProviderError {
111        #[from]
112        err: CapabilityProviderError,
113    },
114    #[error("open: {err}")]
115    OpenError {
116        #[from]
117        err: OpenError,
118    },
119}
120
121impl ModelError {
122    pub fn instance_not_found(moniker: Moniker) -> ModelError {
123        ModelError::from(ComponentInstanceError::instance_not_found(moniker))
124    }
125
126    pub fn open_directory_error(moniker: Moniker, relative_path: impl Into<String>) -> ModelError {
127        ModelError::OpenDirectoryError { moniker, relative_path: relative_path.into() }
128    }
129}
130
131impl ModelError {
132    fn as_zx_status(&self) -> zx::Status {
133        match self {
134            ModelError::RoutingError { err } => err.as_zx_status(),
135            ModelError::PolicyError { err } => err.as_zx_status(),
136            ModelError::StartActionError { err } => err.as_zx_status(),
137            ModelError::ComponentInstanceError { err } => err.as_zx_status(),
138            ModelError::OpenOutgoingDirError { err } => err.as_zx_status(),
139            ModelError::RouterError { err } => err.as_zx_status(),
140            ModelError::CapabilityProviderError { err } => err.as_zx_status(),
141            // Any other type of error is not expected.
142            _ => zx::Status::INTERNAL,
143        }
144    }
145}
146
147#[derive(Debug, Error, Clone)]
148pub enum StructuredConfigError {
149    #[error("component has a config schema but resolver did not provide values")]
150    ConfigValuesMissing,
151    #[error("failed to resolve component's config:\n\t{_0}")]
152    ConfigResolutionFailed(#[source] config_encoder::ResolutionError),
153    #[error("couldn't create vmo: {_0}")]
154    VmoCreateFailed(#[source] zx::Status),
155    #[error("failed to match values for key `{key}`")]
156    ValueMismatch { key: String },
157    #[error("failed to find values for key `{key}`")]
158    KeyNotFound { key: String },
159    #[error("failed to route structured config values:\n\t{_0}")]
160    RoutingError(#[from] router_error::RouterError),
161}
162
163#[derive(Clone, Debug, Error)]
164pub enum VfsError {
165    #[error("failed to add node `{name}`: {status}")]
166    AddNodeError { name: String, status: zx::Status },
167    #[error("failed to remove node `{name}`: {status}")]
168    RemoveNodeError { name: String, status: zx::Status },
169}
170
171#[derive(Debug, Error)]
172pub enum RebootError {
173    #[error("failed to connect to admin protocol in root component's exposed dir:\n\t{0}")]
174    ConnectToAdminFailed(#[source] anyhow::Error),
175    #[error("StateControl Admin FIDL:\n\t{0}")]
176    FidlError(#[from] fidl::Error),
177    #[error("StateControl Admin: {0}")]
178    AdminError(zx::Status),
179    #[error("opening root component's exposed dir: {0}")]
180    OpenRootExposedDirFailed(#[from] OpenExposedDirError),
181}
182
183#[derive(Debug, Error)]
184pub enum OpenExposedDirError {
185    #[error("instance is not resolved")]
186    InstanceNotResolved,
187    #[error("instance was destroyed")]
188    InstanceDestroyed,
189    #[error("open error: {0}")]
190    Open(#[from] zx::Status),
191}
192
193impl Explain for OpenExposedDirError {
194    fn as_zx_status(&self) -> zx::Status {
195        match self {
196            Self::InstanceNotResolved => zx::Status::NOT_FOUND,
197            Self::InstanceDestroyed => zx::Status::NOT_FOUND,
198            Self::Open(status) => *status,
199        }
200    }
201}
202
203impl From<OpenExposedDirError> for fsys::OpenError {
204    fn from(value: OpenExposedDirError) -> Self {
205        match value {
206            OpenExposedDirError::InstanceNotResolved => fsys::OpenError::InstanceNotResolved,
207            OpenExposedDirError::InstanceDestroyed => fsys::OpenError::InstanceDestroyed,
208            OpenExposedDirError::Open(_) => fsys::OpenError::FidlError,
209        }
210    }
211}
212
213#[derive(Clone, Debug, Error)]
214pub enum OpenOutgoingDirError {
215    #[error("instance is not resolved")]
216    InstanceNotResolved,
217    #[error("instance is non-executable")]
218    InstanceNonExecutable,
219    #[error("failed to open: {0}")]
220    Open(#[from] zx::Status),
221    #[error("fidl IPC to protocol in outgoing directory:\n\t{0}")]
222    Fidl(fidl::Error),
223}
224
225impl Explain for OpenOutgoingDirError {
226    fn as_zx_status(&self) -> zx::Status {
227        match self {
228            Self::InstanceNotResolved => zx::Status::NOT_FOUND,
229            Self::InstanceNonExecutable => zx::Status::NOT_FOUND,
230            Self::Open(err) => *err,
231            Self::Fidl(_) => zx::Status::NOT_FOUND,
232        }
233    }
234}
235
236impl From<OpenOutgoingDirError> for fsys::OpenError {
237    fn from(value: OpenOutgoingDirError) -> Self {
238        match value {
239            OpenOutgoingDirError::InstanceNotResolved => fsys::OpenError::InstanceNotResolved,
240            OpenOutgoingDirError::InstanceNonExecutable => fsys::OpenError::NoSuchDir,
241            OpenOutgoingDirError::Open(_) => fsys::OpenError::FidlError,
242            OpenOutgoingDirError::Fidl(_) => fsys::OpenError::FidlError,
243        }
244    }
245}
246
247impl From<OpenOutgoingDirError> for RouterError {
248    fn from(value: OpenOutgoingDirError) -> Self {
249        Self::NotFound(Arc::new(value))
250    }
251}
252
253#[derive(Debug, Error, Clone)]
254pub enum AddDynamicChildError {
255    #[error("component collection not found with name `{name}`")]
256    CollectionNotFound { name: String },
257    #[error(
258        "numbered handles can only be provided when adding components to a single-run collection"
259    )]
260    NumberedHandleNotInSingleRunCollection,
261    #[error("name length is longer than the allowed max of {max_len}")]
262    NameTooLong { max_len: usize },
263    #[error("collection `{collection_name}` does not allow dynamic offers")]
264    DynamicOffersNotAllowed { collection_name: String },
265    #[error(transparent)]
266    ActionError {
267        #[from]
268        err: ActionError,
269    },
270    #[error("invalid dictionary")]
271    InvalidDictionary,
272    #[error(
273        "dictionary entry for capability `{capability_name}` conflicts with existing static route"
274    )]
275    StaticRouteConflict { capability_name: Name },
276    #[error(transparent)]
277    AddChildError {
278        #[from]
279        err: AddChildError,
280    },
281}
282
283// This is implemented for fuchsia.component.Realm protocol
284impl Into<fcomponent::Error> for AddDynamicChildError {
285    fn into(self) -> fcomponent::Error {
286        match self {
287            AddDynamicChildError::CollectionNotFound { .. } => {
288                fcomponent::Error::CollectionNotFound
289            }
290            AddDynamicChildError::NumberedHandleNotInSingleRunCollection => {
291                fcomponent::Error::Unsupported
292            }
293            AddDynamicChildError::AddChildError {
294                err: AddChildError::InstanceAlreadyExists { .. },
295            } => fcomponent::Error::InstanceAlreadyExists,
296            AddDynamicChildError::DynamicOffersNotAllowed { .. } => {
297                fcomponent::Error::InvalidArguments
298            }
299            AddDynamicChildError::ActionError { err } => err.into(),
300            AddDynamicChildError::InvalidDictionary { .. } => fcomponent::Error::InvalidArguments,
301            AddDynamicChildError::StaticRouteConflict { .. } => fcomponent::Error::InvalidArguments,
302            AddDynamicChildError::NameTooLong { .. } => fcomponent::Error::InvalidArguments,
303            // TODO(https://fxbug.dev/297403341): This should become its own error in fidl once
304            // we can introduce it without breaking compatibility.
305            AddDynamicChildError::AddChildError {
306                err:
307                    AddChildError::DynamicCapabilityError { err: DynamicCapabilityError::Cycle { .. } },
308            } => fcomponent::Error::DependencyCycle,
309            AddDynamicChildError::AddChildError {
310                err: AddChildError::DynamicCapabilityError { .. },
311            } => fcomponent::Error::InvalidArguments,
312            AddDynamicChildError::AddChildError { err: AddChildError::ChildNameInvalid { .. } } => {
313                fcomponent::Error::InvalidArguments
314            }
315        }
316    }
317}
318
319// This is implemented for fuchsia.sys2.LifecycleController protocol
320impl Into<fsys::CreateError> for AddDynamicChildError {
321    fn into(self) -> fsys::CreateError {
322        match self {
323            AddDynamicChildError::CollectionNotFound { .. } => {
324                fsys::CreateError::CollectionNotFound
325            }
326            AddDynamicChildError::AddChildError {
327                err: AddChildError::InstanceAlreadyExists { .. },
328            } => fsys::CreateError::InstanceAlreadyExists,
329
330            AddDynamicChildError::DynamicOffersNotAllowed { .. } => {
331                fsys::CreateError::DynamicOffersForbidden
332            }
333            AddDynamicChildError::ActionError { .. } => fsys::CreateError::Internal,
334            AddDynamicChildError::InvalidDictionary { .. } => fsys::CreateError::Internal,
335            AddDynamicChildError::StaticRouteConflict { .. } => fsys::CreateError::Internal,
336            AddDynamicChildError::NameTooLong { .. } => fsys::CreateError::BadChildDecl,
337            AddDynamicChildError::AddChildError {
338                err: AddChildError::DynamicCapabilityError { .. },
339            } => fsys::CreateError::BadDynamicOffer,
340            AddDynamicChildError::AddChildError { err: AddChildError::ChildNameInvalid { .. } } => {
341                fsys::CreateError::BadMoniker
342            }
343            AddDynamicChildError::NumberedHandleNotInSingleRunCollection => {
344                fsys::CreateError::NumberedHandlesForbidden
345            }
346        }
347    }
348}
349
350#[derive(Debug, Error, Clone)]
351pub enum AddChildError {
352    #[error("component instance `{child}` in realm `{moniker}` already exists")]
353    InstanceAlreadyExists { moniker: Moniker, child: ChildName },
354    #[error(transparent)]
355    DynamicCapabilityError {
356        #[from]
357        err: DynamicCapabilityError,
358    },
359    #[error("invalid child name: {err}")]
360    ChildNameInvalid {
361        #[from]
362        err: MonikerError,
363    },
364}
365
366#[derive(Debug, Error, Clone, PartialEq)]
367pub enum DynamicCapabilityError {
368    #[error("a dynamic capability was not valid:\n\t{err}")]
369    Invalid {
370        #[source]
371        err: cm_fidl_validator::error::ErrorList,
372    },
373    #[error("dynamic offers are not allowed for {typename}")]
374    UnsupportedType { typename: &'static str },
375    #[error("dynamic offer would create a cycle:\n\t{err}")]
376    Cycle {
377        #[source]
378        err: cm_fidl_validator::error::ErrorList,
379    },
380    #[error("source for dynamic offer not found:\n\t{:?}", offer)]
381    SourceNotFound { offer: cm_rust::OfferDecl },
382    #[error("unknown offer type in dynamic offers")]
383    UnknownOfferType,
384}
385
386#[derive(Debug, Clone, Error)]
387pub enum ActionError {
388    #[error("discover: {err}")]
389    DiscoverError {
390        #[from]
391        err: DiscoverActionError,
392    },
393
394    #[error("resolve: {err}")]
395    ResolveError {
396        #[from]
397        err: ResolveActionError,
398    },
399
400    #[error("unresolve: {err}")]
401    UnresolveError {
402        #[from]
403        err: UnresolveActionError,
404    },
405
406    #[error("start: {err}")]
407    StartError {
408        #[from]
409        err: StartActionError,
410    },
411
412    #[error("stop: {err}")]
413    StopError {
414        #[from]
415        err: StopActionError,
416    },
417
418    #[error("destroy: {err}")]
419    DestroyError {
420        #[from]
421        err: DestroyActionError,
422    },
423
424    #[error("shutdown: {err}")]
425    ShutdownError {
426        #[from]
427        err: ShutdownActionError,
428    },
429}
430
431impl Explain for ActionError {
432    fn as_zx_status(&self) -> zx::Status {
433        match self {
434            ActionError::DiscoverError { .. } => zx::Status::INTERNAL,
435            ActionError::ResolveError { err } => err.as_zx_status(),
436            ActionError::UnresolveError { .. } => zx::Status::INTERNAL,
437            ActionError::StartError { err } => err.as_zx_status(),
438            ActionError::StopError { .. } => zx::Status::INTERNAL,
439            ActionError::DestroyError { .. } => zx::Status::INTERNAL,
440            ActionError::ShutdownError { .. } => zx::Status::INTERNAL,
441        }
442    }
443}
444
445impl From<ActionError> for fcomponent::Error {
446    fn from(err: ActionError) -> Self {
447        match err {
448            ActionError::DiscoverError { .. } => fcomponent::Error::Internal,
449            ActionError::ResolveError { .. } => fcomponent::Error::Internal,
450            ActionError::UnresolveError { .. } => fcomponent::Error::Internal,
451            ActionError::StartError { err } => err.into(),
452            ActionError::StopError { err } => err.into(),
453            ActionError::DestroyError { err } => err.into(),
454            ActionError::ShutdownError { .. } => fcomponent::Error::Internal,
455        }
456    }
457}
458
459impl From<ActionError> for fsys::ResolveError {
460    fn from(err: ActionError) -> Self {
461        match err {
462            ActionError::ResolveError { err } => err.into(),
463            _ => fsys::ResolveError::Internal,
464        }
465    }
466}
467
468impl From<ActionError> for fsys::UnresolveError {
469    fn from(err: ActionError) -> Self {
470        match err {
471            ActionError::UnresolveError { err } => err.into(),
472            _ => fsys::UnresolveError::Internal,
473        }
474    }
475}
476
477impl From<ActionError> for fsys::StartError {
478    fn from(err: ActionError) -> Self {
479        match err {
480            ActionError::StartError { err } => err.into(),
481            _ => fsys::StartError::Internal,
482        }
483    }
484}
485
486impl From<ActionError> for fsys::StopError {
487    fn from(err: ActionError) -> Self {
488        match err {
489            ActionError::StopError { err } => err.into(),
490            _ => fsys::StopError::Internal,
491        }
492    }
493}
494
495impl From<ActionError> for fsys::DestroyError {
496    fn from(err: ActionError) -> Self {
497        match err {
498            ActionError::DestroyError { err } => err.into(),
499            _ => fsys::DestroyError::Internal,
500        }
501    }
502}
503
504#[derive(Debug, Clone, Error)]
505pub enum DiscoverActionError {
506    #[error("`{moniker}` was destroyed")]
507    InstanceDestroyed { moniker: Moniker },
508}
509
510#[derive(Debug, Clone, Error)]
511pub enum ResolveActionError {
512    #[error("discover during resolve: {err}")]
513    DiscoverActionError {
514        #[from]
515        err: DiscoverActionError,
516    },
517    #[error("`{moniker}` was shut down")]
518    InstanceShutDown { moniker: Moniker },
519    #[error("`{moniker}` was destroyed")]
520    InstanceDestroyed { moniker: Moniker },
521    #[error("could not parse component address for `{url}` at `{moniker}`:\n\t{err}")]
522    ComponentAddressParseError {
523        url: Url,
524        moniker: Moniker,
525        #[source]
526        err: ResolverError,
527    },
528    #[error("resolve failed for `{url}`:\n\t{err}")]
529    ResolverError {
530        url: Url,
531        #[source]
532        err: ResolverError,
533    },
534    #[error("expose dir for `{moniker}`:\n\t{err}")]
535    // TODO(https://fxbug.dev/42071713): Determine whether this is expected to fail.
536    ExposeDirError {
537        moniker: Moniker,
538
539        #[source]
540        err: VfsError,
541    },
542    #[error("adding static child `{child_name}`:\n\t{err}")]
543    AddStaticChildError {
544        child_name: String,
545        #[source]
546        err: AddChildError,
547    },
548    #[error("structured config: {err}")]
549    StructuredConfigError {
550        #[from]
551        err: StructuredConfigError,
552    },
553    #[error("creating package dir proxy: {err}")]
554    PackageDirProxyCreateError {
555        #[source]
556        err: fidl::Error,
557    },
558    #[error("ABI compatibility check for `{url}`: {err}")]
559    AbiCompatibilityError {
560        url: Url,
561        #[source]
562        err: CompatibilityCheckError,
563    },
564    #[error(transparent)]
565    Policy(#[from] PolicyError),
566    #[error("`{moniker}` was interrupted")]
567    Aborted { moniker: Moniker },
568}
569
570impl ResolveActionError {
571    fn as_zx_status(&self) -> zx::Status {
572        match self {
573            ResolveActionError::DiscoverActionError { .. }
574            | ResolveActionError::InstanceShutDown { .. }
575            | ResolveActionError::InstanceDestroyed { .. }
576            | ResolveActionError::ComponentAddressParseError { .. }
577            | ResolveActionError::AbiCompatibilityError { .. } => zx::Status::NOT_FOUND,
578            ResolveActionError::ExposeDirError { .. }
579            | ResolveActionError::AddStaticChildError { .. }
580            | ResolveActionError::StructuredConfigError { .. }
581            | ResolveActionError::Aborted { .. }
582            | ResolveActionError::PackageDirProxyCreateError { .. } => zx::Status::INTERNAL,
583            ResolveActionError::ResolverError { err, .. } => err.as_zx_status(),
584            ResolveActionError::Policy(err) => err.as_zx_status(),
585        }
586    }
587}
588
589// This is implemented for fuchsia.sys2.LifecycleController protocol
590impl Into<fsys::ResolveError> for ResolveActionError {
591    fn into(self) -> fsys::ResolveError {
592        match self {
593            ResolveActionError::ResolverError {
594                err: ResolverError::PackageNotFound(_), ..
595            } => fsys::ResolveError::PackageNotFound,
596            ResolveActionError::ResolverError {
597                err: ResolverError::ManifestNotFound(_), ..
598            } => fsys::ResolveError::ManifestNotFound,
599            ResolveActionError::InstanceShutDown { .. }
600            | ResolveActionError::InstanceDestroyed { .. } => fsys::ResolveError::InstanceNotFound,
601            ResolveActionError::ExposeDirError { .. }
602            | ResolveActionError::ResolverError { .. }
603            | ResolveActionError::StructuredConfigError { .. }
604            | ResolveActionError::ComponentAddressParseError { .. }
605            | ResolveActionError::AddStaticChildError { .. }
606            | ResolveActionError::DiscoverActionError { .. }
607            | ResolveActionError::AbiCompatibilityError { .. }
608            | ResolveActionError::Aborted { .. }
609            | ResolveActionError::PackageDirProxyCreateError { .. } => fsys::ResolveError::Internal,
610            ResolveActionError::Policy(_) => fsys::ResolveError::PolicyError,
611        }
612    }
613}
614
615// This is implemented for fuchsia.sys2.LifecycleController protocol.
616// Starting a component instance also causes a resolve.
617impl Into<fsys::StartError> for ResolveActionError {
618    fn into(self) -> fsys::StartError {
619        match self {
620            ResolveActionError::ResolverError {
621                err: ResolverError::PackageNotFound(_), ..
622            } => fsys::StartError::PackageNotFound,
623            ResolveActionError::ResolverError {
624                err: ResolverError::ManifestNotFound(_), ..
625            } => fsys::StartError::ManifestNotFound,
626            ResolveActionError::InstanceShutDown { .. }
627            | ResolveActionError::InstanceDestroyed { .. } => fsys::StartError::InstanceNotFound,
628            ResolveActionError::ExposeDirError { .. }
629            | ResolveActionError::ResolverError { .. }
630            | ResolveActionError::StructuredConfigError { .. }
631            | ResolveActionError::ComponentAddressParseError { .. }
632            | ResolveActionError::AddStaticChildError { .. }
633            | ResolveActionError::DiscoverActionError { .. }
634            | ResolveActionError::AbiCompatibilityError { .. }
635            | ResolveActionError::Aborted { .. }
636            | ResolveActionError::PackageDirProxyCreateError { .. } => fsys::StartError::Internal,
637            ResolveActionError::Policy(_) => fsys::StartError::PolicyError,
638        }
639    }
640}
641
642#[derive(Debug, Clone, Error)]
643pub enum PkgDirError {
644    #[error("no pkg dir found for component")]
645    NoPkgDir,
646    #[error("opening pkg dir failed: {err}")]
647    OpenFailed {
648        #[from]
649        err: zx::Status,
650    },
651}
652
653impl PkgDirError {
654    fn as_zx_status(&self) -> zx::Status {
655        match self {
656            Self::NoPkgDir => zx::Status::NOT_FOUND,
657            Self::OpenFailed { err } => *err,
658        }
659    }
660}
661
662#[derive(Debug, Clone, Error)]
663pub enum ComponentProviderError {
664    #[error("starting source instance:\n\t{err}")]
665    SourceStartError {
666        #[from]
667        err: ActionError,
668    },
669    #[error("opening source instance's outgoing dir:\n\t{err}")]
670    OpenOutgoingDirError {
671        #[from]
672        err: OpenOutgoingDirError,
673    },
674}
675
676impl ComponentProviderError {
677    pub fn as_zx_status(&self) -> zx::Status {
678        match self {
679            Self::SourceStartError { err } => err.as_zx_status(),
680            Self::OpenOutgoingDirError { err } => err.as_zx_status(),
681        }
682    }
683}
684
685#[derive(Debug, Clone, Error)]
686pub enum CapabilityProviderError {
687    #[error("bad path")]
688    BadPath,
689    #[error(transparent)]
690    ComponentInstanceError {
691        #[from]
692        err: ComponentInstanceError,
693    },
694    #[error(transparent)]
695    PkgDirError {
696        #[from]
697        err: PkgDirError,
698    },
699    #[error("event source: {0}")]
700    EventSourceError(#[from] EventSourceError),
701    #[error(transparent)]
702    ComponentProviderError {
703        #[from]
704        err: ComponentProviderError,
705    },
706    #[error("component_manager namespace: {err}")]
707    CmNamespaceError {
708        #[from]
709        err: ClonableError,
710    },
711    #[error("router: {err}")]
712    RouterError {
713        #[from]
714        err: RouterError,
715    },
716    #[error(transparent)]
717    RoutingError(#[from] RoutingError),
718    #[error("opening vfs failed: {0}")]
719    VfsOpenError(#[source] zx::Status),
720}
721
722impl CapabilityProviderError {
723    pub fn as_zx_status(&self) -> zx::Status {
724        match self {
725            Self::BadPath => zx::Status::INVALID_ARGS,
726            Self::ComponentInstanceError { err } => err.as_zx_status(),
727            Self::CmNamespaceError { .. } => zx::Status::INTERNAL,
728            Self::PkgDirError { err } => err.as_zx_status(),
729            Self::EventSourceError(err) => err.as_zx_status(),
730            Self::ComponentProviderError { err } => err.as_zx_status(),
731            Self::RouterError { err } => err.as_zx_status(),
732            Self::RoutingError(err) => err.as_zx_status(),
733            Self::VfsOpenError(err) => *err,
734        }
735    }
736}
737
738#[derive(Debug, Clone, Error)]
739pub enum OpenError {
740    #[error("failed to get default capability provider: {err}")]
741    GetDefaultProviderError {
742        // TODO(https://fxbug.dev/42068065): This will get fixed when we untangle ModelError
743        #[source]
744        err: Box<ModelError>,
745    },
746    #[error("no capability provider found")]
747    CapabilityProviderNotFound,
748    #[error("capability provider: {err}")]
749    CapabilityProviderError {
750        #[from]
751        err: CapabilityProviderError,
752    },
753    #[error("opening storage capability: {err}")]
754    OpenStorageError {
755        // TODO(https://fxbug.dev/42068065): This will get fixed when we untangle ModelError
756        #[source]
757        err: Box<ModelError>,
758    },
759    #[error("timed out opening capability")]
760    Timeout,
761    #[error("invalid path found")]
762    BadPath,
763    #[error("capability does not support opening: {0}")]
764    DoesNotSupportOpen(ConversionError),
765    #[error("failed to create directory watcher: {err}")]
766    WatcherCreateError {
767        #[from]
768        err: WatcherCreateError,
769    },
770}
771
772impl Explain for OpenError {
773    fn as_zx_status(&self) -> zx::Status {
774        match self {
775            Self::GetDefaultProviderError { err } => err.as_zx_status(),
776            Self::OpenStorageError { err } => err.as_zx_status(),
777            Self::CapabilityProviderError { err } => err.as_zx_status(),
778            Self::CapabilityProviderNotFound => zx::Status::NOT_FOUND,
779            Self::Timeout => zx::Status::TIMED_OUT,
780            Self::BadPath => zx::Status::BAD_PATH,
781            Self::DoesNotSupportOpen(_) => zx::Status::NOT_SUPPORTED,
782            Self::WatcherCreateError { err: WatcherCreateError::SendWatchRequest(_err) } => {
783                zx::Status::PEER_CLOSED
784            }
785            Self::WatcherCreateError { err: WatcherCreateError::WatchError(status) } => *status,
786            Self::WatcherCreateError { err: WatcherCreateError::ChannelConversion(status) } => {
787                *status
788            }
789        }
790    }
791}
792
793impl From<OpenError> for RouterError {
794    fn from(value: OpenError) -> Self {
795        Self::NotFound(Arc::new(value))
796    }
797}
798
799#[derive(Debug, Clone, Error)]
800pub enum StartActionError {
801    #[error("`{moniker}` was shut down")]
802    InstanceShutDown { moniker: Moniker },
803    #[error("`{moniker}` was destroyed")]
804    InstanceDestroyed { moniker: Moniker },
805    #[error("`{moniker}` couldn't resolve during start: {err}")]
806    ResolveActionError {
807        moniker: Moniker,
808        #[source]
809        err: Box<ActionError>,
810    },
811    #[error("runner for `{moniker}` `{runner}` couldn't resolve: {err}")]
812    ResolveRunnerError {
813        moniker: Moniker,
814        runner: Name,
815        #[source]
816        err: Box<RouterError>,
817    },
818    #[error(
819        "`{moniker}` uses `\"on_terminate\": \"reboot\"` but is disallowed by policy:\n\t{err}"
820    )]
821    RebootOnTerminateForbidden {
822        moniker: Moniker,
823        #[source]
824        err: PolicyError,
825    },
826    #[error("creating program input dictionary for `{moniker}`")]
827    InputDictionaryError { moniker: Moniker },
828    #[error("creating namespace: {0}")]
829    CreateNamespaceError(#[from] CreateNamespaceError),
830    #[error("starting program for `{moniker}`: {err}")]
831    StartProgramError {
832        moniker: Moniker,
833        #[source]
834        err: StartError,
835    },
836    #[error("structured configuration for `{moniker}`: {err}")]
837    StructuredConfigError {
838        moniker: Moniker,
839        #[source]
840        err: StructuredConfigError,
841    },
842    #[error("starting eager child of `{moniker}`: {err}")]
843    EagerStartError {
844        moniker: Moniker,
845        #[source]
846        err: Box<ActionError>,
847    },
848    #[error("`{moniker}` was interrupted")]
849    Aborted { moniker: Moniker },
850}
851
852impl StartActionError {
853    fn as_zx_status(&self) -> zx::Status {
854        match self {
855            StartActionError::InstanceDestroyed { .. } | Self::InstanceShutDown { .. } => {
856                zx::Status::NOT_FOUND
857            }
858            StartActionError::StartProgramError { .. }
859            | StartActionError::StructuredConfigError { .. }
860            | StartActionError::EagerStartError { .. } => zx::Status::INTERNAL,
861            StartActionError::RebootOnTerminateForbidden { err, .. } => err.as_zx_status(),
862            StartActionError::ResolveRunnerError { err, .. } => err.as_zx_status(),
863            StartActionError::CreateNamespaceError(err) => err.as_zx_status(),
864            StartActionError::InputDictionaryError { .. } => zx::Status::NOT_FOUND,
865            StartActionError::ResolveActionError { err, .. } => err.as_zx_status(),
866            StartActionError::Aborted { .. } => zx::Status::NOT_FOUND,
867        }
868    }
869}
870
871// This is implemented for fuchsia.sys2.LifecycleController protocol.
872impl Into<fsys::StartError> for StartActionError {
873    fn into(self) -> fsys::StartError {
874        match self {
875            StartActionError::ResolveActionError { err, .. } => (*err).into(),
876            StartActionError::InstanceDestroyed { .. } => fsys::StartError::InstanceNotFound,
877            StartActionError::InstanceShutDown { .. } => fsys::StartError::InstanceNotFound,
878            _ => fsys::StartError::Internal,
879        }
880    }
881}
882
883// This is implemented for fuchsia.component.Realm protocol.
884impl Into<fcomponent::Error> for StartActionError {
885    fn into(self) -> fcomponent::Error {
886        match self {
887            StartActionError::ResolveActionError { .. } => fcomponent::Error::InstanceCannotResolve,
888            StartActionError::RebootOnTerminateForbidden { .. } => fcomponent::Error::AccessDenied,
889            StartActionError::InstanceShutDown { .. } => fcomponent::Error::InstanceDied,
890            StartActionError::InstanceDestroyed { .. } => fcomponent::Error::InstanceDied,
891            _ => fcomponent::Error::InstanceCannotStart,
892        }
893    }
894}
895
896#[derive(Debug, Clone, Error)]
897pub enum StopActionError {
898    #[error("stopping program: {0}")]
899    ProgramStopError(#[source] StopError),
900    #[error("failed to get top instance")]
901    GetTopInstanceFailed,
902    #[error("failed to get parent instance")]
903    GetParentFailed,
904    #[error("failed to destroy dynamic children: {err}")]
905    DestroyDynamicChildrenFailed { err: Box<ActionError> },
906    #[error("resolution during stop: {err}")]
907    ResolveActionError {
908        #[source]
909        err: Box<ActionError>,
910    },
911    #[error("started while shutdown was ongoing")]
912    ComponentStartedDuringShutdown,
913}
914
915// This is implemented for fuchsia.sys2.LifecycleController protocol.
916impl Into<fsys::StopError> for StopActionError {
917    fn into(self) -> fsys::StopError {
918        fsys::StopError::Internal
919    }
920}
921
922impl Into<fcomponent::Error> for StopActionError {
923    fn into(self) -> fcomponent::Error {
924        fcomponent::Error::Internal
925    }
926}
927
928#[cfg(test)]
929impl PartialEq for StopActionError {
930    fn eq(&self, other: &Self) -> bool {
931        match (self, other) {
932            (StopActionError::ProgramStopError(_), StopActionError::ProgramStopError(_)) => true,
933            (StopActionError::GetTopInstanceFailed, StopActionError::GetTopInstanceFailed) => true,
934            (StopActionError::GetParentFailed, StopActionError::GetParentFailed) => true,
935            (
936                StopActionError::DestroyDynamicChildrenFailed { .. },
937                StopActionError::DestroyDynamicChildrenFailed { .. },
938            ) => true,
939            (
940                StopActionError::ResolveActionError { .. },
941                StopActionError::ResolveActionError { .. },
942            ) => true,
943            _ => false,
944        }
945    }
946}
947
948#[derive(Debug, Clone, Error)]
949pub enum ShutdownActionError {
950    #[error("child name invalid: {}", err)]
951    InvalidChildName {
952        #[from]
953        err: MonikerError,
954    },
955    #[error("cycles detected in graph")]
956    CyclesDetected {},
957}
958
959#[derive(Debug, Clone, Error)]
960pub enum DestroyActionError {
961    #[error("discover during destroy: {}", err)]
962    DiscoverActionError {
963        #[from]
964        err: DiscoverActionError,
965    },
966    #[error("shutdown during destroy: {}", err)]
967    ShutdownFailed {
968        #[source]
969        err: Box<ActionError>,
970    },
971    #[error("could not find `{moniker}`")]
972    InstanceNotFound { moniker: Moniker },
973    #[error("`{moniker}` is not resolved")]
974    InstanceNotResolved { moniker: Moniker },
975}
976
977// This is implemented for fuchsia.component.Realm protocol.
978impl Into<fcomponent::Error> for DestroyActionError {
979    fn into(self) -> fcomponent::Error {
980        match self {
981            DestroyActionError::InstanceNotFound { .. } => fcomponent::Error::InstanceNotFound,
982            _ => fcomponent::Error::Internal,
983        }
984    }
985}
986
987// This is implemented for fuchsia.sys2.LifecycleController protocol.
988impl Into<fsys::DestroyError> for DestroyActionError {
989    fn into(self) -> fsys::DestroyError {
990        match self {
991            DestroyActionError::InstanceNotFound { .. } => fsys::DestroyError::InstanceNotFound,
992            DestroyActionError::InstanceNotResolved { .. } => {
993                fsys::DestroyError::InstanceNotResolved
994            }
995            _ => fsys::DestroyError::Internal,
996        }
997    }
998}
999
1000#[derive(Debug, Clone, Error)]
1001pub enum UnresolveActionError {
1002    #[error("shutdown during unresolve: {err}")]
1003    ShutdownFailed {
1004        #[from]
1005        err: StopActionError,
1006    },
1007    #[error("`{moniker}` cannot be unresolved while it is running")]
1008    InstanceRunning { moniker: Moniker },
1009    #[error("`{moniker}` was destroyed")]
1010    InstanceDestroyed { moniker: Moniker },
1011}
1012
1013// This is implemented for fuchsia.sys2.LifecycleController protocol.
1014impl Into<fsys::UnresolveError> for UnresolveActionError {
1015    fn into(self) -> fsys::UnresolveError {
1016        match self {
1017            UnresolveActionError::InstanceDestroyed { .. } => {
1018                fsys::UnresolveError::InstanceNotFound
1019            }
1020            _ => fsys::UnresolveError::Internal,
1021        }
1022    }
1023}
1024
1025#[derive(Debug, Clone, Error)]
1026pub enum CreateNamespaceError {
1027    #[error("failed to clone pkg dir for {moniker}: {err}")]
1028    ClonePkgDirFailed {
1029        moniker: Moniker,
1030        #[source]
1031        err: fuchsia_fs::node::CloneError,
1032    },
1033
1034    #[error("use decl without path cannot be installed into the namespace for {moniker}: {decl:?}")]
1035    UseDeclWithoutPath { moniker: Moniker, decl: UseDecl },
1036
1037    #[error("instance not in index: {0}")]
1038    InstanceNotInInstanceIdIndex(#[from] RoutingError),
1039
1040    #[error("building namespace for {moniker}: {err}")]
1041    BuildNamespaceError {
1042        moniker: Moniker,
1043        #[source]
1044        err: serve_processargs::BuildNamespaceError,
1045    },
1046
1047    #[error("failed to convert namespace into directory for {moniker}: {err}")]
1048    ConvertToDirectory {
1049        moniker: Moniker,
1050        #[source]
1051        err: ClonableError,
1052    },
1053
1054    #[error(transparent)]
1055    ComponentInstanceError(#[from] ComponentInstanceError),
1056}
1057
1058impl CreateNamespaceError {
1059    fn as_zx_status(&self) -> zx::Status {
1060        match self {
1061            Self::ClonePkgDirFailed { .. } => zx::Status::INTERNAL,
1062            Self::UseDeclWithoutPath { .. } => zx::Status::NOT_FOUND,
1063            Self::InstanceNotInInstanceIdIndex(err) => err.as_zx_status(),
1064            Self::BuildNamespaceError { .. } => zx::Status::NOT_FOUND,
1065            Self::ConvertToDirectory { .. } => zx::Status::INTERNAL,
1066            Self::ComponentInstanceError(err) => err.as_zx_status(),
1067        }
1068    }
1069}
1070
1071#[derive(Debug, Clone, Error)]
1072pub enum EventSourceError {
1073    #[error(transparent)]
1074    ComponentInstance(#[from] ComponentInstanceError),
1075    #[error(transparent)]
1076    // TODO(https://fxbug.dev/42068065): This will get fixed when we untangle ModelError
1077    Model(#[from] Box<ModelError>),
1078    #[error("event stream already consumed")]
1079    AlreadyConsumed,
1080}
1081
1082impl EventSourceError {
1083    fn as_zx_status(&self) -> zx::Status {
1084        match self {
1085            Self::ComponentInstance(err) => err.as_zx_status(),
1086            Self::Model(err) => err.as_zx_status(),
1087            Self::AlreadyConsumed => zx::Status::INTERNAL,
1088        }
1089    }
1090}
1091
1092#[derive(Debug, Error, Clone)]
1093pub enum EventsError {
1094    #[error("capability_requested event streams cannot be taken twice")]
1095    CapabilityRequestedStreamTaken,
1096
1097    #[error("model not available")]
1098    ModelNotAvailable,
1099
1100    #[error("instance shut down")]
1101    InstanceShutdown,
1102
1103    #[error("instance destroyed")]
1104    InstanceDestroyed,
1105
1106    #[error("registry not found")]
1107    RegistryNotFound,
1108
1109    #[error("event `{event_name}` appears more than once in a subscription request")]
1110    DuplicateEvent { event_name: Name },
1111
1112    #[error("events not available for subscription: `{names:?}`")]
1113    NotAvailable { names: Vec<Name> },
1114}
1115
1116impl EventsError {
1117    pub fn duplicate_event(event_name: Name) -> Self {
1118        Self::DuplicateEvent { event_name }
1119    }
1120
1121    pub fn not_available(names: Vec<Name>) -> Self {
1122        Self::NotAvailable { names }
1123    }
1124}
1125
1126/// Errors related to isolated storage.
1127#[derive(Debug, Error, Clone)]
1128pub enum StorageError {
1129    #[error("opening directory from `{dir_source_moniker:?}` at `{dir_source_path}`:\n\t{err}")]
1130    OpenRoot {
1131        dir_source_moniker: Option<Moniker>,
1132        dir_source_path: cm_types::Path,
1133        #[source]
1134        err: ClonableError,
1135    },
1136    #[error(
1137        "opening isolated storage from `{dir_source_moniker:?}`'s for `{moniker}` at `{dir_source_path}` (instance_id={instance_id:?}):\n\t{err}"
1138    )]
1139    Open {
1140        dir_source_moniker: Option<Moniker>,
1141        dir_source_path: cm_types::Path,
1142        moniker: Moniker,
1143        instance_id: Option<InstanceId>,
1144        #[source]
1145        err: ClonableError,
1146    },
1147    #[error(
1148        "opening isolated storage from `{dir_source_moniker:?}` at `{dir_source_path}` for {instance_id}:\n\t{err}"
1149    )]
1150    OpenById {
1151        dir_source_moniker: Option<Moniker>,
1152        dir_source_path: cm_types::Path,
1153        instance_id: InstanceId,
1154        #[source]
1155        err: ClonableError,
1156    },
1157    #[error(
1158        "removing isolated storage from {dir_source_moniker:?} at `{dir_source_path}` for `{moniker}` (instance_id={instance_id:?}):n\t{err} "
1159    )]
1160    Remove {
1161        dir_source_moniker: Option<Moniker>,
1162        dir_source_path: cm_types::Path,
1163        moniker: Moniker,
1164        instance_id: Option<InstanceId>,
1165        #[source]
1166        err: ClonableError,
1167    },
1168    #[error("storage path for `{moniker}` (instance_id={instance_id:?}) is invalid")]
1169    InvalidStoragePath { moniker: Moniker, instance_id: Option<InstanceId> },
1170}
1171
1172impl StorageError {
1173    pub fn open_root(
1174        dir_source_moniker: Option<Moniker>,
1175        dir_source_path: cm_types::Path,
1176        err: impl Into<Error>,
1177    ) -> Self {
1178        Self::OpenRoot { dir_source_moniker, dir_source_path, err: err.into().into() }
1179    }
1180
1181    pub fn open(
1182        dir_source_moniker: Option<Moniker>,
1183        dir_source_path: cm_types::Path,
1184        moniker: Moniker,
1185        instance_id: Option<InstanceId>,
1186        err: impl Into<Error>,
1187    ) -> Self {
1188        Self::Open {
1189            dir_source_moniker,
1190            dir_source_path,
1191            moniker,
1192            instance_id,
1193            err: err.into().into(),
1194        }
1195    }
1196
1197    pub fn open_by_id(
1198        dir_source_moniker: Option<Moniker>,
1199        dir_source_path: cm_types::Path,
1200        instance_id: InstanceId,
1201        err: impl Into<Error>,
1202    ) -> Self {
1203        Self::OpenById { dir_source_moniker, dir_source_path, instance_id, err: err.into().into() }
1204    }
1205
1206    pub fn remove(
1207        dir_source_moniker: Option<Moniker>,
1208        dir_source_path: cm_types::Path,
1209        moniker: Moniker,
1210        instance_id: Option<InstanceId>,
1211        err: impl Into<Error>,
1212    ) -> Self {
1213        Self::Remove {
1214            dir_source_moniker,
1215            dir_source_path,
1216            moniker,
1217            instance_id,
1218            err: err.into().into(),
1219        }
1220    }
1221
1222    pub fn invalid_storage_path(moniker: Moniker, instance_id: Option<InstanceId>) -> Self {
1223        Self::InvalidStoragePath { moniker, instance_id }
1224    }
1225}
1226
1227#[derive(Error, Debug, Clone)]
1228pub enum StartError {
1229    #[error("serving namespace: {0}")]
1230    ServeNamespace(BuildNamespaceError),
1231}
1232
1233#[derive(Error, Debug, Clone)]
1234pub enum StopError {
1235    /// Internal errors are not meant to be meaningfully handled by the user.
1236    #[error("internal: {0}")]
1237    Internal(fidl::Error),
1238}