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    #[error("cannot set both `dictionary` and `additional_inputs`")]
282    DictionaryAndAdditionalInputsSet,
283}
284
285// This is implemented for fuchsia.component.Realm protocol
286impl Into<fcomponent::Error> for AddDynamicChildError {
287    fn into(self) -> fcomponent::Error {
288        match self {
289            AddDynamicChildError::CollectionNotFound { .. } => {
290                fcomponent::Error::CollectionNotFound
291            }
292            AddDynamicChildError::NumberedHandleNotInSingleRunCollection => {
293                fcomponent::Error::Unsupported
294            }
295            AddDynamicChildError::AddChildError {
296                err: AddChildError::InstanceAlreadyExists { .. },
297            } => fcomponent::Error::InstanceAlreadyExists,
298            AddDynamicChildError::DynamicOffersNotAllowed { .. } => {
299                fcomponent::Error::InvalidArguments
300            }
301            AddDynamicChildError::ActionError { err } => err.into(),
302            AddDynamicChildError::InvalidDictionary { .. } => fcomponent::Error::InvalidArguments,
303            AddDynamicChildError::StaticRouteConflict { .. } => fcomponent::Error::InvalidArguments,
304            AddDynamicChildError::NameTooLong { .. } => fcomponent::Error::InvalidArguments,
305            // TODO(https://fxbug.dev/297403341): This should become its own error in fidl once
306            // we can introduce it without breaking compatibility.
307            AddDynamicChildError::AddChildError {
308                err:
309                    AddChildError::DynamicCapabilityError { err: DynamicCapabilityError::Cycle { .. } },
310            } => fcomponent::Error::DependencyCycle,
311            AddDynamicChildError::AddChildError {
312                err: AddChildError::DynamicCapabilityError { .. },
313            } => fcomponent::Error::InvalidArguments,
314            AddDynamicChildError::AddChildError { err: AddChildError::ChildNameInvalid { .. } } => {
315                fcomponent::Error::InvalidArguments
316            }
317            AddDynamicChildError::DictionaryAndAdditionalInputsSet => {
318                fcomponent::Error::InvalidArguments
319            }
320        }
321    }
322}
323
324// This is implemented for fuchsia.sys2.LifecycleController protocol
325impl Into<fsys::CreateError> for AddDynamicChildError {
326    fn into(self) -> fsys::CreateError {
327        match self {
328            AddDynamicChildError::CollectionNotFound { .. } => {
329                fsys::CreateError::CollectionNotFound
330            }
331            AddDynamicChildError::AddChildError {
332                err: AddChildError::InstanceAlreadyExists { .. },
333            } => fsys::CreateError::InstanceAlreadyExists,
334
335            AddDynamicChildError::DynamicOffersNotAllowed { .. } => {
336                fsys::CreateError::DynamicOffersForbidden
337            }
338            AddDynamicChildError::ActionError { .. } => fsys::CreateError::Internal,
339            AddDynamicChildError::InvalidDictionary { .. } => fsys::CreateError::Internal,
340            AddDynamicChildError::StaticRouteConflict { .. } => fsys::CreateError::Internal,
341            AddDynamicChildError::NameTooLong { .. } => fsys::CreateError::BadChildDecl,
342            AddDynamicChildError::AddChildError {
343                err: AddChildError::DynamicCapabilityError { .. },
344            } => fsys::CreateError::BadDynamicOffer,
345            AddDynamicChildError::AddChildError { err: AddChildError::ChildNameInvalid { .. } } => {
346                fsys::CreateError::BadMoniker
347            }
348            AddDynamicChildError::NumberedHandleNotInSingleRunCollection => {
349                fsys::CreateError::NumberedHandlesForbidden
350            }
351            AddDynamicChildError::DictionaryAndAdditionalInputsSet => {
352                fsys::CreateError::DictionaryAndAdditionalInputsSet
353            }
354        }
355    }
356}
357
358#[derive(Debug, Error, Clone)]
359pub enum AddChildError {
360    #[error("component instance `{child}` in realm `{moniker}` already exists")]
361    InstanceAlreadyExists { moniker: Moniker, child: ChildName },
362    #[error(transparent)]
363    DynamicCapabilityError {
364        #[from]
365        err: DynamicCapabilityError,
366    },
367    #[error("invalid child name: {err}")]
368    ChildNameInvalid {
369        #[from]
370        err: MonikerError,
371    },
372}
373
374#[derive(Debug, Error, Clone, PartialEq)]
375pub enum DynamicCapabilityError {
376    #[error("a dynamic capability was not valid:\n\t{err}")]
377    Invalid {
378        #[source]
379        err: cm_fidl_validator::error::ErrorList,
380    },
381    #[error("dynamic offers are not allowed for {typename}")]
382    UnsupportedType { typename: &'static str },
383    #[error("dynamic offer would create a cycle:\n\t{err}")]
384    Cycle {
385        #[source]
386        err: cm_fidl_validator::error::ErrorList,
387    },
388    #[error("source for dynamic offer not found:\n\t{:?}", offer)]
389    SourceNotFound { offer: cm_rust::OfferDecl },
390    #[error("unknown offer type in dynamic offers")]
391    UnknownOfferType,
392}
393
394#[derive(Debug, Clone, Error)]
395#[error(transparent)]
396pub struct ActionError {
397    kind: Box<ActionErrorKind>,
398}
399
400impl ActionError {
401    pub fn kind(&self) -> &ActionErrorKind {
402        &self.kind
403    }
404}
405
406impl From<ActionErrorKind> for ActionError {
407    fn from(err: ActionErrorKind) -> Self {
408        ActionError { kind: Box::new(err) }
409    }
410}
411
412macro_rules! impl_from_action_error_kind {
413    ($($ty:ty,)+) => {
414        $(
415            impl From<$ty> for ActionError {
416                fn from(err: $ty) -> Self {
417                    ActionError::from(ActionErrorKind::from(err))
418                }
419            }
420        )+
421    }
422}
423
424impl_from_action_error_kind! {
425    DiscoverActionError,
426    ResolveActionError,
427    UnresolveActionError,
428    StartActionError,
429    StopActionError,
430    DestroyActionError,
431    ShutdownActionError,
432}
433
434#[derive(Debug, Clone, Error)]
435pub enum ActionErrorKind {
436    #[error("discover: {err}")]
437    DiscoverError {
438        #[from]
439        err: DiscoverActionError,
440    },
441
442    #[error("resolve: {err}")]
443    ResolveError {
444        #[from]
445        err: ResolveActionError,
446    },
447
448    #[error("unresolve: {err}")]
449    UnresolveError {
450        #[from]
451        err: UnresolveActionError,
452    },
453
454    #[error("start: {err}")]
455    StartError {
456        #[from]
457        err: StartActionError,
458    },
459
460    #[error("stop: {err}")]
461    StopError {
462        #[from]
463        err: StopActionError,
464    },
465
466    #[error("destroy: {err}")]
467    DestroyError {
468        #[from]
469        err: DestroyActionError,
470    },
471
472    #[error("shutdown: {err}")]
473    ShutdownError {
474        #[from]
475        err: ShutdownActionError,
476    },
477}
478
479impl Explain for ActionError {
480    fn as_zx_status(&self) -> zx::Status {
481        match &*self.kind {
482            ActionErrorKind::DiscoverError { .. } => zx::Status::INTERNAL,
483            ActionErrorKind::ResolveError { err } => err.as_zx_status(),
484            ActionErrorKind::UnresolveError { .. } => zx::Status::INTERNAL,
485            ActionErrorKind::StartError { err } => err.as_zx_status(),
486            ActionErrorKind::StopError { .. } => zx::Status::INTERNAL,
487            ActionErrorKind::DestroyError { .. } => zx::Status::INTERNAL,
488            ActionErrorKind::ShutdownError { .. } => zx::Status::INTERNAL,
489        }
490    }
491}
492
493impl From<ActionError> for fcomponent::Error {
494    fn from(err: ActionError) -> Self {
495        match *err.kind {
496            ActionErrorKind::DiscoverError { .. } => fcomponent::Error::Internal,
497            ActionErrorKind::ResolveError { .. } => fcomponent::Error::Internal,
498            ActionErrorKind::UnresolveError { .. } => fcomponent::Error::Internal,
499            ActionErrorKind::StartError { err } => err.into(),
500            ActionErrorKind::StopError { err } => err.into(),
501            ActionErrorKind::DestroyError { err } => err.into(),
502            ActionErrorKind::ShutdownError { .. } => fcomponent::Error::Internal,
503        }
504    }
505}
506
507impl From<ActionError> for fsys::ResolveError {
508    fn from(err: ActionError) -> Self {
509        match *err.kind {
510            ActionErrorKind::ResolveError { err } => err.into(),
511            _ => fsys::ResolveError::Internal,
512        }
513    }
514}
515
516impl From<ActionError> for fsys::UnresolveError {
517    fn from(err: ActionError) -> Self {
518        match *err.kind {
519            ActionErrorKind::UnresolveError { err } => err.into(),
520            _ => fsys::UnresolveError::Internal,
521        }
522    }
523}
524
525impl From<ActionError> for fsys::StartError {
526    fn from(err: ActionError) -> Self {
527        match *err.kind {
528            ActionErrorKind::StartError { err } => err.into(),
529            _ => fsys::StartError::Internal,
530        }
531    }
532}
533
534impl From<ActionError> for fsys::StopError {
535    fn from(err: ActionError) -> Self {
536        match *err.kind {
537            ActionErrorKind::StopError { err } => err.into(),
538            _ => fsys::StopError::Internal,
539        }
540    }
541}
542
543impl From<ActionError> for fsys::DestroyError {
544    fn from(err: ActionError) -> Self {
545        match *err.kind {
546            ActionErrorKind::DestroyError { err } => err.into(),
547            _ => fsys::DestroyError::Internal,
548        }
549    }
550}
551
552#[derive(Debug, Clone, Error)]
553pub enum DiscoverActionError {
554    #[error("`{moniker}` was destroyed")]
555    InstanceDestroyed { moniker: Moniker },
556}
557
558#[derive(Debug, Clone, Error)]
559pub enum ResolveActionError {
560    #[error("discover during resolve: {err}")]
561    DiscoverActionError {
562        #[from]
563        err: DiscoverActionError,
564    },
565    #[error("`{moniker}` was shut down")]
566    InstanceShutDown { moniker: Moniker },
567    #[error("`{moniker}` was destroyed")]
568    InstanceDestroyed { moniker: Moniker },
569    #[error("could not parse component address for `{url}` at `{moniker}`:\n\t{err}")]
570    ComponentAddressParseError {
571        url: Url,
572        moniker: Moniker,
573        #[source]
574        err: ResolverError,
575    },
576    #[error("resolve failed for `{url}`:\n\t{err}")]
577    ResolverError {
578        url: Url,
579        #[source]
580        err: ResolverError,
581    },
582    #[error("expose dir for `{moniker}`:\n\t{err}")]
583    // TODO(https://fxbug.dev/42071713): Determine whether this is expected to fail.
584    ExposeDirError {
585        moniker: Moniker,
586
587        #[source]
588        err: VfsError,
589    },
590    #[error("adding static child `{child_name}`:\n\t{err}")]
591    AddStaticChildError {
592        child_name: String,
593        #[source]
594        err: AddChildError,
595    },
596    #[error("structured config: {err}")]
597    StructuredConfigError {
598        #[from]
599        err: StructuredConfigError,
600    },
601    #[error("creating package dir proxy: {err}")]
602    PackageDirProxyCreateError {
603        #[source]
604        err: fidl::Error,
605    },
606    #[error("ABI compatibility check for `{url}`: {err}")]
607    AbiCompatibilityError {
608        url: Url,
609        #[source]
610        err: CompatibilityCheckError,
611    },
612    #[error(transparent)]
613    Policy(#[from] PolicyError),
614    #[error("`{moniker}` was interrupted")]
615    Aborted { moniker: Moniker },
616}
617
618impl ResolveActionError {
619    fn as_zx_status(&self) -> zx::Status {
620        match self {
621            ResolveActionError::DiscoverActionError { .. }
622            | ResolveActionError::InstanceShutDown { .. }
623            | ResolveActionError::InstanceDestroyed { .. }
624            | ResolveActionError::ComponentAddressParseError { .. }
625            | ResolveActionError::AbiCompatibilityError { .. } => zx::Status::NOT_FOUND,
626            ResolveActionError::ExposeDirError { .. }
627            | ResolveActionError::AddStaticChildError { .. }
628            | ResolveActionError::StructuredConfigError { .. }
629            | ResolveActionError::Aborted { .. }
630            | ResolveActionError::PackageDirProxyCreateError { .. } => zx::Status::INTERNAL,
631            ResolveActionError::ResolverError { err, .. } => err.as_zx_status(),
632            ResolveActionError::Policy(err) => err.as_zx_status(),
633        }
634    }
635}
636
637// This is implemented for fuchsia.sys2.LifecycleController protocol
638impl Into<fsys::ResolveError> for ResolveActionError {
639    fn into(self) -> fsys::ResolveError {
640        match self {
641            ResolveActionError::ResolverError {
642                err: ResolverError::PackageNotFound(_), ..
643            } => fsys::ResolveError::PackageNotFound,
644            ResolveActionError::ResolverError {
645                err: ResolverError::ManifestNotFound(_), ..
646            } => fsys::ResolveError::ManifestNotFound,
647            ResolveActionError::InstanceShutDown { .. }
648            | ResolveActionError::InstanceDestroyed { .. } => fsys::ResolveError::InstanceNotFound,
649            ResolveActionError::ExposeDirError { .. }
650            | ResolveActionError::ResolverError { .. }
651            | ResolveActionError::StructuredConfigError { .. }
652            | ResolveActionError::ComponentAddressParseError { .. }
653            | ResolveActionError::AddStaticChildError { .. }
654            | ResolveActionError::DiscoverActionError { .. }
655            | ResolveActionError::AbiCompatibilityError { .. }
656            | ResolveActionError::Aborted { .. }
657            | ResolveActionError::PackageDirProxyCreateError { .. } => fsys::ResolveError::Internal,
658            ResolveActionError::Policy(_) => fsys::ResolveError::PolicyError,
659        }
660    }
661}
662
663// This is implemented for fuchsia.sys2.LifecycleController protocol.
664// Starting a component instance also causes a resolve.
665impl Into<fsys::StartError> for ResolveActionError {
666    fn into(self) -> fsys::StartError {
667        match self {
668            ResolveActionError::ResolverError {
669                err: ResolverError::PackageNotFound(_), ..
670            } => fsys::StartError::PackageNotFound,
671            ResolveActionError::ResolverError {
672                err: ResolverError::ManifestNotFound(_), ..
673            } => fsys::StartError::ManifestNotFound,
674            ResolveActionError::InstanceShutDown { .. }
675            | ResolveActionError::InstanceDestroyed { .. } => fsys::StartError::InstanceNotFound,
676            ResolveActionError::ExposeDirError { .. }
677            | ResolveActionError::ResolverError { .. }
678            | ResolveActionError::StructuredConfigError { .. }
679            | ResolveActionError::ComponentAddressParseError { .. }
680            | ResolveActionError::AddStaticChildError { .. }
681            | ResolveActionError::DiscoverActionError { .. }
682            | ResolveActionError::AbiCompatibilityError { .. }
683            | ResolveActionError::Aborted { .. }
684            | ResolveActionError::PackageDirProxyCreateError { .. } => fsys::StartError::Internal,
685            ResolveActionError::Policy(_) => fsys::StartError::PolicyError,
686        }
687    }
688}
689
690#[derive(Debug, Clone, Error)]
691pub enum PkgDirError {
692    #[error("no pkg dir found for component")]
693    NoPkgDir,
694    #[error("opening pkg dir failed: {err}")]
695    OpenFailed {
696        #[from]
697        err: zx::Status,
698    },
699}
700
701impl PkgDirError {
702    fn as_zx_status(&self) -> zx::Status {
703        match self {
704            Self::NoPkgDir => zx::Status::NOT_FOUND,
705            Self::OpenFailed { err } => *err,
706        }
707    }
708}
709
710#[derive(Debug, Clone, Error)]
711pub enum ComponentProviderError {
712    #[error("starting source instance:\n\t{err}")]
713    SourceStartError {
714        #[from]
715        err: ActionError,
716    },
717    #[error("opening source instance's outgoing dir:\n\t{err}")]
718    OpenOutgoingDirError {
719        #[from]
720        err: OpenOutgoingDirError,
721    },
722}
723
724impl ComponentProviderError {
725    pub fn as_zx_status(&self) -> zx::Status {
726        match self {
727            Self::SourceStartError { err } => err.as_zx_status(),
728            Self::OpenOutgoingDirError { err } => err.as_zx_status(),
729        }
730    }
731}
732
733#[derive(Debug, Clone, Error)]
734pub enum CapabilityProviderError {
735    #[error("bad path")]
736    BadPath,
737    #[error(transparent)]
738    ComponentInstanceError {
739        #[from]
740        err: ComponentInstanceError,
741    },
742    #[error(transparent)]
743    PkgDirError {
744        #[from]
745        err: PkgDirError,
746    },
747    #[error("event source: {0}")]
748    EventSourceError(#[from] EventSourceError),
749    #[error(transparent)]
750    ComponentProviderError {
751        #[from]
752        err: ComponentProviderError,
753    },
754    #[error("component_manager namespace: {err}")]
755    CmNamespaceError {
756        #[from]
757        err: ClonableError,
758    },
759    #[error("router: {err}")]
760    RouterError {
761        #[from]
762        err: RouterError,
763    },
764    #[error(transparent)]
765    RoutingError(#[from] RoutingError),
766    #[error("opening vfs failed: {0}")]
767    VfsOpenError(#[source] zx::Status),
768}
769
770impl CapabilityProviderError {
771    pub fn as_zx_status(&self) -> zx::Status {
772        match self {
773            Self::BadPath => zx::Status::INVALID_ARGS,
774            Self::ComponentInstanceError { err } => err.as_zx_status(),
775            Self::CmNamespaceError { .. } => zx::Status::INTERNAL,
776            Self::PkgDirError { err } => err.as_zx_status(),
777            Self::EventSourceError(err) => err.as_zx_status(),
778            Self::ComponentProviderError { err } => err.as_zx_status(),
779            Self::RouterError { err } => err.as_zx_status(),
780            Self::RoutingError(err) => err.as_zx_status(),
781            Self::VfsOpenError(err) => *err,
782        }
783    }
784}
785
786#[derive(Debug, Clone, Error)]
787pub enum OpenError {
788    #[error("failed to get default capability provider: {err}")]
789    GetDefaultProviderError {
790        // TODO(https://fxbug.dev/42068065): This will get fixed when we untangle ModelError
791        #[source]
792        err: Box<ModelError>,
793    },
794    #[error("no capability provider found")]
795    CapabilityProviderNotFound,
796    #[error("capability provider: {err}")]
797    CapabilityProviderError {
798        #[from]
799        err: CapabilityProviderError,
800    },
801    #[error("opening storage capability: {err}")]
802    OpenStorageError {
803        // TODO(https://fxbug.dev/42068065): This will get fixed when we untangle ModelError
804        #[source]
805        err: Box<ModelError>,
806    },
807    #[error("timed out opening capability")]
808    Timeout,
809    #[error("invalid path found")]
810    BadPath,
811    #[error("capability does not support opening: {0}")]
812    DoesNotSupportOpen(ConversionError),
813    #[error("failed to create directory watcher: {err}")]
814    WatcherCreateError {
815        #[from]
816        err: WatcherCreateError,
817    },
818}
819
820impl Explain for OpenError {
821    fn as_zx_status(&self) -> zx::Status {
822        match self {
823            Self::GetDefaultProviderError { err } => err.as_zx_status(),
824            Self::OpenStorageError { err } => err.as_zx_status(),
825            Self::CapabilityProviderError { err } => err.as_zx_status(),
826            Self::CapabilityProviderNotFound => zx::Status::NOT_FOUND,
827            Self::Timeout => zx::Status::TIMED_OUT,
828            Self::BadPath => zx::Status::BAD_PATH,
829            Self::DoesNotSupportOpen(_) => zx::Status::NOT_SUPPORTED,
830            Self::WatcherCreateError { err: WatcherCreateError::SendWatchRequest(_err) } => {
831                zx::Status::PEER_CLOSED
832            }
833            Self::WatcherCreateError { err: WatcherCreateError::WatchError(status) } => *status,
834            Self::WatcherCreateError { err: WatcherCreateError::ChannelConversion(status) } => {
835                *status
836            }
837        }
838    }
839}
840
841impl From<OpenError> for RouterError {
842    fn from(value: OpenError) -> Self {
843        Self::NotFound(Arc::new(value))
844    }
845}
846
847#[derive(Debug, Clone, Error)]
848pub enum StartActionError {
849    #[error("`{moniker}` was shut down")]
850    InstanceShutDown { moniker: Moniker },
851    #[error("`{moniker}` was destroyed")]
852    InstanceDestroyed { moniker: Moniker },
853    #[error("`{moniker}` couldn't resolve during start: {err}")]
854    ResolveActionError {
855        moniker: Moniker,
856        #[source]
857        err: Box<ActionError>,
858    },
859    #[error("runner for `{moniker}` `{runner}` couldn't resolve: {err}")]
860    ResolveRunnerError {
861        moniker: Moniker,
862        runner: Name,
863        #[source]
864        err: Box<RouterError>,
865    },
866    #[error(
867        "`{moniker}` uses `\"on_terminate\": \"reboot\"` but is disallowed by policy:\n\t{err}"
868    )]
869    RebootOnTerminateForbidden {
870        moniker: Moniker,
871        #[source]
872        err: PolicyError,
873    },
874    #[error("creating program input dictionary for `{moniker}`")]
875    InputDictionaryError { moniker: Moniker },
876    #[error("creating namespace: {0}")]
877    CreateNamespaceError(#[from] CreateNamespaceError),
878    #[error("starting program for `{moniker}`: {err}")]
879    StartProgramError {
880        moniker: Moniker,
881        #[source]
882        err: StartError,
883    },
884    #[error("structured configuration for `{moniker}`: {err}")]
885    StructuredConfigError {
886        moniker: Moniker,
887        #[source]
888        err: StructuredConfigError,
889    },
890    #[error("starting eager child of `{moniker}`: {err}")]
891    EagerStartError {
892        moniker: Moniker,
893        #[source]
894        err: Box<ActionError>,
895    },
896    #[error("`{moniker}` was interrupted")]
897    Aborted { moniker: Moniker },
898}
899
900impl StartActionError {
901    fn as_zx_status(&self) -> zx::Status {
902        match self {
903            StartActionError::InstanceDestroyed { .. } | Self::InstanceShutDown { .. } => {
904                zx::Status::NOT_FOUND
905            }
906            StartActionError::StartProgramError { .. }
907            | StartActionError::StructuredConfigError { .. }
908            | StartActionError::EagerStartError { .. } => zx::Status::INTERNAL,
909            StartActionError::RebootOnTerminateForbidden { err, .. } => err.as_zx_status(),
910            StartActionError::ResolveRunnerError { err, .. } => err.as_zx_status(),
911            StartActionError::CreateNamespaceError(err) => err.as_zx_status(),
912            StartActionError::InputDictionaryError { .. } => zx::Status::NOT_FOUND,
913            StartActionError::ResolveActionError { err, .. } => err.as_zx_status(),
914            StartActionError::Aborted { .. } => zx::Status::NOT_FOUND,
915        }
916    }
917}
918
919// This is implemented for fuchsia.sys2.LifecycleController protocol.
920impl Into<fsys::StartError> for StartActionError {
921    fn into(self) -> fsys::StartError {
922        match self {
923            StartActionError::ResolveActionError { err, .. } => (*err).into(),
924            StartActionError::InstanceDestroyed { .. } => fsys::StartError::InstanceNotFound,
925            StartActionError::InstanceShutDown { .. } => fsys::StartError::InstanceNotFound,
926            _ => fsys::StartError::Internal,
927        }
928    }
929}
930
931// This is implemented for fuchsia.component.Realm protocol.
932impl Into<fcomponent::Error> for StartActionError {
933    fn into(self) -> fcomponent::Error {
934        match self {
935            StartActionError::ResolveActionError { .. } => fcomponent::Error::InstanceCannotResolve,
936            StartActionError::RebootOnTerminateForbidden { .. } => fcomponent::Error::AccessDenied,
937            StartActionError::InstanceShutDown { .. } => fcomponent::Error::InstanceDied,
938            StartActionError::InstanceDestroyed { .. } => fcomponent::Error::InstanceDied,
939            _ => fcomponent::Error::InstanceCannotStart,
940        }
941    }
942}
943
944#[derive(Debug, Clone, Error)]
945pub enum StopActionError {
946    #[error("stopping program: {0}")]
947    ProgramStopError(#[source] StopError),
948    #[error("failed to get top instance")]
949    GetTopInstanceFailed,
950    #[error("failed to get parent instance")]
951    GetParentFailed,
952    #[error("failed to destroy dynamic children: {err}")]
953    DestroyDynamicChildrenFailed { err: Box<ActionError> },
954    #[error("resolution during stop: {err}")]
955    ResolveActionError {
956        #[source]
957        err: Box<ActionError>,
958    },
959    #[error("started while shutdown was ongoing")]
960    ComponentStartedDuringShutdown,
961}
962
963// This is implemented for fuchsia.sys2.LifecycleController protocol.
964impl Into<fsys::StopError> for StopActionError {
965    fn into(self) -> fsys::StopError {
966        fsys::StopError::Internal
967    }
968}
969
970impl Into<fcomponent::Error> for StopActionError {
971    fn into(self) -> fcomponent::Error {
972        fcomponent::Error::Internal
973    }
974}
975
976#[cfg(test)]
977impl PartialEq for StopActionError {
978    fn eq(&self, other: &Self) -> bool {
979        match (self, other) {
980            (StopActionError::ProgramStopError(_), StopActionError::ProgramStopError(_)) => true,
981            (StopActionError::GetTopInstanceFailed, StopActionError::GetTopInstanceFailed) => true,
982            (StopActionError::GetParentFailed, StopActionError::GetParentFailed) => true,
983            (
984                StopActionError::DestroyDynamicChildrenFailed { .. },
985                StopActionError::DestroyDynamicChildrenFailed { .. },
986            ) => true,
987            (
988                StopActionError::ResolveActionError { .. },
989                StopActionError::ResolveActionError { .. },
990            ) => true,
991            _ => false,
992        }
993    }
994}
995
996#[derive(Debug, Clone, Error)]
997pub enum ShutdownActionError {
998    #[error("child name invalid: {}", err)]
999    InvalidChildName {
1000        #[from]
1001        err: MonikerError,
1002    },
1003    #[error("cycles detected in graph")]
1004    CyclesDetected {},
1005}
1006
1007#[derive(Debug, Clone, Error)]
1008pub enum DestroyActionError {
1009    #[error("discover during destroy: {}", err)]
1010    DiscoverActionError {
1011        #[from]
1012        err: DiscoverActionError,
1013    },
1014    #[error("shutdown during destroy: {}", err)]
1015    ShutdownFailed {
1016        #[source]
1017        err: Box<ActionError>,
1018    },
1019    #[error("could not find `{moniker}`")]
1020    InstanceNotFound { moniker: Moniker },
1021    #[error("`{moniker}` is not resolved")]
1022    InstanceNotResolved { moniker: Moniker },
1023}
1024
1025// This is implemented for fuchsia.component.Realm protocol.
1026impl Into<fcomponent::Error> for DestroyActionError {
1027    fn into(self) -> fcomponent::Error {
1028        match self {
1029            DestroyActionError::InstanceNotFound { .. } => fcomponent::Error::InstanceNotFound,
1030            _ => fcomponent::Error::Internal,
1031        }
1032    }
1033}
1034
1035// This is implemented for fuchsia.sys2.LifecycleController protocol.
1036impl Into<fsys::DestroyError> for DestroyActionError {
1037    fn into(self) -> fsys::DestroyError {
1038        match self {
1039            DestroyActionError::InstanceNotFound { .. } => fsys::DestroyError::InstanceNotFound,
1040            DestroyActionError::InstanceNotResolved { .. } => {
1041                fsys::DestroyError::InstanceNotResolved
1042            }
1043            _ => fsys::DestroyError::Internal,
1044        }
1045    }
1046}
1047
1048#[derive(Debug, Clone, Error)]
1049pub enum UnresolveActionError {
1050    #[error("shutdown during unresolve: {err}")]
1051    ShutdownFailed {
1052        #[from]
1053        err: StopActionError,
1054    },
1055    #[error("`{moniker}` cannot be unresolved while it is running")]
1056    InstanceRunning { moniker: Moniker },
1057    #[error("`{moniker}` was destroyed")]
1058    InstanceDestroyed { moniker: Moniker },
1059}
1060
1061// This is implemented for fuchsia.sys2.LifecycleController protocol.
1062impl Into<fsys::UnresolveError> for UnresolveActionError {
1063    fn into(self) -> fsys::UnresolveError {
1064        match self {
1065            UnresolveActionError::InstanceDestroyed { .. } => {
1066                fsys::UnresolveError::InstanceNotFound
1067            }
1068            _ => fsys::UnresolveError::Internal,
1069        }
1070    }
1071}
1072
1073#[derive(Debug, Clone, Error)]
1074pub enum CreateNamespaceError {
1075    #[error("failed to clone pkg dir for {moniker}: {err}")]
1076    ClonePkgDirFailed {
1077        moniker: Moniker,
1078        #[source]
1079        err: fuchsia_fs::node::CloneError,
1080    },
1081
1082    #[error("use decl without path cannot be installed into the namespace for {moniker}: {decl:?}")]
1083    UseDeclWithoutPath { moniker: Moniker, decl: UseDecl },
1084
1085    #[error("instance not in index: {0}")]
1086    InstanceNotInInstanceIdIndex(#[from] RoutingError),
1087
1088    #[error("building namespace for {moniker}: {err}")]
1089    BuildNamespaceError {
1090        moniker: Moniker,
1091        #[source]
1092        err: serve_processargs::BuildNamespaceError,
1093    },
1094
1095    #[error("failed to convert namespace into directory for {moniker}: {err}")]
1096    ConvertToDirectory {
1097        moniker: Moniker,
1098        #[source]
1099        err: ClonableError,
1100    },
1101
1102    #[error(transparent)]
1103    ComponentInstanceError(#[from] ComponentInstanceError),
1104}
1105
1106impl CreateNamespaceError {
1107    fn as_zx_status(&self) -> zx::Status {
1108        match self {
1109            Self::ClonePkgDirFailed { .. } => zx::Status::INTERNAL,
1110            Self::UseDeclWithoutPath { .. } => zx::Status::NOT_FOUND,
1111            Self::InstanceNotInInstanceIdIndex(err) => err.as_zx_status(),
1112            Self::BuildNamespaceError { .. } => zx::Status::NOT_FOUND,
1113            Self::ConvertToDirectory { .. } => zx::Status::INTERNAL,
1114            Self::ComponentInstanceError(err) => err.as_zx_status(),
1115        }
1116    }
1117}
1118
1119#[derive(Debug, Clone, Error)]
1120pub enum EventSourceError {
1121    #[error(transparent)]
1122    ComponentInstance(#[from] ComponentInstanceError),
1123    #[error(transparent)]
1124    // TODO(https://fxbug.dev/42068065): This will get fixed when we untangle ModelError
1125    Model(#[from] Box<ModelError>),
1126    #[error("event stream already consumed")]
1127    AlreadyConsumed,
1128}
1129
1130impl EventSourceError {
1131    fn as_zx_status(&self) -> zx::Status {
1132        match self {
1133            Self::ComponentInstance(err) => err.as_zx_status(),
1134            Self::Model(err) => err.as_zx_status(),
1135            Self::AlreadyConsumed => zx::Status::INTERNAL,
1136        }
1137    }
1138}
1139
1140#[derive(Debug, Error, Clone)]
1141pub enum EventsError {
1142    #[error("capability_requested event streams cannot be taken twice")]
1143    CapabilityRequestedStreamTaken,
1144
1145    #[error("model not available")]
1146    ModelNotAvailable,
1147
1148    #[error("instance shut down")]
1149    InstanceShutdown,
1150
1151    #[error("instance destroyed")]
1152    InstanceDestroyed,
1153
1154    #[error("registry not found")]
1155    RegistryNotFound,
1156
1157    #[error("event `{event_name}` appears more than once in a subscription request")]
1158    DuplicateEvent { event_name: Name },
1159
1160    #[error("events not available for subscription: `{names:?}`")]
1161    NotAvailable { names: Vec<Name> },
1162}
1163
1164impl EventsError {
1165    pub fn duplicate_event(event_name: Name) -> Self {
1166        Self::DuplicateEvent { event_name }
1167    }
1168
1169    pub fn not_available(names: Vec<Name>) -> Self {
1170        Self::NotAvailable { names }
1171    }
1172}
1173
1174/// Errors related to isolated storage.
1175#[derive(Debug, Error, Clone)]
1176pub enum StorageError {
1177    #[error("opening directory from `{dir_source_moniker:?}` at `{dir_source_path}`:\n\t{err}")]
1178    OpenRoot {
1179        dir_source_moniker: Option<Moniker>,
1180        dir_source_path: cm_types::Path,
1181        #[source]
1182        err: ClonableError,
1183    },
1184    #[error(
1185        "opening isolated storage from `{dir_source_moniker:?}`'s for `{moniker}` at `{dir_source_path}` (instance_id={instance_id:?}):\n\t{err}"
1186    )]
1187    Open {
1188        dir_source_moniker: Option<Moniker>,
1189        dir_source_path: cm_types::Path,
1190        moniker: Moniker,
1191        instance_id: Option<InstanceId>,
1192        #[source]
1193        err: ClonableError,
1194    },
1195    #[error(
1196        "opening isolated storage from `{dir_source_moniker:?}` at `{dir_source_path}` for {instance_id}:\n\t{err}"
1197    )]
1198    OpenById {
1199        dir_source_moniker: Option<Moniker>,
1200        dir_source_path: cm_types::Path,
1201        instance_id: InstanceId,
1202        #[source]
1203        err: ClonableError,
1204    },
1205    #[error(
1206        "removing isolated storage from {dir_source_moniker:?} at `{dir_source_path}` for `{moniker}` (instance_id={instance_id:?}):n\t{err} "
1207    )]
1208    Remove {
1209        dir_source_moniker: Option<Moniker>,
1210        dir_source_path: cm_types::Path,
1211        moniker: Moniker,
1212        instance_id: Option<InstanceId>,
1213        #[source]
1214        err: ClonableError,
1215    },
1216    #[error("storage path for `{moniker}` (instance_id={instance_id:?}) is invalid")]
1217    InvalidStoragePath { moniker: Moniker, instance_id: Option<InstanceId> },
1218}
1219
1220impl StorageError {
1221    pub fn open_root(
1222        dir_source_moniker: Option<Moniker>,
1223        dir_source_path: cm_types::Path,
1224        err: impl Into<Error>,
1225    ) -> Self {
1226        Self::OpenRoot { dir_source_moniker, dir_source_path, err: err.into().into() }
1227    }
1228
1229    pub fn open(
1230        dir_source_moniker: Option<Moniker>,
1231        dir_source_path: cm_types::Path,
1232        moniker: Moniker,
1233        instance_id: Option<InstanceId>,
1234        err: impl Into<Error>,
1235    ) -> Self {
1236        Self::Open {
1237            dir_source_moniker,
1238            dir_source_path,
1239            moniker,
1240            instance_id,
1241            err: err.into().into(),
1242        }
1243    }
1244
1245    pub fn open_by_id(
1246        dir_source_moniker: Option<Moniker>,
1247        dir_source_path: cm_types::Path,
1248        instance_id: InstanceId,
1249        err: impl Into<Error>,
1250    ) -> Self {
1251        Self::OpenById { dir_source_moniker, dir_source_path, instance_id, err: err.into().into() }
1252    }
1253
1254    pub fn remove(
1255        dir_source_moniker: Option<Moniker>,
1256        dir_source_path: cm_types::Path,
1257        moniker: Moniker,
1258        instance_id: Option<InstanceId>,
1259        err: impl Into<Error>,
1260    ) -> Self {
1261        Self::Remove {
1262            dir_source_moniker,
1263            dir_source_path,
1264            moniker,
1265            instance_id,
1266            err: err.into().into(),
1267        }
1268    }
1269
1270    pub fn invalid_storage_path(moniker: Moniker, instance_id: Option<InstanceId>) -> Self {
1271        Self::InvalidStoragePath { moniker, instance_id }
1272    }
1273}
1274
1275#[derive(Error, Debug, Clone)]
1276pub enum StartError {
1277    #[error("serving namespace: {0}")]
1278    ServeNamespace(BuildNamespaceError),
1279}
1280
1281#[derive(Error, Debug, Clone)]
1282pub enum StopError {
1283    /// Internal errors are not meant to be meaningfully handled by the user.
1284    #[error("internal: {0}")]
1285    Internal(fidl::Error),
1286}