App access to /tmp

Hiya,

Is it possible for an app to get read and write access to the /tmp directory to store intermediate and volatile data files?

I’ve tried require:'ing the /tmp directory into my app in the adef file - both as sandboxed and unsandboxed.

I’ve also tried simply creating a file in /tmp as an unsandboxed application.

Nether method wrote to the system /tmp directory - they all seemed to create a tmp directory in the application’s /legato/…/appWritable/application/ directory (same place as bin, dev, lib etc are created.

Questions:

  1. is it possible for an app to write to the system /tmp area? If so, how?
  2. I can’t use the legato created tmp directory as it goes away if the application stops and restarts. Is there any other volatile file storage on the module that an app can write to?

ciao, Dave

Hi Dave,

May I ask which Legato/product you are using?

In my case, I can read/write to /tmp/test.txt whenever app is not run inside sandbox, as expected I don’t even need to specify in requires section.

Thx

Hi Lotam,

I’ve been testing against a WP7702 with Legato 18.05.1 installed.

I was also somewhat confused about not being able to write to /tmp in an unsandboxed app.

Quite literally, all my code does is the following:

#include "legato.h"
#include "interfaces.h"	/* include auto-generated api interfaces from Component.cdef */


COMPONENT_INIT
{
    LE_INFO( "tmpDirTest Init: Enter" );

    char template[128] = { 0 };
    int fd = -1;
    
    sprintf(template, "/tmp/mytmpXXXXXX");
    
    if ( -1 == (fd = mkstemp(template)) )
    {
        LE_WARN("mkstemp failed [%d:%m]", errno );
    }
    else
    {
        LE_INFO( "Opened [%s] as fd[%d]", template, fd );
        
        close( fd );
    }

    LE_INFO( "tmpDirTest Init: Exit" );
    
}

Can’t be much simpler than this …

But unsandboxed or not, it never creates the file in /tmp … but only in the app local tmp folder.

ciao, Dave

Hi Dave,

Thanks for the code snippet.
It works quite well on my WP77 18.05.1 as I marked “sandboxed: false” in .adef.

Below the .adef and test log:

executables:
{
helloWorld = ( helloComponent )
}

processes:
{
envVars:
{
LE_LOG_LEVEL = DEBUG
}

run:
{
    ( helloWorld )
}

}
sandboxed: false
start: manual

Test log:

root@swi-mdm9x28:~# legato version
18.05.1_aad562713e05df40ebc4a49c57fa8e97
root@swi-mdm9x28:~# ls -l /tmp/
drwx-----x 2 root root 120 Jan 6 00:37 legato
drwx------ 2 root root 80 Jan 6 00:37 pkgdwl
drw-r–r-- 2 root root 60 Jan 6 00:37 psm_socket
srwx------ 1 root root 0 Jan 6 00:37 sock0
srwxr-xr-x 1 root root 0 Jan 6 00:37 thermal_engi_ipc
root@swi-mdm9x28:~# logread -f &
root@swi-mdm9x28:~# app start helloWorld
root@swi-mdm9x28:~# Jan 6 00:39:25 swi-mdm9x28 user.info Legato: INFO | supervisor[699]/supervisor T=main | app.c app_Create() 2716 | Creating app ‘helloWorld’
Jan 6 00:39:25 swi-mdm9x28 user.info Legato: INFO | supervisor[699]/supervisor T=main | proc.c GetFaultAction() 323 | No fault action specified for process ‘helloWorld’. Assuming ‘ignore’.
Jan 6 00:39:25 swi-mdm9x28 user.warn Legato: -WRN- | supervisor[699]/supervisor T=main | proc.c GetWatchdogAction() 359 | helloWorld watchdogAction ‘’ in proc section
Jan 6 00:39:25 swi-mdm9x28 user.warn Legato: -WRN- | supervisor[699]/supervisor T=main | proc.c GetWatchdogAction() 359 | helloWorld watchdogAction ‘’ in proc section
Jan 6 00:39:25 swi-mdm9x28 user.info Legato: INFO | supervisor[699]/supervisor T=main | app.c CreateFileLink() 1605 | Created file link ‘/legato/systems/current/apps/helloWorld/read-only/lib/libComponent_helloComponent.so’ to '/legato/systems/current/appsWriteable/helloW
Jan 6 00:39:25 swi-mdm9x28 user.info Legato: INFO | supervisor[699]/supervisor T=main | app.c CreateFileLink() 1605 | Created file link ‘/legato/systems/current/apps/helloWorld/read-only/bin/helloWorld’ to ‘/legato/systems/current/appsWriteable/helloWorld/bin/helloWorld’
Jan 6 00:39:25 swi-mdm9x28 user.info Legato: INFO | supervisor[699]/supervisor T=main | app.c app_Start() 2915 | Starting app ‘helloWorld’
Jan 6 00:39:25 swi-mdm9x28 user.info Legato: INFO | supervisor[699]/supervisor T=main | resourceLimits.c SetRLimitValue() 282 | Setting resource limit maxCoreDumpFileBytes to value 102400.
Jan 6 00:39:25 swi-mdm9x28 user.info Legato: INFO | supervisor[699]/supervisor T=main | resourceLimits.c SetRLimitValue() 282 | Setting resource limit maxFileBytes to value 102400.
Jan 6 00:39:25 swi-mdm9x28 user.info Legato: INFO | supervisor[699]/supervisor T=main | resourceLimits.c SetRLimitValue() 282 | Setting resource limit maxLockedMemoryBytes to value 8192.
Jan 6 00:39:25 swi-mdm9x28 user.info Legato: INFO | supervisor[699]/supervisor T=main | resourceLimits.c SetRLimitValue() 282 | Setting resource limit maxFileDescriptors to value 256.
Jan 6 00:39:25 swi-mdm9x28 user.info Legato: INFO | supervisor[699]/supervisor T=main | resourceLimits.c SetRLimitValue() 282 | Setting resource limit maxMQueueBytes to value 512.
Jan 6 00:39:25 swi-mdm9x28 user.info Legato: INFO | supervisor[699]/supervisor T=main | resourceLimits.c SetRLimitValue() 282 | Setting resource limit maxThreads to value 20.
Jan 6 00:39:25 swi-mdm9x28 user.info Legato: INFO | supervisor[699]/supervisor T=main | resourceLimits.c SetRLimitValue() 282 | Setting resource limit maxQueuedSignals to value 100.
Jan 6 00:39:25 swi-mdm9x28 user.info Legato: INFO | supervisor[699]/supervisor T=main | proc.c proc_Start() 1389 | Starting process ‘helloWorld’ with pid 1701
Jan 6 00:39:25 swi-mdm9x28 user.info Legato: INFO | supervisor[699]/supervisor T=main | supervisor.c SigChildHandler() 783 | Reaping unconfigured child process 1700.
Jan 6 00:39:25 swi-mdm9x28 user.info Legato: INFO | supervisor[1701]/supervisor T=main | proc.c proc_Start() 1354 | Execing ‘helloWorld’
Jan 6 00:39:25 swi-mdm9x28 user.debug Legato: DBUG | UNKNOWN[1701]/framework T=unknown | LE_FILENAME InitPool() 303 | Memory pool name ‘framework.hashMap_refPathIteratorMap’ is truncated to ‘framework.hashMap_refPathIterat’
Jan 6 00:39:25 swi-mdm9x28 user.debug Legato: DBUG | UNKNOWN[1701]/framework T=main | LE_FILENAME InitPool() 303 | Memory pool name ‘framework.hashMap_refEventHandlers’ is truncated to ‘framework.hashMap_refEventHandl’
Jan 6 00:39:25 swi-mdm9x28 user.debug Legato: DBUG | UNKNOWN[1701]/framework T=main | LE_FILENAME InitPool() 303 | Memory pool name ‘framework.hashMap_refDefault Timer SafeRe’ is truncated to ‘framework.hashMap_refDefault Ti’
Jan 6 00:39:25 swi-mdm9x28 user.debug Legato: DBUG | UNKNOWN[1701]/framework T=main | LE_FILENAME InitPool() 303 | Memory pool name ‘framework.MessagingClientInterfaces’ is truncated to ‘framework.MessagingClientInterf’
Jan 6 00:39:25 swi-mdm9x28 user.debug Legato: DBUG | UNKNOWN[1701]/framework T=main | LE_FILENAME InitPool() 303 | Memory pool name ‘framework.hashMap_refHandlersRef’ is truncated to ‘framework.hashMap_refHandlersRe’
Jan 6 00:39:25 swi-mdm9x28 user.debug Legato: DBUG | UNKNOWN[1701]/framework T=main | LE_FILENAME InitPool() 303 | Memory pool name ‘framework.hashMap_MessagingServices’ is truncated to ‘framework.hashMap_MessagingServ’
Jan 6 00:39:25 swi-mdm9x28 user.debug Legato: DBUG | UNKNOWN[1701]/framework T=main | LE_FILENAME InitPool() 303 | Memory pool name ‘framework.hashMap_MessagingClients’ is truncated to ‘framework.hashMap_MessagingClie’
Jan 6 00:39:25 swi-mdm9x28 user.debug Legato: DBUG | UNKNOWN[1701]/framework T=main | LE_FILENAME InitPool() 303 | Memory pool name ‘framework.PipelineSIGCHLD-reports’ is truncated to ‘framework.PipelineSIGCHLD-repor’
Jan 6 00:39:25 swi-mdm9x28 user.debug Legato: DBUG | UNKNOWN[1701]/framework T=main | LE_FILENAME fs_Init() 838 | FS prefix path “/data/le_fs/”
Jan 6 00:39:25 swi-mdm9x28 user.debug Legato: DBUG | UNKNOWN[1701]/framework T=main | LE_FILENAME InitPool() 303 | Memory pool name ‘framework.hashMap_refFsFileRefMap’ is truncated to ‘framework.hashMap_refFsFileRefM’
Jan 6 00:39:25 swi-mdm9x28 user.debug Legato: DBUG | UNKNOWN[1701]/framework T=main | LE_FILENAME le_mem_ForceAlloc() 841 | Memory pool ‘framework.DestructorObjs’ overflowed. Expanded to 1 blocks.
Jan 6 00:39:25 swi-mdm9x28 user.debug Legato: DBUG | UNKNOWN[1701]/ T=main | _componentMain.c _helloComponent_Init() 26 | Initializing helloComponent component library.
Jan 6 00:39:25 swi-mdm9x28 user.debug Legato: DBUG | helloWorld[1701]/framework T=main | LE_FILENAME InitPool() 303 | Memory pool name ‘framework.msgs-LogControlProtocol’ is truncated to ‘framework.msgs-LogControlProtoc’
Jan 6 00:39:25 swi-mdm9x28 user.debug Legato: DBUG | helloWorld[1701]/framework T=main | LE_FILENAME le_mem_ForceAlloc() 841 | Memory pool ‘framework.SigMonitor’ overflowed. Expanded to 1 blocks.
Jan 6 00:39:25 swi-mdm9x28 user.debug Legato: DBUG | helloWorld[1701]/framework T=main | LE_FILENAME le_mem_ForceAlloc() 841 | Memory pool ‘framework.SigHandler’ overflowed. Expanded to 1 blocks.
Jan 6 00:39:25 swi-mdm9x28 user.debug Legato: DBUG | helloWorld[1701]/helloWorld_exe T=main | _main.c main() 60 | == Starting Event Processing Loop ==
Jan 6 00:39:25 swi-mdm9x28 user.info Legato: INFO | helloWorld[1701]/helloComponent T=main | helloWorld.c _helloComponent_COMPONENT_INIT() 7 | tmpDirTest Init: Enter
Jan 6 00:39:25 swi-mdm9x28 user.info Legato: INFO | helloWorld[1701]/helloComponent T=main | helloWorld.c _helloComponent_COMPONENT_INIT() 20 | Opened [/tmp/mytmpkvmjRv] as fd[8]
Jan 6 00:39:25 swi-mdm9x28 user.info Legato: INFO | helloWorld[1701]/helloComponent T=main | helloWorld.c _helloComponent_COMPONENT_INIT() 25 | tmpDirTest Init: Exit

root@swi-mdm9x28:~# ls -l /tmp
drwx-----x 2 root root 120 Jan 6 00:37 legato
-rw------- 1 root root 0 Jan 6 00:39 mytmpkvmjRv
drwx------ 2 root root 80 Jan 6 00:37 pkgdwl
drw-r–r-- 2 root root 60 Jan 6 00:37 psm_socket
srwx------ 1 root root 0 Jan 6 00:37 sock0
srwxr-xr-x 1 root root 0 Jan 6 00:37 thermal_engi_ipc
-rw-r–r-- 1 root root 534 Jan 6 00:39 tmpfdbtable.txt
root@swi-mdm9x28:~#

Hi, I’m having the same issue with sandboxed apps. If the app is not sandboxed the access to /tmp is no problem, but a sandboxed app cannot open the required file in read mode.

In the .adef

requires:
{
    dir:
    {
        /tmp /tmp
        /proc /proc
        /home /home
    }

    file:
    {
    }
}

In the component:

FILE *fp = fopen("/tmp/alive", "r");

I can see that the file exists and the content is right. However, the file-pointer is NULL.

you can see here:

Unfortunatelly, that doesn’t work, because /tmp/alive does not exist when the app tries to start and therefore, the requires condition is not fulfilled which means that the whole app cannot start properly. So I don’t even get to the point where fopen is called. Also, after the file has been created by the other app and the app which wants to read the file is restarted, the fopen command still returns null. Please try it in one of your test applications if you can access a file in /tmp from a sandboxed app.

requires:
{
    dir:
    {
        /proc /proc
        /home /home
    }

    file:
    {
        /tmp/alive /tmp/alive
    }
}
FILE *fp = fopen("/tmp/alive", "rw+");

I don’t understand why it’s not possible to just map the whole directory. That should be no problem but for some reason it seems to be. At least with /tmp.

you can create the file in the init script:

Can startlegato.sh be included into the package that is being installed via /legato/systems/current/bin/update? Because we don’t want to have to add specific files manually to the device. Also this wouldn’t solve the problem, that the file can obviously not be read.

modified startlegato.sh should be stored in /mnt/flash/ufs/etc/init.d/startlegato.sh

then why don’t you add an unsandboxed application to create the file during each power on?

We already have this kind of process. The file however, as mentioned above, cannot be accessed in read-mode for some reason. Please try it in one of your test apps. Maybe I’m doing something wrong or missed something that prevents me from accessing the file from a sandboxed app. Because I just tried it with an unsandboxed app, which works perfectly fine.

I found that you must manually enter these commands in the console instead of using unsandboxed legato app to create it:

echo hello_everybody > /tmp/hello.txt
chmod o+w /tmp/hello.txt
xattr set 'security.SMACK64' 'app.hello7rwx' /tmp/hello.txt
app start hello7

Or you can choose to use unsandboxed app to access the files outside

you can do this which is working on my side:

  1. edit /etc/init.d/startlegato.sh
case "$1" in
start)
echo "Legato start sequence 123"

