Skip to main content

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