11import type { Kernel , SpawnResult } from "../../../kernel" ;
22
33const SERVICES_DIR = "/etc/services/" ;
4+ const PRIVILEGED_SERVICES_DIR = "/etc/services/privileged/" ;
45
56interface ServiceRestartPolicyBase {
67 on : "failure" | "always" | "never" ;
@@ -27,8 +28,9 @@ interface ServiceFile {
2728// TODO: do something with name
2829// TODO: do something with max_retries
2930
30- interface ServiceFileWithId extends ServiceFile {
31+ interface ServiceFileWithExtra extends ServiceFile {
3132 id : string ;
33+ privileged : boolean ;
3234}
3335
3436const CLEAN_EXIT_CODES = new Set ( [ 0 , 143 ] ) ; // 0 = success, 143 = SIGTERM
@@ -54,7 +56,7 @@ export type ServiceStatus = ServiceStatusRunning | ServiceStatusNotRunning;
5456export class ServiceManager {
5557 readonly #kernel: Kernel ;
5658
57- readonly #service_files: Map < string , ServiceFileWithId > = new Map ( ) ;
59+ readonly #service_files: Map < string , ServiceFileWithExtra > = new Map ( ) ;
5860 readonly #running_services: Map < string , SpawnResult > = new Map ( ) ; // service ID to spawn result
5961 readonly #should_be_running_services: Set < string > = new Set ( ) ;
6062 readonly #failed_services: Set < string > = new Set ( ) ;
@@ -73,6 +75,38 @@ export class ServiceManager {
7375
7476 const service_files = await fs . list_dir ( SERVICES_DIR ) ;
7577
78+ // TODO: DRY
79+
80+ let privileged_service_files : string [ ] | null = null ;
81+ if ( await fs . exists ( PRIVILEGED_SERVICES_DIR ) ) {
82+ privileged_service_files = await fs . list_dir ( PRIVILEGED_SERVICES_DIR ) ;
83+
84+ for ( const file_name of privileged_service_files ) {
85+ if ( file_name . endsWith ( ".service.json" ) ) {
86+ const file_path = fs . join ( PRIVILEGED_SERVICES_DIR , file_name ) ;
87+ const file_content = await fs . read_file ( file_path ) as string ;
88+
89+ try {
90+ const service_data = JSON . parse ( file_content ) as ServiceFile ;
91+ const service_id = file_name . substring ( 0 , file_name . length - ".service.json" . length ) ;
92+
93+ // TODO: validate service_data here
94+
95+ const service : ServiceFileWithExtra = {
96+ id : service_id ,
97+ ...service_data ,
98+ privileged : true
99+ } ;
100+
101+ // add or update service file
102+ this . #service_files. set ( service_id , service ) ;
103+ } catch ( e ) {
104+ console . error ( `Failed to parse service file ${ file_name } :` , e ) ;
105+ }
106+ }
107+ }
108+ }
109+
76110 // load each service file
77111 for ( const file_name of service_files ) {
78112 if ( file_name . endsWith ( ".service.json" ) ) {
@@ -83,11 +117,17 @@ export class ServiceManager {
83117 const service_data = JSON . parse ( file_content ) as ServiceFile ;
84118 const service_id = file_name . substring ( 0 , file_name . length - ".service.json" . length ) ;
85119
120+ if ( "privileged" in service_data ) {
121+ // dont let them try to bypass it by putting privileged in the service file
122+ delete service_data . privileged ;
123+ }
124+
86125 // TODO: validate service_data here
87126
88- const service : ServiceFileWithId = {
127+ const service : ServiceFileWithExtra = {
89128 id : service_id ,
90- ...service_data
129+ ...service_data ,
130+ privileged : false
91131 } ;
92132
93133 // add or update service file
@@ -100,7 +140,7 @@ export class ServiceManager {
100140
101141 // remove any services that no longer exist
102142 for ( const existing_service_id of this . #service_files. keys ( ) ) {
103- if ( ! service_files . includes ( existing_service_id + ".service.json" ) ) {
143+ if ( ! service_files . includes ( existing_service_id + ".service.json" ) && ! ( privileged_service_files && privileged_service_files . includes ( existing_service_id + ".service.json" ) ) ) {
104144 this . #service_files. delete ( existing_service_id ) ;
105145 }
106146 }
@@ -111,6 +151,8 @@ export class ServiceManager {
111151 const temp_mark : Set < string > = new Set ( ) ;
112152 const result : string [ ] = [ ] ;
113153
154+ // TODO: should privileged have priority?
155+
114156 const visit = ( service_id : string ) => {
115157 if ( visited . has ( service_id ) ) {
116158 return ;
@@ -166,7 +208,7 @@ export class ServiceManager {
166208
167209 let spawn_result : SpawnResult ;
168210 try {
169- spawn_result = this . #kernel. spawn ( service . exec , service . args || [ ] ) ;
211+ spawn_result = this . #kernel. spawn ( service . exec , service . args || [ ] , undefined , service . privileged ) ;
170212 } catch ( e ) {
171213 console . error ( `Failed to start service ${ service_id } :` , e ) ;
172214 return ;
0 commit comments