diff options
author | Simo Piiroinen <simo.piiroinen@jolla.com> | 2020-11-05 18:52:29 +0200 |
---|---|---|
committer | Tomi Leppänen <tomi.leppanen@jolla.com> | 2021-02-25 16:30:56 +0200 |
commit | cddc48322240e83104ec583d5551a68523470833 (patch) | |
tree | 9528924b83268531128a9ea5d11d7f03ededf4e4 | |
parent | fix spacing in gget.profile (diff) | |
download | firejail-cddc48322240e83104ec583d5551a68523470833.tar.gz firejail-cddc48322240e83104ec583d5551a68523470833.tar.zst firejail-cddc48322240e83104ec583d5551a68523470833.zip |
Add utility functions for handling comma separated lists
A lot of profile options deal with manipulating strings containing
comma separated list of things, using several strains of similar but
not exactly the same code, duplicated for the purposes of processing
command line arguments and parsing configuration files.
Having utility functions available for handling such list strings can
make higher level logic shorter, cleaner and function in more uniform
manner.
Signed-off-by: Simo Piiroinen <simo.piiroinen@jolla.com>
Signed-off-by: Tomi Leppänen <tomi.leppanen@jolla.com>
-rw-r--r-- | src/firejail/firejail.h | 3 | ||||
-rw-r--r-- | src/firejail/profile.c | 140 |
2 files changed, 143 insertions, 0 deletions
diff --git a/src/firejail/firejail.h b/src/firejail/firejail.h index 36340ff2c..c8080f778 100644 --- a/src/firejail/firejail.h +++ b/src/firejail/firejail.h | |||
@@ -451,6 +451,9 @@ int profile_check_line(char *ptr, int lineno, const char *fname); | |||
451 | // add a profile entry in cfg.profile list; use str to populate the list | 451 | // add a profile entry in cfg.profile list; use str to populate the list |
452 | void profile_add(char *str); | 452 | void profile_add(char *str); |
453 | void profile_add_ignore(const char *str); | 453 | void profile_add_ignore(const char *str); |
454 | char *profile_list_normalize(char *list); | ||
455 | char *profile_list_compress(char *list); | ||
456 | void profile_list_augment(char **list, const char *items); | ||
454 | 457 | ||
455 | // list.c | 458 | // list.c |
456 | void list(void); | 459 | void list(void); |
diff --git a/src/firejail/profile.c b/src/firejail/profile.c index 9339228f4..7b5fbfedf 100644 --- a/src/firejail/profile.c +++ b/src/firejail/profile.c | |||
@@ -1773,3 +1773,143 @@ void profile_read(const char *fname) { | |||
1773 | } | 1773 | } |
1774 | fclose(fp); | 1774 | fclose(fp); |
1775 | } | 1775 | } |
1776 | |||
1777 | char *profile_list_normalize(char *list) | ||
1778 | { | ||
1779 | /* Remove redundant commas. | ||
1780 | * | ||
1781 | * As result is always shorter than original, | ||
1782 | * in-place copying can be used. | ||
1783 | */ | ||
1784 | size_t i = 0; | ||
1785 | size_t j = 0; | ||
1786 | int c; | ||
1787 | while (list[i] == ',') | ||
1788 | ++i; | ||
1789 | while ((c = list[i++])) { | ||
1790 | if (c == ',') { | ||
1791 | while (list[i] == ',') | ||
1792 | ++i; | ||
1793 | if (list[i] == 0) | ||
1794 | break; | ||
1795 | } | ||
1796 | list[j++] = c; | ||
1797 | } | ||
1798 | list[j] = 0; | ||
1799 | return list; | ||
1800 | } | ||
1801 | |||
1802 | char *profile_list_compress(char *list) | ||
1803 | { | ||
1804 | size_t i; | ||
1805 | |||
1806 | /* Comma separated list is processed so that: | ||
1807 | * "item" -> adds item to list | ||
1808 | * "-item" -> removes item from list | ||
1809 | * "+item" -> adds item to list | ||
1810 | * "=item" -> clear list, add item | ||
1811 | * | ||
1812 | * For example: | ||
1813 | * ,a,,,b,,,c, -> a,b,c | ||
1814 | * a,,b,,,c,a -> a,b,c | ||
1815 | * a,b,c,-a -> b,c | ||
1816 | * a,b,c,-a,a -> b,c,a | ||
1817 | * a,+b,c -> a,b,c | ||
1818 | * a,b,=c,d -> c,d | ||
1819 | * a,b,c,= -> | ||
1820 | */ | ||
1821 | profile_list_normalize(list); | ||
1822 | |||
1823 | /* Count items: comma count + 1 */ | ||
1824 | size_t count = 1; | ||
1825 | for (i = 0; list[i]; ++i) { | ||
1826 | if (list[i] == ',') | ||
1827 | ++count; | ||
1828 | } | ||
1829 | |||
1830 | /* Collect items in an array */ | ||
1831 | char *in[count]; | ||
1832 | count = 0; | ||
1833 | in[count++] = list; | ||
1834 | for (i = 0; list[i]; ++i) { | ||
1835 | if (list[i] != ',') | ||
1836 | continue; | ||
1837 | list[i] = 0; | ||
1838 | in[count++] = list + i + 1; | ||
1839 | } | ||
1840 | |||
1841 | /* Filter array: add, remove, reset, filter out duplicates */ | ||
1842 | for (i = 0; i < count; ++i) { | ||
1843 | char *item = in[i]; | ||
1844 | assert(item); | ||
1845 | |||
1846 | size_t k; | ||
1847 | switch (*item) { | ||
1848 | case '-': | ||
1849 | ++item; | ||
1850 | /* Do not include this item */ | ||
1851 | in[i] = 0; | ||
1852 | /* Remove if already included */ | ||
1853 | for (k = 0; k < i; ++k) { | ||
1854 | if (in[k] && !strcmp(in[k], item)) { | ||
1855 | in[k] = 0; | ||
1856 | break; | ||
1857 | } | ||
1858 | } | ||
1859 | break; | ||
1860 | case '+': | ||
1861 | /* Allow +/- symmetry */ | ||
1862 | in[i] = ++item; | ||
1863 | /* FALLTHRU */ | ||
1864 | default: | ||
1865 | /* Adding empty item is a NOP */ | ||
1866 | if (!*item) { | ||
1867 | in[i] = 0; | ||
1868 | break; | ||
1869 | } | ||
1870 | /* Include item unless it is already included */ | ||
1871 | for (k = 0; k < i; ++k) { | ||
1872 | if (in[k] && !strcmp(in[k], item)) { | ||
1873 | in[i] = 0; | ||
1874 | break; | ||
1875 | } | ||
1876 | } | ||
1877 | break; | ||
1878 | case '=': | ||
1879 | in[i] = ++item; | ||
1880 | /* Include non-empty item */ | ||
1881 | if (!*item) | ||
1882 | in[i] = 0; | ||
1883 | /* Remove all allready included items */ | ||
1884 | for (k = 0; k < i; ++k) | ||
1885 | in[k] = 0; | ||
1886 | break; | ||
1887 | } | ||
1888 | } | ||
1889 | |||
1890 | /* Copying back using in-place data works because the | ||
1891 | * original order is retained and no item gets longer | ||
1892 | * than what it used to be. | ||
1893 | */ | ||
1894 | char *pos = list; | ||
1895 | for (i = 0; i < count; ++i) { | ||
1896 | char *item = in[i]; | ||
1897 | if (!item) | ||
1898 | continue; | ||
1899 | if (pos > list) | ||
1900 | *pos++ = ','; | ||
1901 | while (*item) | ||
1902 | *pos++ = *item++; | ||
1903 | } | ||
1904 | *pos = 0; | ||
1905 | return list; | ||
1906 | } | ||
1907 | |||
1908 | void profile_list_augment(char **list, const char *items) | ||
1909 | { | ||
1910 | char *tmp = 0; | ||
1911 | if (asprintf(&tmp, "%s,%s", *list ?: "", items ?: "") < 0) | ||
1912 | errExit("asprintf"); | ||
1913 | free(*list); | ||
1914 | *list = profile_list_compress(tmp); | ||
1915 | } | ||