KasperskyOS Community Edition 1.1
[Topic sc_application_start]

Overview: Einit and init.yaml

Einit initializing program

At startup, the KasperskyOS kernel finds the executable file named Einit (initializing program) in the solution image and runs this executable file. The running process has the Einit class and is normally used to start all other processes that are required when the solution is started.

Generating the C-code of the initializing program

The KasperskyOS Community Edition toolkit includes the einit tool, which lets you generate the C-code of the initializing program based on the init description (the description file is normally named init.yaml). The obtained program uses the KasperskyOS API to do the following:

  • Statically create and run processes.
  • Statically create IPC channels.

The standard way of using the einit tool is to integrate an einit call into one of the steps of the build script. As a result, the einit tool uses the init.yaml file to generate the einit.c file containing the code of the initializing program. In one of the following steps of the build script, you must compile the einit.c file into the executable file of Einit and include it into the solution image.

You are not required to create static description files for the initializing program. These files are included in the KasperskyOS Community Edition toolkit and are automatically connected during a solution build. However, the Einit process class must be described in the security.psl file.

Syntax of init.yaml

An init description contains data in YAML format. This data identifies the following:

  • Processes that are started when KasperskyOS is loaded.
  • IPC channels that are used by processes to interact with each other.

This data consists of a dictionary with the entities key containing a list of dictionaries of processes. Process dictionary keys are presented in the table below.

Process dictionary keys in an init description

Key

Required

Value

name

Yes

Process security class

task

No

Process name. If this name is not specified, the security class name will be used. Each process must have a unique name.

You can start multiple processes of the same security class if they have different names.

path

No

Name of the executable file in ROMFS (in the solution image) from which the process will be started. If this name is not specified, the security class name (without prefixes and dots) will be used. For example, processes of the Client and net.Client security classes for which an executable file name is not specified will be started from the Client file.

You can start multiple processes from the same executable file.

connections

No

Process IPC channel dictionaries list. This list defines the statically created IPC channels whose client handles will be owned by the process. The list is empty by default. (In addition to statically created IPC channels, processes can also use dynamically created IPC channels.)

args

No

List of arguments passed to the process (the main() function). The maximum size of one item on the list is 1024 bytes.

env

No

Dictionary of environment variables passed to the process. The keys in this dictionary are the names of variables mapped to the passed values. The maximum size of a value is 1024 bytes.

Process IPC channel dictionary keys are presented in the table below.

IPC channel dictionary keys in an init description

Key

Required

Value

id

Yes

IPC channel name, which can be defined as a specific value or as a link such as

{var: <constant name>, include: <path to header file>}.

target

Yes

Name of the process that will own the server handle of the IPC channel.

Page top

[Topic einit_overview]

Example init descriptions

This section contains init descriptions that demonstrate various aspects of starting processes.

Examples in KasperskyOS Community Edition may utilize a macro-containing init description format (init.yaml.in).

The file containing an init description is usually named init.yaml, but it can have any name.

Connecting and starting a client process and server process

In the next example, two processes will be started: one process of the Client class and one process of the Server class. The names of the processes are not specified, so they will match the names of their respective process classes. The names of the executable files are not specified either, so they will also match the names of their respective classes. The processes will be connected by an IPC channel named server_connection.

init.yaml

entities:

- name: Client

connections:

- target: Server

id: server_connection

- name: Server

Specifying the executable file to run

The next example will run a Client-class process from the cl executable file, a ClientServer-class process from the csr executable file, and a MainServer-class process from the msr executable file. The names of the processes are not specified, so they will match the names of their respective process classes.

init.yaml

entities:

- name: Client

path: cl

- name: ClientServer

path: csr

- name: MainServer

path: msr

Starting two processes from the same executable file

The next example will run three processes: a Client-class process from the default executable file (Client), and processes of the MainServer and BkServer classes from the srv executable file. The names of the processes are not specified, so they will match the names of their respective process classes.

init.yaml

entities:

- name: Client

- name: MainServer

path: srv

- name: BkServer

path: srv

Starting two processes of the same class

The next example will run one Client-class process (named Client by default) and two Server-class processes named UserServer and PrivilegedServer. The client process is linked to the server processes through IPC channels named server_connection_us and server_connection_ps, respectively. The names of the executable files are not specified, so they will match the names of their respective process classes.

init.yaml

entities:

- name: Client

connections:

- id: server_connection_us

target: UserServer

- id: server_connection_ps

target: PrivilegedServer

- task: UserServer

name: Server

- task: PrivilegedServer

name: Server

Passing environment variables and arguments using the main() function

The next example will run two processes: one VfsFirst-class process (named VfsFirst by default) and one VfsSecond-class process (named VfsSecond by default). At startup, the first process receives the -f /etc/fstab argument and the following environment variables: ROOTFS with the value ramdisk0,0 / ext2 0 and UNMAP_ROMFS with the value 1. At startup, the second process receives the -l devfs /dev devfs 0 argument.

The names of the executable files are not specified, so they will match the names of their respective process classes.

If the Env program is used in a solution, the arguments and environment variables passed through this program redefine the values that were defined through init.yaml.

init.yaml

entities:

- name: VfsFirst

args:

- -f

- /etc/fstab

env:

ROOTFS: ramdisk0,0 / ext2 0

UNMAP_ROMFS: 1

- name: VfsSecond

args:

- -l

- devfs /dev devfs 0

Page top
[Topic using_einit]

Starting a process using the KasperskyOS API

This example uses the EntityInitEx() and EntityRun() functions to run an executable file from the solution image.

Below is the code of the GpMgrOpenSession() function, which starts the server process, connects it to the client process and initializes IPC transport. The executable file of the new process must be contained in the ROMFS storage of the solution.

#define CONNECT_RETRY 150 /* Number of connection attempts */

#define CONNECT_DELAY 10 /* Delay (ms) between attempts */

/**

* The "classname" parameter defines the class name of the started process,

* the "server" parameter defines a unique name for the process, and the "service" parameter contains the service name

* that is used when dynamically creating a channel.

* Output parameter "transport" contains the initialized transport

* if an IPC channel to the client was successfully created.

*/

Retcode GpMgrOpenSession(const char *classname, const char *server,

const char *service, NkKosTransport *transport)

{

Retcode rc;

Entity *e;

EntityInfo tae_info;

Handle endpoint;

rtl_uint32_t riid;

int count = CONNECT_RETRY;

/* Initializes the process description structure. */

rtl_memset(&tae_info, 0, sizeof(tae_info));

tae_info.eiid = classname;

tae_info.args[0] = server;

tae_info.args[1] = service;

/* Creates a process named "server" with the tae_info description.

* The third parameter is equal to RTL_NULL, therefore the name of the started

* binary file matches the class name from the tae_info description.

* The created process is in the stopped state. */

if ((e = EntityInitEx(&tae_info, server, RTL_NULL)) == NK_NULL)

{

rtl_printf("Cannot init entity '%s'\n", tae_info.eiid);

return rcFail;

}

/* Starts the process. */

if ((rc = EntityRun(e)) != rcOk)

{

rtl_printf("Cannot launch entity %" RTL_PRId32 "\n", rc);

EntityFree(e);

return rc;

}

/* Dynamically creates an IPC channel. */

while ((rc = KnCmConnect(server, service, INFINITE_TIMEOUT, &endpoint, &riid) ==

rcResourceNotFound && count--)

{

KnSleep(CONNECT_DELAY);

}

if (rc != rcOk)

{

rtl_printf("Cannot connect to server %" RTL_PRId32 "\n", rc);

return rc;

}

/* Initializes IPC transport. */

NkKosTransport_Init(transport, endpoint, NK_NULL, 0);

...

return rcOk;

}

To enable a process to start other processes, the solution security policy must allow this process to use the following core endpoints: Handle, Task and VMM (their descriptions are in the directory kl\core\).

Page top
[Topic app_static_start]

Overview: Env program

The Env program is intended for passing arguments and environment variables to started processes. When started, each process automatically sends a request to the Env process and receives the necessary data.

A process query to Env redefines the arguments and environment variables received through Einit.

To use the Env program in your solution, you need to do the following:

1. Develop the code of the Env program by using macros from env/env.h.

2. Build the binary file of the Env program by linking it to the env_server library.

3. In the init description, indicate that the Env process must be started and connected to the selected processes (Env acts a server in this case). The channel name is defined by the ENV_SERVICE_NAME macro declared in the env/env.h file.

4. Include the Env binary file in the solution image.

Env program code

The code of the Env program utilizes the following macros and functions declared in the env/env.h file:

  • ENV_REGISTER_ARGS(name,argarr) – arguments from the argarr array are passed to the process named name (the maximum size of one element is 256 bytes).
  • ENV_REGISTER_VARS(name,envarr) – environment variables from the envarr array are passed to the process named name (the maximum size of one element is 256 bytes).
  • ENV_REGISTER_PROGRAM_ENVIRONMENT(name,argarr,envarr) – arguments and environment variables are passed to the process named name.
  • envServerRun() – initialize the server part of the Env program so that it can respond to requests.

Env usage examples

Page top

[Topic env_overview]

Passing environment variables and arguments using Env

Example of passing arguments at process startup

Below is the code of the Env program. When the process named NetVfs starts, the program passes three arguments to this process: NetVfs, -l devfs /dev devfs 0 and -l romfs /etc romfs 0:

env.c

#include <env/env.h>

#include <stdlib.h>

int main(int argc, char** argv)

{

const char* NetVfsArgs[] = {

"-l", "devfs /dev devfs 0",

"-l", "romfs /etc romfs 0"

};

ENV_REGISTER_ARGS("NetVfs", NetVfsArgs);

envServerRun();

return EXIT_SUCCESS;

}

Example of passing environment variables at process startup

Below is the code of the Env program. When the process named Vfs3 starts, the program passes two environment variables to this process: ROOTFS=ramdisk0,0 / ext2 0 and UNMAP_ROMFS=1:

env.c

#include <env/env.h>

#include <stdlib.h>

int main(int argc, char** argv)

{

const char* Vfs3Envs[] = {

"ROOTFS=ramdisk0,0 / ext2 0",

"UNMAP_ROMFS=1"

};

ENV_REGISTER_VARS("Vfs3", Vfs3Envs);

envServerRun();

return EXIT_SUCCESS;

}

Page top
[Topic using_env_app]