echo hello_everybody > /tmp/hello.txt
  1. create a hello1 unsandboxed app to change the attribute:
system("chmod o+w /tmp/hello.txt");
system("/mnt/legato/system/bin/xattr set 'security.SMACK64' 'app.hello7rwx' /tmp/hello.txt");
  1. create another hello7 sandboxed app to read the /tmp/hello.txt

I tried this, but it still doesn’t work. fopen still keeps returning NULL. Weird.

Unsandboxed app:

/* Write alive file */
FILE *fp = fopen("/tmp/alive", "w");
if (fp)
{
    system("chmod o+w /tmp/alive");
    system("chmod o+r /tmp/alive");
    system("/mnt/legato/system/bin/xattr set 'security.SMACK64' 'app.Health' /tmp/alive");
    fputc((currentNrAppsAlive == NR_APPS) ? IPC_VALUE_APPS_ALIVE_OK : IPC_VALUE_APPS_ALIVE_NOK, fp);
    fclose(fp);
}

Sandboxed Health app:

FILE *fp = fopen("/tmp/alive", "r");

Health app .adef:

requires:
{
    dir:
    {
        /proc /proc
        /home /home
    }

    file:
    {
        /tmp/alive /tmp/alive
    }
}

image

as said before, you cannot create the file with any unsandboxed app if you want sandboxed app to access it

