LCOV - code coverage report
Current view: top level - lib/util - tini.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 117 135 86.7 %
Date: 2024-05-31 13:13:24 Functions: 9 9 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Trivial smb.conf parsing code
       3             :  *
       4             :  * Copyright Volker Lendecke <vl@samba.org> 2014
       5             :  *
       6             :  * Redistribution and use in source and binary forms, with or without
       7             :  * modification, are permitted provided that the following conditions
       8             :  * are met:
       9             :  * 1. Redistributions of source code must retain the above copyright
      10             :  *    notice, and the entire permission notice in its entirety,
      11             :  *    including the disclaimer of warranties.
      12             :  * 2. Redistributions in binary form must reproduce the above copyright
      13             :  *    notice, this list of conditions and the following disclaimer in the
      14             :  *    documentation and/or other materials provided with the distribution.
      15             :  * 3. The name of the author may not be used to endorse or promote
      16             :  *    products derived from this software without specific prior
      17             :  *    written permission.
      18             :  *
      19             :  * ALTERNATIVELY, this product may be distributed under the terms of
      20             :  * the GNU Public License Version 3 or later, in which case the
      21             :  * provisions of the GPL are required INSTEAD OF the above restrictions.
      22             :  * (This clause is necessary due to a potential bad interaction between the
      23             :  * GPL and the restrictions contained in a BSD-style copyright.)
      24             :  *
      25             :  * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED
      26             :  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      27             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
      28             :  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
      29             :  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
      30             :  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      31             :  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      32             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
      33             :  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      34             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
      35             :  * OF THE POSSIBILITY OF SUCH DAMAGE.
      36             :  */
      37             : 
      38             : #include <stdio.h>
      39             : #include <stdlib.h>
      40             : #include <stdbool.h>
      41             : #include <ctype.h>
      42             : #include <errno.h>
      43             : #include <string.h>
      44             : #include "tini.h"
      45             : 
      46  1258609103 : static bool c_isspace(char c)
      47             : {
      48  1258609103 :         unsigned char uc = c;
      49  1258609103 :         if (c != uc) {
      50        5008 :                 return false;
      51             :         }
      52  1258604095 :         return isspace(uc);
      53             : }
      54             : 
      55    30672431 : static int next_content(FILE *f)
      56             : {
      57       55782 :         int c;
      58             : 
      59    58310636 :         for (c = fgetc(f); c != EOF; c = fgetc(f)) {
      60    58080219 :                 if (!c_isspace(c)) {
      61    26048971 :                         break;
      62             :                 }
      63    31983685 :                 if (c == '\n') {
      64     4338075 :                         break;
      65             :                 }
      66             :         }
      67             : 
      68    30672431 :         return c;
      69             : }
      70             : 
      71      598452 : static int next_end_of_line(FILE *f)
      72             : {
      73        1508 :         int c;
      74             : 
      75    26238341 :         for (c = fgetc(f); c != EOF; c = fgetc(f)) {
      76    26238341 :                 if (c == '\n') {
      77      596944 :                         break;
      78             :                 }
      79             :         }
      80      598452 :         return c;
      81             : }
      82             : 
      83  1093605117 : static bool make_space(char **buf, size_t *buflen, size_t position)
      84             : {
      85     2080861 :         char *tmp;
      86             : 
      87  1093605117 :         if (position < *buflen) {
      88  1091443120 :                 return true;
      89             :         }
      90       81192 :         tmp = realloc(*buf, (*buflen) * 2);
      91       81192 :         if (tmp == NULL) {
      92           0 :                 return false;
      93             :         }
      94       81192 :         *buf = tmp;
      95       81192 :         *buflen *= 2;
      96       81192 :         return true;
      97             : }
      98             : 
      99             : /*
     100             :  * Get a conf line into *pbuf (which must be a malloc'ed buffer already).
     101             :  *
     102             :  * Ignores leading spaces
     103             :  * Ignores comment lines
     104             :  * Ignores empty lines
     105             :  * Takes care of continuation lines
     106             :  * Zaps multiple spaces into one
     107             :  */
     108             : 
     109    25728499 : static int get_line(FILE *f, char **pbuf, size_t *pbuflen)
     110             : {
     111       46869 :         int c;
     112       46869 :         char *buf;
     113       46869 :         size_t buflen, pos;
     114             : 
     115    25728499 :         buf = *pbuf;
     116    25728499 :         buflen = *pbuflen;
     117    25728499 :         pos = 0;
     118             : 
     119    27908892 : next_line:
     120             : 
     121    30672431 :         c = next_content(f);
     122    30672431 :         if (c == EOF) {
     123      229603 :                 return ENOENT;
     124             :         }
     125             : 
     126    30442014 :         if ((c == '#') || (c == ';')) {
     127             :                 /*
     128             :                  * Line starting with a comment, skip
     129             :                  */
     130      598452 :                 c = next_end_of_line(f);
     131      598452 :                 if (c == EOF) {
     132           0 :                         return ENOENT;
     133             :                 }
     134      598452 :                 goto next_line;
     135             :         }
     136             : 
     137    29843562 :         if (c == '\n') {
     138             :                 /*
     139             :                  * Blank line, skip
     140             :                  */
     141     4345480 :                 goto next_line;
     142             :         }
     143             : 
     144  1094045083 :         for ( ; c != EOF ; c = fgetc(f)) {
     145             : 
     146  1094044115 :                 if (c == '\n') {
     147             : 
     148    25497114 :                         if ((pos > 0) && (buf[pos-1] == '\\')) {
     149             :                                 /*
     150             :                                  * Line ends in "\". Continuation.
     151             :                                  */
     152           0 :                                 pos -= 1;
     153           0 :                                 continue;
     154             :                         }
     155             : 
     156    25497114 :                         if ((pos > 1) && (buf[pos-2] == '\\') &&
     157           0 :                             c_isspace(buf[pos-1])) {
     158             :                                 /*
     159             :                                  * Line ends in "\ ". Mind that we zap
     160             :                                  * multiple spaces into one. Continuation.
     161             :                                  */
     162           0 :                                 pos -= 2;
     163           0 :                                 continue;
     164             :                         }
     165             : 
     166             :                         /*
     167             :                          * No continuation, done with the line
     168             :                          */
     169    25451059 :                         break;
     170             :                 }
     171             : 
     172  1068547001 :                 if ((pos > 0) && c_isspace(buf[pos-1]) && c_isspace(c)) {
     173             :                         /*
     174             :                          * Zap multiple spaces to one
     175             :                          */
     176      439966 :                         continue;
     177             :                 }
     178             : 
     179  1068107035 :                 if (!make_space(&buf, &buflen, pos)) {
     180           0 :                         return ENOMEM;
     181             :                 }
     182  1068107035 :                 buf[pos++] = c;
     183             :         }
     184             : 
     185    25498082 :         if (!make_space(&buf, &buflen, pos)) {
     186           0 :                 return ENOMEM;
     187             :         }
     188    25498082 :         buf[pos++] = '\0';
     189             : 
     190    25498082 :         *pbuf = buf;
     191    25498082 :         return 0;
     192             : }
     193             : 
     194     4042390 : static bool parse_section(
     195             :         char *buf, bool (*sfunc)(const char *section, void *private_data),
     196             :         void *private_data)
     197             : {
     198        4051 :         char *p, *q;
     199             : 
     200     4042390 :         p = buf+1;              /* skip [ */
     201             : 
     202     4042390 :         q = strchr(p, ']');
     203     4042390 :         if (q == NULL) {
     204           0 :                 return false;
     205             :         }
     206     4042390 :         *q = '\0';
     207             : 
     208     4042390 :         return sfunc(p, private_data);
     209             : }
     210             : 
     211    42909504 : static char *trim_one_space(char *buf)
     212             : {
     213       84008 :         size_t len;
     214             : 
     215    42909504 :         if (c_isspace(buf[0])) {
     216    21288290 :                 buf += 1;
     217             :         }
     218    42909504 :         len = strlen(buf);
     219    42909504 :         if (len == 0) {
     220       93527 :                 return buf;
     221             :         }
     222    42815977 :         if (c_isspace(buf[len-1])) {
     223    21372041 :                 buf[len-1] = '\0';
     224             :         }
     225             : 
     226    42731969 :         return buf;
     227             : }
     228             : 
     229    21455692 : static bool parse_param(char *buf,
     230             :                         bool allow_empty_value,
     231             :                         bool (*pfunc)(const char *name, const char *value,
     232             :                                       void *private_data),
     233             :                         void *private_data)
     234             : {
     235       42004 :         char *equals;
     236       42004 :         char *name;
     237       42004 :         const char *value;
     238       42004 :         size_t len;
     239    21455692 :         bool no_value = false;
     240             : 
     241    21455692 :         equals = strchr(buf, '=');
     242    21455692 :         if (equals != NULL) {
     243    21454752 :                 *equals = '\0';
     244             :         } else {
     245         940 :                 if (allow_empty_value) {
     246           0 :                         no_value = true;
     247             :                 } else {
     248         940 :                         return true;
     249             :                 }
     250             :         }
     251             : 
     252    21454752 :         name = trim_one_space(buf);
     253    21454752 :         len = strlen(buf);
     254    21454752 :         if (len == 0) {
     255           0 :                 return false;
     256             :         }
     257             : 
     258    21454752 :         if (no_value) {
     259           0 :                 value = "";
     260             :         } else {
     261    21454752 :                 value = trim_one_space(equals+1);
     262             :         }
     263             : 
     264    21454752 :         return pfunc(name, value, private_data);
     265             : }
     266             : 
     267      230429 : bool tini_parse(FILE *f,
     268             :                 bool allow_empty_value,
     269             :                 bool (*sfunc)(const char *section, void *private_data),
     270             :                 bool (*pfunc)(const char *name, const char *value,
     271             :                               void *private_data),
     272             :                 void *private_data)
     273             : {
     274         814 :         char *buf;
     275         814 :         size_t buflen;
     276             : 
     277      230429 :         buflen = 256;
     278             : 
     279      230429 :         buf = malloc(buflen);
     280      230429 :         if (buf == NULL) {
     281           0 :                 return false;
     282             :         }
     283             : 
     284    25498884 :         while (true) {
     285       46869 :                 int ret;
     286       46869 :                 bool ok;
     287             : 
     288    25728499 :                 ret = get_line(f, &buf, &buflen);
     289             : 
     290    25728499 :                 if (ret == ENOENT) {
     291             :                         /* No lines anymore */
     292      229603 :                         break;
     293             :                 }
     294             : 
     295    25498082 :                 if (ret != 0) {
     296             :                         /* Real error */
     297           0 :                         free(buf);
     298           0 :                         return false;
     299             :                 }
     300             : 
     301    25498082 :                 switch(buf[0]) {
     302           0 :                 case 0:
     303           0 :                         continue;
     304             :                         break;
     305     4042390 :                 case '[':
     306     4042390 :                         ok = parse_section(buf, sfunc, private_data);
     307     4042390 :                         break;
     308    21455692 :                 default:
     309    21455692 :                         ok = parse_param(buf, allow_empty_value, pfunc, private_data);
     310    21455692 :                         break;
     311             :                 }
     312             : 
     313    25498082 :                 if (!ok) {
     314          12 :                         free(buf);
     315          12 :                         return false;
     316             :                 }
     317             :         }
     318      230417 :         free(buf);
     319      230417 :         return true;
     320             : }

Generated by: LCOV version 1.14