Handle file-properties for setting eXecutable flag
[src/app-framework-main.git] / src / wgtpkg-install.c
index 44d2171..79cb7fb 100644 (file)
@@ -27,6 +27,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
+#include <fcntl.h>
 #include <sys/stat.h>
 
 #include "verbose.h"
@@ -50,7 +51,40 @@ static const char* exec_type_strings[] = {
        "application/vnd.agl.native"
 };
 
-static const char key_http_port[] = "X-AFM--http-port";
+static const char key_afm_prefix[] = "X-AFM-";
+static const char key_http_port[] = "http-port";
+
+/*
+ * normalize unit files: remove comments, remove heading blanks,
+ * make single lines
+ */
+static void normalize_unit_file(char *content)
+{
+       char *read, *write, c;
+
+       read = write = content;
+       c = *read++;
+       while (c) {
+               switch (c) {
+               case '\n':
+               case ' ':
+               case '\t':
+                       c = *read++;
+                       break;
+               case '#':
+               case ';':
+                       do { c = *read++; } while(c && c != '\n');
+                       break;
+               default:
+                       *write++ = c;
+                       do { *write++ = c = *read++; } while(c && c != '\n');
+                       if (write - content >= 2 && write[-2] == '\\')
+                               (--write)[-1] = ' ';
+                       break;
+               }
+       }
+       *write = c;
+}
 
 static int get_port_cb(void *closure, const char *name, const char *path, int isuser)
 {
@@ -64,19 +98,27 @@ static int get_port_cb(void *closure, const char *name, const char *path, int is
        if (rc < 0)
                return rc;
 
+       /* normalize the unit file */
+       normalize_unit_file(content);
+
        /* process the file */
-       iter = strstr(content, key_http_port);
+       iter = strstr(content, key_afm_prefix);
        while (iter) {
-               iter += sizeof key_http_port - 1;
-               while(*iter && *iter != '=' && *iter != '\n')
+               iter += sizeof key_afm_prefix - 1;
+               if (*iter == '-')
                        iter++;
-               if (*iter == '=') {
-                       while(*++iter == ' ');
-                       p = atoi(iter);
-                       if (p >= 0 && p < 32768)
-                               ((uint32_t*)closure)[p >> 5] |= (uint32_t)1 << (p & 31);
+               if (!strncmp(iter, key_http_port, sizeof key_http_port - 1)) {
+                       iter += sizeof key_http_port - 1;
+                       while(*iter && *iter != '=' && *iter != '\n')
+                               iter++;
+                       if (*iter == '=') {
+                               while(*++iter == ' ');
+                               p = atoi(iter);
+                               if (p >= 0 && p < 32768)
+                                       ((uint32_t*)closure)[p >> 5] |= (uint32_t)1 << (p & 31);
+                       }
                }
-               iter = strstr(iter, key_http_port);
+               iter = strstr(iter, key_afm_prefix);
        }
        free(content);
        return 0;
@@ -94,6 +136,7 @@ static int get_port()
                if (rc >= 0) {
                        for (rc = 1024 ; rc < 32768 && !~ports[rc >> 5] ; rc += 32);
                        if (rc == 32768) {
+                               ERROR("Can't compute a valid port");
                                errno = EADDRNOTAVAIL;
                                rc = -1;
                        } else {
@@ -145,12 +188,13 @@ static int check_temporary_constraints(const struct wgt_desc *desc)
        result  = check_valid_string(desc->id, "id");
        result |= check_valid_string(desc->version, "version");
        result |= check_valid_string(desc->ver, "ver");
-       result |= check_defined(desc->icons, "icon");
        result |= check_defined(desc->content_src, "content");
+       if (desc->icons)
+               result |= check_defined(desc->icons->src, "icon.src");
        if (result)
                return result;
 
-       if (desc->icons->next) {
+       if (desc->icons && desc->icons->next) {
                ERROR("widget has more than one icon defined (temporary constraints)");
                errno = EINVAL;
                result = -1;
@@ -208,6 +252,74 @@ static int check_permissions(const struct wgt_desc *desc)
        return result;
 }
 
+static int for_all_content(const struct wgt_desc *desc, int (*action)(const char *src, const char *type))
+{
+       int rc, rc2;
+       struct wgt_desc_feature *feat;
+       const char *src, *type;
+
+       rc = action(desc->content_src, desc->content_type);
+       feat = desc->features;
+       while (feat) {
+               if (!strcmp(feat->name, "urn:AGL:widget:provided-unit")) {
+                       src = wgt_info_param(feat, "content.src");
+                       type = wgt_info_param(feat, "content.type");
+                       rc2 = action(src, type);
+                       if (rc >= 0 && rc2 < 0)
+                               rc = rc2;
+               }
+               feat = feat->next;
+       }
+       return rc;
+}
+
+static int set_exec_flag(const char *src, const char *type)
+{
+       int i, rc;
+
+       if (src && type) {
+               i = sizeof exec_type_strings / sizeof *exec_type_strings;
+               while (i) {
+                       if (!strcasecmp(type, exec_type_strings[--i])) {
+                               rc = fchmodat(workdirfd, src, 0755, 0);
+                               if (rc < 0)
+                                       ERROR("can't make executable the file %s", src);
+                               return rc;
+                       }
+               }
+       }
+       return 0;
+}
+
+static int check_one_content(const char *src, const char *type)
+{
+       int rc;
+       struct stat s;
+
+       if (!src) {
+               ERROR("a content src is missing");
+               errno = EINVAL;
+               rc = -1;
+       } else {
+               /* TODO: when dealing with HTML and languages, the check should
+                * include i18n path search of widgets */
+               rc = fstatat(workdirfd, src, &s, AT_NO_AUTOMOUNT|AT_SYMLINK_NOFOLLOW);
+               if (rc < 0)
+                       ERROR("can't get info on content %s: %m", src);
+               else if (!S_ISREG(s.st_mode)) {
+                       ERROR("content %s isn't a regular file", src);
+                       errno = EINVAL;
+                       rc = -1;
+               }
+       }
+       return rc;
+}
+
+static int check_content(const struct wgt_desc *desc)
+{
+       return for_all_content(desc, check_one_content);
+}
+
 static int check_widget(const struct wgt_desc *desc)
 {
        int result;
@@ -215,6 +327,8 @@ static int check_widget(const struct wgt_desc *desc)
        result = check_temporary_constraints(desc);
        if (result >= 0)
                result = check_permissions(desc);
+       if (result >= 0)
+               result = check_content(desc);
        return result;
 }
 
@@ -244,6 +358,9 @@ static int install_icon(const struct wgt_desc *desc)
        char target[PATH_MAX];
        int rc;
 
+       if (!desc->icons)
+               return 0;
+
        create_directory(FWK_ICON_DIR, 0755, 1);
        rc = snprintf(link, sizeof link, "%s/%s", FWK_ICON_DIR, desc->idaver);
        if (rc >= (int)sizeof link) {
@@ -268,16 +385,38 @@ static int install_icon(const struct wgt_desc *desc)
 
 static int install_exec_flag(const struct wgt_desc *desc)
 {
-       int i;
+       return for_all_content(desc, set_exec_flag);
+}
 
-       if (desc->content_type) {
-               i = sizeof exec_type_strings / sizeof *exec_type_strings;
-               while (i) {
-                       if (!strcasecmp(desc->content_type, exec_type_strings[--i]))
-                               return fchmodat(workdirfd, desc->content_src, 0755, 0);
+static int install_file_properties(const struct wgt_desc *desc)
+{
+       int rc, rc2;
+       struct wgt_desc_feature *feat;
+       struct wgt_desc_param *param;
+
+       rc = 0;
+       feat = desc->features;
+       while (feat) {
+               if (!strcmp(feat->name, "urn:AGL:widget:file-properties")) {
+                       param = feat->params;
+                       while (param) {
+                               if (!strcmp(param->value, "executable")) {
+                                       rc2 = fchmodat(workdirfd, param->name, 0755, 0);
+                                       if (rc2 < 0)
+                                               ERROR("can't make executable the file %s: %m", param->name);
+                               } else {
+                                       ERROR("unknown file property %s for %s", param->value, param->name);
+                                       errno = EINVAL;
+                                       rc2 = -1;
+                               }
+                               if (rc2 < 0 && !rc)
+                                       rc = rc2;
+                               param = param->next;
+                       }
                }
+               feat = feat->next;
        }
-       return 0;
+       return rc;
 }
 
 static int install_security(const struct wgt_desc *desc)
@@ -307,7 +446,7 @@ static int install_security(const struct wgt_desc *desc)
        }
        len--;
        *head++ = '/';
-       icon = desc->icons->src;
+       icon = desc->icons ? desc->icons->src : NULL;
        lic = (unsigned)strlen(icon);
        n = file_count();
        i = 0;
@@ -320,7 +459,7 @@ static int install_security(const struct wgt_desc *desc)
                        goto error2;
                }
                strcpy(head, f->name);
-               if (lf <= lic && !memcmp(f->name, icon, lf) && (!f->name[lf] || f->name[lf] == '/'))
+               if (lf <= lic && icon && !memcmp(f->name, icon, lf) && (!f->name[lf] || f->name[lf] == '/'))
                        rc = secmgr_path_public_read_only(path);
                else
                        rc = secmgr_path_read_only(path);
@@ -394,6 +533,9 @@ struct wgt_info *install_widget(const char *wgtfile, const char *root, int force
        if (install_exec_flag(desc))
                goto error4;
 
+       if (install_file_properties(desc))
+               goto error4;
+
        port = get_port();
        if (port < 0)
                goto error4;