LCOV - code coverage report
Current view: top level - lib/util - tini.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 99 119 83.2 %
Date: 2024-06-13 04:01:37 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   203559176 : static bool c_isspace(char c)
      47             : {
      48   203559176 :         unsigned char uc = c;
      49   203559176 :         if (c != uc) {
      50        4932 :                 return false;
      51             :         }
      52   203554244 :         return isspace(uc);
      53             : }
      54             : 
      55     5007445 : static int next_content(FILE *f)
      56             : {
      57             :         int c;
      58             : 
      59     9993196 :         for (c = fgetc(f); c != EOF; c = fgetc(f)) {
      60     9952709 :                 if (!c_isspace(c)) {
      61     4235503 :                         break;
      62             :                 }
      63     5717206 :                 if (c == '\n') {
      64      731455 :                         break;
      65             :                 }
      66             :         }
      67             : 
      68     5007445 :         return c;
      69             : }
      70             : 
      71      130685 : static int next_end_of_line(FILE *f)
      72             : {
      73             :         int c;
      74             : 
      75     5715136 :         for (c = fgetc(f); c != EOF; c = fgetc(f)) {
      76     5715136 :                 if (c == '\n') {
      77      130685 :                         break;
      78             :                 }
      79             :         }
      80      130685 :         return c;
      81             : }
      82             : 
      83   175599384 : static bool make_space(char **buf, size_t *buflen, size_t position)
      84             : {
      85             :         char *tmp;
      86             : 
      87   175599384 :         if (position < *buflen) {
      88   175590625 :                 return true;
      89             :         }
      90        8759 :         tmp = realloc(*buf, (*buflen) * 2);
      91        8759 :         if (tmp == NULL) {
      92           0 :                 return false;
      93             :         }
      94        8759 :         *buf = tmp;
      95        8759 :         *buflen *= 2;
      96        8759 :         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     4145305 : static int get_line(FILE *f, char **pbuf, size_t *pbuflen)
     110             : {
     111             :         int c;
     112             :         char *buf;
     113             :         size_t buflen, pos;
     114             : 
     115     4145305 :         buf = *pbuf;
     116     4145305 :         buflen = *pbuflen;
     117     4145305 :         pos = 0;
     118             : 
     119     3757206 : next_line:
     120             : 
     121     5007445 :         c = next_content(f);
     122     5007445 :         if (c == EOF) {
     123       40487 :                 return ENOENT;
     124             :         }
     125             : 
     126     4966958 :         if ((c == '#') || (c == ';')) {
     127             :                 /*
     128             :                  * Line starting with a comment, skip
     129             :                  */
     130      130685 :                 c = next_end_of_line(f);
     131      130685 :                 if (c == EOF) {
     132           0 :                         return ENOENT;
     133             :                 }
     134      130685 :                 goto next_line;
     135             :         }
     136             : 
     137     4836273 :         if (c == '\n') {
     138             :                 /*
     139             :                  * Blank line, skip
     140             :                  */
     141      731455 :                 goto next_line;
     142             :         }
     143             : 
     144   175676158 :         for ( ; c != EOF ; c = fgetc(f)) {
     145             : 
     146   175675232 :                 if (c == '\n') {
     147             : 
     148     4103892 :                         if ((pos > 0) && (buf[pos-1] == '\\')) {
     149             :                                 /*
     150             :                                  * Line ends in "\". Continuation.
     151             :                                  */
     152           0 :                                 pos -= 1;
     153           0 :                                 continue;
     154             :                         }
     155             : 
     156     4103892 :                         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     4103892 :                         break;
     170             :                 }
     171             : 
     172   171571340 :                 if ((pos > 0) && c_isspace(buf[pos-1]) && c_isspace(c)) {
     173             :                         /*
     174             :                          * Zap multiple spaces to one
     175             :                          */
     176       76774 :                         continue;
     177             :                 }
     178             : 
     179   171494566 :                 if (!make_space(&buf, &buflen, pos)) {
     180           0 :                         return ENOMEM;
     181             :                 }
     182   171494566 :                 buf[pos++] = c;
     183             :         }
     184             : 
     185     4104818 :         if (!make_space(&buf, &buflen, pos)) {
     186           0 :                 return ENOMEM;
     187             :         }
     188     4104818 :         buf[pos++] = '\0';
     189             : 
     190     4104818 :         *pbuf = buf;
     191     4104818 :         return 0;
     192             : }
     193             : 
     194      552688 : static bool parse_section(
     195             :         char *buf, bool (*sfunc)(const char *section, void *private_data),
     196             :         void *private_data)
     197             : {
     198             :         char *p, *q;
     199             : 
     200      552688 :         p = buf+1;              /* skip [ */
     201             : 
     202      552688 :         q = strchr(p, ']');
     203      552688 :         if (q == NULL) {
     204           0 :                 return false;
     205             :         }
     206      552688 :         *q = '\0';
     207             : 
     208      552688 :         return sfunc(p, private_data);
     209             : }
     210             : 
     211     7102408 : static char *trim_one_space(char *buf)
     212             : {
     213             :         size_t len;
     214             : 
     215     7102408 :         if (c_isspace(buf[0])) {
     216     3529333 :                 buf += 1;
     217             :         }
     218     7102408 :         len = strlen(buf);
     219     7102408 :         if (len == 0) {
     220       14010 :                 return buf;
     221             :         }
     222     7088398 :         if (c_isspace(buf[len-1])) {
     223     3536899 :                 buf[len-1] = '\0';
     224             :         }
     225             : 
     226     7088398 :         return buf;
     227             : }
     228             : 
     229     3552130 : 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             :         char *equals;
     236             :         char *name;
     237             :         const char *value;
     238             :         size_t len;
     239     3552130 :         bool no_value = false;
     240             : 
     241     3552130 :         equals = strchr(buf, '=');
     242     3552130 :         if (equals != NULL) {
     243     3551204 :                 *equals = '\0';
     244             :         } else {
     245         926 :                 if (allow_empty_value) {
     246           0 :                         no_value = true;
     247             :                 } else {
     248         926 :                         return true;
     249             :                 }
     250             :         }
     251             : 
     252     3551204 :         name = trim_one_space(buf);
     253     3551204 :         len = strlen(buf);
     254     3551204 :         if (len == 0) {
     255           0 :                 return false;
     256             :         }
     257             : 
     258     3551204 :         if (no_value) {
     259           0 :                 value = "";
     260             :         } else {
     261     3551204 :                 value = trim_one_space(equals+1);
     262             :         }
     263             : 
     264     3551204 :         return pfunc(name, value, private_data);
     265             : }
     266             : 
     267       40487 : 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             :         char *buf;
     275             :         size_t buflen;
     276             : 
     277       40487 :         buflen = 256;
     278             : 
     279       40487 :         buf = malloc(buflen);
     280       40487 :         if (buf == NULL) {
     281           0 :                 return false;
     282             :         }
     283             : 
     284     4104818 :         while (true) {
     285             :                 int ret;
     286             :                 bool ok;
     287             : 
     288     4145305 :                 ret = get_line(f, &buf, &buflen);
     289             : 
     290     4145305 :                 if (ret == ENOENT) {
     291             :                         /* No lines anymore */
     292       40487 :                         break;
     293             :                 }
     294             : 
     295     4104818 :                 if (ret != 0) {
     296             :                         /* Real error */
     297           0 :                         free(buf);
     298           0 :                         return false;
     299             :                 }
     300             : 
     301     4104818 :                 switch(buf[0]) {
     302           0 :                 case 0:
     303           0 :                         continue;
     304             :                         break;
     305      552688 :                 case '[':
     306      552688 :                         ok = parse_section(buf, sfunc, private_data);
     307      552688 :                         break;
     308     3552130 :                 default:
     309     3552130 :                         ok = parse_param(buf, allow_empty_value, pfunc, private_data);
     310     3552130 :                         break;
     311             :                 }
     312             : 
     313     4104818 :                 if (!ok) {
     314           0 :                         free(buf);
     315           0 :                         return false;
     316             :                 }
     317             :         }
     318       40487 :         free(buf);
     319       40487 :         return true;
     320             : }

Generated by: LCOV version 1.13