Yes you can. You just can’t in the /tmp directory. Just tried it with /home/root which works fine. Alright, then I will just use the home directory.

To wrap it up (if someone comes back to this thread).

  • The start attribute of the app which requires a specific file is set to manual in the .adef file.
  • The file is mapped into the sandboxed application within the .adef file (e.g. [rw] /tmp/alive /).
  • An unsandboxed app writes the file on startup and starts the application which requires the file (le_appCtrl_Start).
  • Everyone is happy that it works somehow.

Thanks for your support.


FYI:

requires:
{
    dir:
    {
        /proc /proc
        /home /home
    }

    file:
    {
        [rw] /tmp/alive /
    }
}

Throws the following error: “Cannot set access permission of: /tmp/alive”, while [rw] /home/root/alive / works as intended.


Please mark this post as solution, if you agree.

Hiya,

Just a quick note about using /home as opposed to /tmp.

Don’t forget that /tmp is a volatile partition - constructed in RAM each time the module boots, so (a) anything that’s put there probably won’t survive a cold boot; & (b) As it’s in RAM you have an effectively infinite erase/write cycles.

/home on the other hand is in flash - on the up side the data is persistent across reboots; on the down side you’ve got a limited number or erase/write cycles so if you’re using the file for rapid temporary storage purposes then you run the risk of wearing out the flash.

