aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Simo Piiroinen <simo.piiroinen@jolla.com>2020-11-05 18:52:29 +0200
committerLibravatar Tomi Leppänen <tomi.leppanen@jolla.com>2021-02-25 16:30:56 +0200
commitcddc48322240e83104ec583d5551a68523470833 (patch)
tree9528924b83268531128a9ea5d11d7f03ededf4e4
parentfix spacing in gget.profile (diff)
downloadfirejail-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.h3
-rw-r--r--src/firejail/profile.c140
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
452void profile_add(char *str); 452void profile_add(char *str);
453void profile_add_ignore(const char *str); 453void profile_add_ignore(const char *str);
454char *profile_list_normalize(char *list);
455char *profile_list_compress(char *list);
456void profile_list_augment(char **list, const char *items);
454 457
455// list.c 458// list.c
456void list(void); 459void 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
1777char *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
1802char *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
1908void 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}