Private
Public Access
Prepare webOSbrew publishing audit and safe symlink autostart
This commit is contained in:
1 parent
aaa8aa82e6
commit
b81cb9a8a0
16 files changed
+185
-31
No files matched your search
+30
-22
@@ -1,28 +1,36 @@
|
||||
#ifndef HISTOGRAM_AUTOSTART_H
|
||||
#define HISTOGRAM_AUTOSTART_H
|
||||
#define BOOT_HOOK "/var/lib/webosbrew/init.d/60-histogramhyperion"
|
||||
static const char boot_script[] = "#!/bin/sh\n# Histogram Hyperion own boot hook v1\n(\n attempt=0\n while [ -x /var/lib/webosbrew/init.d/60-histogramhyperion ] && [ \"$attempt\" -lt 120 ]; do\n result=$(timeout 12 luna-send -n 1 luna://org.webosbrew.histogramhyperion.service/start '{}' 2>&1)\n case \"$result\" in\n *'\"running\":true'*) exit 0 ;;\n esac\n attempt=$((attempt + 1))\n sleep 5\n done\n echo 'Histogram Hyperion boot start cancelled or timed out'\n) >/var/lib/webosbrew/histogramhyperion-boot.log 2>&1 </dev/null &\nexit 0\n";
|
||||
static bool boot_enabled(void){return access(BOOT_HOOK,X_OK)==0;}
|
||||
static bool set_boot(bool enabled){
|
||||
struct stat st;
|
||||
if(lstat(BOOT_HOOK,&st)==0){
|
||||
if(!S_ISREG(st.st_mode))return false;
|
||||
char existing[sizeof(boot_script)];int fd=open(BOOT_HOOK,O_RDONLY|O_NOFOLLOW|O_CLOEXEC);if(fd<0)return false;
|
||||
ssize_t size=read(fd,existing,sizeof(existing));close(fd);
|
||||
if(size!=(ssize_t)(sizeof(boot_script)-1) || memcmp(existing,boot_script,(size_t)size)!=0)return false;
|
||||
if(!enabled)return unlink(BOOT_HOOK)==0;
|
||||
return chmod(BOOT_HOOK,0755)==0;
|
||||
#ifndef BOOT_DIRECTORY
|
||||
#define BOOT_DIRECTORY "/var/lib/webosbrew/init.d"
|
||||
#endif
|
||||
#ifndef BOOT_SCRIPT
|
||||
#define BOOT_SCRIPT "/media/developer/apps/usr/palm/services/org.webosbrew.histogramhyperion.service/boot.sh"
|
||||
#endif
|
||||
#define BOOT_HOOK BOOT_DIRECTORY "/60-histogramhyperion"
|
||||
/* Exact pre-0.6.1 hook; only this known own file may be migrated. */
|
||||
static const char legacy_boot_script[] = "#!/bin/sh\n# Histogram Hyperion own boot hook v1\n(\n attempt=0\n while [ -x /var/lib/webosbrew/init.d/60-histogramhyperion ] && [ \"$attempt\" -lt 120 ]; do\n result=$(timeout 12 luna-send -n 1 luna://org.webosbrew.histogramhyperion.service/start '{}' 2>&1)\n case \"$result\" in\n *'\"running\":true'*) exit 0 ;;\n esac\n attempt=$((attempt + 1))\n sleep 5\n done\n echo 'Histogram Hyperion boot start cancelled or timed out'\n) >/var/lib/webosbrew/histogramhyperion-boot.log 2>&1 </dev/null &\nexit 0\n";
|
||||
/* 0: absent, 1: own legacy copy, 2: own symlink, -1: foreign/error. */
|
||||
static int boot_hook_kind(void){
|
||||
struct stat st;if(lstat(BOOT_HOOK,&st)!=0)return errno==ENOENT?0:-1;
|
||||
if(S_ISLNK(st.st_mode)){
|
||||
char target[sizeof(BOOT_SCRIPT)+1];ssize_t n=readlink(BOOT_HOOK,target,sizeof(target));
|
||||
return n==(ssize_t)(sizeof(BOOT_SCRIPT)-1) && memcmp(target,BOOT_SCRIPT,(size_t)n)==0?2:-1;
|
||||
}
|
||||
if(errno!=ENOENT)return false;
|
||||
if(!enabled)return true;
|
||||
if(mkdir("/var/lib/webosbrew",0755)!=0 && errno!=EEXIST)return false;
|
||||
if(mkdir("/var/lib/webosbrew/init.d",0755)!=0 && errno!=EEXIST)return false;
|
||||
int fd=open(BOOT_HOOK ".tmp",O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOFOLLOW,0700);if(fd<0)return false;
|
||||
size_t used=0;bool ok=true;
|
||||
while(used<sizeof(boot_script)-1){ssize_t n=write(fd,boot_script+used,sizeof(boot_script)-1-used);if(n<=0){ok=false;break;}used+=(size_t)n;}
|
||||
if(ok)ok=fchmod(fd,0755)==0 && fsync(fd)==0;
|
||||
if(close(fd)!=0)ok=false;
|
||||
if(ok)ok=rename(BOOT_HOOK ".tmp",BOOT_HOOK)==0;
|
||||
if(!S_ISREG(st.st_mode))return -1;
|
||||
char data[sizeof(legacy_boot_script)];int fd=open(BOOT_HOOK,O_RDONLY|O_NOFOLLOW|O_CLOEXEC);if(fd<0)return -1;
|
||||
ssize_t n=read(fd,data,sizeof(data));close(fd);
|
||||
return n==(ssize_t)(sizeof(legacy_boot_script)-1) && memcmp(data,legacy_boot_script,(size_t)n)==0?1:-1;
|
||||
}
|
||||
static bool boot_enabled(void){return boot_hook_kind()>0 && access(BOOT_HOOK,X_OK)==0;}
|
||||
static bool set_boot(bool enabled){
|
||||
int kind=boot_hook_kind();if(kind<0)return false;
|
||||
if(!enabled)return kind==0 || unlink(BOOT_HOOK)==0;
|
||||
if(access(BOOT_SCRIPT,X_OK)!=0)return false;
|
||||
if(kind==2)return true;
|
||||
if(mkdir(BOOT_DIRECTORY,0755)!=0 && errno!=EEXIST)return false;
|
||||
/* Never overwrite another process's temporary file or a foreign hook. */
|
||||
if(symlink(BOOT_SCRIPT,BOOT_HOOK ".tmp")!=0)return false;
|
||||
bool ok=rename(BOOT_HOOK ".tmp",BOOT_HOOK)==0;
|
||||
if(!ok)unlink(BOOT_HOOK ".tmp");
|
||||
return ok;
|
||||
}
|
||||
|
||||
+2
-1
@@ -150,7 +150,7 @@ static bool autostart(void *h,void *m,void *ctx){
|
||||
static bool status(void *h,void *m,void *ctx){
|
||||
(void)ctx;char json[4096],safe[512];size_t n=0;
|
||||
for(size_t i=0;last_error[i] && n+2<sizeof(safe);i++){char c=last_error[i];if(c=='"'||c=='\\')safe[n++]='\\';if((unsigned char)c>=32)safe[n++]=c;}safe[n]=0;
|
||||
int used=snprintf(json,sizeof(json),"{\"returnValue\":true,\"version\":\"0.6.0\",\"running\":%s,\"colorValid\":%s,\"frames\":%lu,\"endpoint\":\"127.0.0.1:19444\",\"priority\":%d,\"uid\":%u,\"drmVerified\":false,\"mappingVerified\":false,\"outputColor\":[%u,%u,%u],\"error\":\"%s\",\"regions\":[",capture?"true":"false",color_valid?"true":"false",frames,PRIORITY,(unsigned)geteuid(),sent_rgb[0],sent_rgb[1],sent_rgb[2],safe);
|
||||
int used=snprintf(json,sizeof(json),"{\"returnValue\":true,\"version\":\"0.6.1\",\"running\":%s,\"colorValid\":%s,\"frames\":%lu,\"endpoint\":\"127.0.0.1:19444\",\"priority\":%d,\"uid\":%u,\"drmVerified\":false,\"mappingVerified\":false,\"outputColor\":[%u,%u,%u],\"error\":\"%s\",\"regions\":[",capture?"true":"false",color_valid?"true":"false",frames,PRIORITY,(unsigned)geteuid(),sent_rgb[0],sent_rgb[1],sent_rgb[2],safe);
|
||||
for(int i=0;i<16;i++)used+=snprintf(json+used,sizeof(json)-used,"%s[%u,%u,%u]",i?",":"",rgb[i][0],rgb[i][1],rgb[i][2]);
|
||||
used+=snprintf(json+used,sizeof(json)-used,"],\"ledCount\":%u,\"spatialOutput\":%s,\"blackPercent\":[",led_count,led_count?"true":"false");
|
||||
for(int i=0;i<16;i++)used+=snprintf(json+used,sizeof(json)-used,"%s%u",i?",":"",black_percent[i]);
|
||||
@@ -218,6 +218,7 @@ static int tick(void *unused){
|
||||
static void *symbol(void *lib,const char *name){void *s=dlsym(lib,name);if(!s){fprintf(stderr,"Missing symbol %s\n",name);exit(2);}return s;}
|
||||
int main(void){
|
||||
signal(SIGTERM,quit_signal);signal(SIGINT,quit_signal);
|
||||
if(boot_enabled() && !set_boot(true))fprintf(stderr,"Own legacy boot hook migration failed\n");
|
||||
void *vt=dlopen("libvtcapture.so.1",RTLD_NOW),*ls=dlopen("libluna-service2.so.3",RTLD_NOW),*glib=dlopen("libglib-2.0.so.0",RTLD_NOW);
|
||||
if(!vt||!ls||!glib){fprintf(stderr,"Missing LG library: %s\n",dlerror());return 2;}
|
||||
vt_init=symbol(vt,"vtCapture_initHistogram");vt_preset=symbol(vt,"vtCapture_setPresetHistogram");vt_get=symbol(vt,"vtCapture_getHistogram");vt_finish=symbol(vt,"vtCapture_finalizeHistogram");
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
#define _DEFAULT_SOURCE
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#define TEST_ROOT "/tmp/hyperdrm-autostart-test"
|
||||
#define BOOT_DIRECTORY TEST_ROOT "/init.d"
|
||||
#define BOOT_SCRIPT TEST_ROOT "/boot.sh"
|
||||
#include "autostart.h"
|
||||
static void put_file(const char *path,const char *data){
|
||||
int fd=open(path,O_WRONLY|O_CREAT|O_EXCL,0700);assert(fd>=0);
|
||||
size_t size=strlen(data);assert(write(fd,data,size)==(ssize_t)size);assert(close(fd)==0);
|
||||
}
|
||||
int main(void){
|
||||
/* Fail rather than touching another run's files. */
|
||||
assert(mkdir(TEST_ROOT,0700)==0);put_file(BOOT_SCRIPT,"#!/bin/sh\nexit 0\n");
|
||||
assert(!boot_enabled() && set_boot(false));
|
||||
assert(set_boot(true));assert(boot_hook_kind()==2 && boot_enabled());
|
||||
assert(set_boot(true));assert(set_boot(false) && boot_hook_kind()==0);
|
||||
put_file(BOOT_HOOK,legacy_boot_script);assert(boot_hook_kind()==1);
|
||||
assert(set_boot(true) && boot_hook_kind()==2);assert(set_boot(false));
|
||||
put_file(BOOT_HOOK,"foreign startup\n");assert(!set_boot(true) && !set_boot(false));
|
||||
assert(unlink(BOOT_HOOK)==0);
|
||||
assert(symlink("/foreign/script",BOOT_HOOK)==0);assert(!set_boot(true) && !set_boot(false));
|
||||
assert(unlink(BOOT_HOOK)==0);
|
||||
put_file(BOOT_HOOK ".tmp","foreign temporary\n");assert(!set_boot(true));assert(boot_hook_kind()==0);
|
||||
assert(unlink(BOOT_HOOK ".tmp")==0);
|
||||
assert(set_boot(true));assert(unlink(BOOT_SCRIPT)==0);assert(!boot_enabled());
|
||||
assert(!set_boot(true));assert(set_boot(false));
|
||||
assert(rmdir(BOOT_DIRECTORY)==0 && rmdir(TEST_ROOT)==0);
|
||||
puts("PASS: symlink enable/disable, legacy migration, foreign files preserved, missing target harmless");
|
||||
}
|
||||
Reference in new issue
Block a user