Another quiet issue I’ve run into previously - don’t let a flash partition fill up completely. There (used to be - haven’t checked recently) a sneaky little bug in the flash file system where the file system required at least one unused block to allow erasing of files (because of the way the file system did a read - modify - write when deleting data). Sadly, the file system didn’t automatically reserve a flash block for this purpose so you could fill up the flash and then not be able to erase it without a low level format of the entire partition.

ciao, Dave

On my side, if I change the unsandboxed application to create a file in /tmp, and then create another symbolic link in /home/root to this file, then the sandboxed application can still access this symbolic link.

	system("echo hello_everybody > /tmp/hello.txt");
	system("ln -s /tmp/hello.txt /home/root/hello.txt");
	system("chmod o+w /home/root/hello.txt");
	system("/mnt/legato/system/bin/xattr set 'security.SMACK64' 'app.hello7rwx' /home/root/hello.txt");

So it seems we can still create the file in /tmp folder and use sandboxed application to access it.

hello7.adef:


sandboxed:true
start: manual
requires:
{
   
    file:
	{
		
	[rw]   /home/root/hello.txt /
	
	}
}

Hey davidc,

thanks for the follow-up. Yes, that was the purpose, the file should be deleted each time the device is rebootet. However, the flash’s write-erase cycles are a good point to consider. I’ll try to either reduce the write cycles or, as jyijyi mentioned, try to use a symbolic link to the file.

BR
Hudri