LCOV - code coverage report
Current view: top level - lib/util - tevent_req_profile.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 213 271 78.6 %
Date: 2024-02-28 12:06:22 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Unix SMB/CIFS implementation.
       3             :  *
       4             :  * Helpers around tevent_req_profile
       5             :  *
       6             :  * Copyright (C) Volker Lendecke 2018
       7             :  *
       8             :  *   ** NOTE! The following LGPL license applies to the tevent
       9             :  *   ** library. This does NOT imply that all of Samba is released
      10             :  *   ** under the LGPL
      11             :  *
      12             :  * This library is free software; you can redistribute it and/or
      13             :  * modify it under the terms of the GNU Lesser General Public
      14             :  * License as published by the Free Software Foundation; either
      15             :  * version 3 of the License, or (at your option) any later version.
      16             :  *
      17             :  * This library is distributed in the hope that it will be useful,
      18             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      19             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      20             :  * Lesser General Public License for more details.
      21             :  *
      22             :  * You should have received a copy of the GNU Lesser General Public
      23             :  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      24             :  */
      25             : 
      26             : #include "replace.h"
      27             : #include <tevent.h>
      28             : #include "lib/util/tevent_req_profile.h"
      29             : #include "lib/util/time_basic.h"
      30             : #include "lib/util/memory.h"
      31             : 
      32           8 : static bool tevent_req_profile_string_internal(
      33             :         const struct tevent_req_profile *profile,
      34             :         unsigned indent,
      35             :         unsigned max_indent,
      36             :         char **string)
      37             : {
      38           8 :         struct timeval start, stop, diff;
      39           8 :         struct timeval_buf start_buf, stop_buf;
      40           8 :         const char *req_name = NULL;
      41           8 :         const char *start_location = NULL;
      42           8 :         const char *stop_location = NULL;
      43           8 :         pid_t pid;
      44           8 :         enum tevent_req_state state;
      45           8 :         const char *state_buf = NULL;
      46           8 :         uint64_t user_error;
      47           8 :         const struct tevent_req_profile *sub = NULL;
      48           8 :         char *result;
      49             : 
      50           8 :         tevent_req_profile_get_name(profile, &req_name);
      51             : 
      52           8 :         tevent_req_profile_get_start(profile, &start_location, &start);
      53           8 :         timeval_str_buf(&start, false, true, &start_buf);
      54             : 
      55           8 :         tevent_req_profile_get_stop(profile, &stop_location, &stop);
      56           8 :         timeval_str_buf(&stop, false, true, &stop_buf);
      57             : 
      58           8 :         diff = tevent_timeval_until(&start, &stop);
      59             : 
      60           8 :         tevent_req_profile_get_status(profile, &pid, &state, &user_error);
      61             : 
      62           8 :         switch(state) {
      63           0 :         case TEVENT_REQ_INIT:
      64           0 :                 state_buf = "TEVENT_REQ_INIT";
      65           0 :                 break;
      66           0 :         case TEVENT_REQ_IN_PROGRESS:
      67           0 :                 state_buf = "TEVENT_REQ_IN_PROGRESS";
      68           0 :                 break;
      69           4 :         case TEVENT_REQ_DONE:
      70           4 :                 state_buf = "TEVENT_REQ_DONE";
      71           4 :                 break;
      72           0 :         case TEVENT_REQ_USER_ERROR:
      73           0 :                 state_buf = "TEVENT_REQ_USER_ERROR";
      74           0 :                 break;
      75           4 :         case TEVENT_REQ_TIMED_OUT:
      76           4 :                 state_buf = "TEVENT_REQ_TIMED_OUT";
      77           4 :                 break;
      78           0 :         case TEVENT_REQ_NO_MEMORY:
      79           0 :                 state_buf = "TEVENT_REQ_NO_MEMORY";
      80           0 :                 break;
      81           0 :         case TEVENT_REQ_RECEIVED:
      82           0 :                 state_buf = "TEVENT_REQ_RECEIVED";
      83           0 :                 break;
      84           0 :         default:
      85           0 :                 state_buf = "unknown";
      86           0 :                 break;
      87             :         }
      88             : 
      89          16 :         result = talloc_asprintf_append_buffer(
      90             :                 *string,
      91             :                 "%*s[%s] %s [%s] %s [%s] [%ju.%.6ju] -> %s (%d %"PRIu64"))\n",
      92             :                 indent,
      93             :                 "",
      94             :                 req_name,
      95             :                 start_location,
      96             :                 start_buf.buf,
      97             :                 stop_location,
      98             :                 stop_buf.buf,
      99           8 :                 (uintmax_t)diff.tv_sec,
     100           8 :                 (uintmax_t)diff.tv_usec,
     101             :                 state_buf,
     102             :                 (int)state,
     103             :                 user_error);
     104           8 :         if (result == NULL) {
     105           0 :                 return false;
     106             :         }
     107           8 :         *string = result;
     108             : 
     109           8 :         indent += 1;
     110             : 
     111           8 :         if (indent >= max_indent) {
     112           0 :                 return true;
     113             :         }
     114             : 
     115           8 :         for (sub = tevent_req_profile_get_subprofiles(profile);
     116          12 :              sub != NULL;
     117           4 :              sub = tevent_req_profile_next(sub)) {
     118           4 :                 bool ret;
     119             : 
     120           4 :                 ret = tevent_req_profile_string_internal(
     121             :                         sub,
     122             :                         indent,
     123             :                         max_indent,
     124             :                         string);
     125           4 :                 if (!ret) {
     126           0 :                         return false;
     127             :                 }
     128             :         }
     129             : 
     130           0 :         return true;
     131             : }
     132             : 
     133           4 : char *tevent_req_profile_string(TALLOC_CTX *mem_ctx,
     134             :                                 const struct tevent_req_profile *profile,
     135             :                                 unsigned indent,
     136             :                                 unsigned max_indent)
     137             : {
     138           4 :         char *result;
     139           4 :         bool ret;
     140             : 
     141           4 :         result = talloc_strdup(mem_ctx, "");
     142           4 :         if (result == NULL) {
     143           0 :                 return NULL;
     144             :         }
     145             : 
     146           4 :         ret = tevent_req_profile_string_internal(
     147             :                 profile,
     148             :                 indent,
     149             :                 max_indent,
     150             :                 &result);
     151           4 :         if (!ret) {
     152           0 :                 TALLOC_FREE(result);
     153           0 :                 return NULL;
     154             :         }
     155             : 
     156           4 :         return result;
     157             : }
     158             : 
     159           4 : static ssize_t tevent_req_profile_pack_one(
     160             :         const struct tevent_req_profile *profile,
     161             :         uint8_t *buf,
     162             :         size_t buflen)
     163             : {
     164           4 :         const char *req_name = NULL;
     165           4 :         const char *start_location = NULL;
     166           4 :         const char *stop_location = NULL;
     167           4 :         struct timeval start_time, stop_time;
     168           4 :         pid_t pid;
     169           4 :         enum tevent_req_state state;
     170           4 :         uint64_t user_error;
     171           4 :         size_t pack_len, len;
     172           4 :         int ret;
     173             : 
     174           4 :         tevent_req_profile_get_name(profile, &req_name);
     175           4 :         tevent_req_profile_get_start(profile, &start_location, &start_time);
     176           4 :         tevent_req_profile_get_stop(profile, &stop_location, &stop_time);
     177           4 :         tevent_req_profile_get_status(profile, &pid, &state, &user_error);
     178             : 
     179           4 :         len = strlen(req_name)+1;
     180           4 :         if (buflen >= len) {
     181           2 :                 memcpy(buf, req_name, len);
     182           2 :                 buf += len;
     183           2 :                 buflen -= len;
     184             :         }
     185             : 
     186           4 :         pack_len = len;
     187             : 
     188           4 :         len = strlen(start_location)+1;
     189           4 :         pack_len += len;
     190           4 :         if (pack_len < len) {
     191           0 :                 return -1;      /* overflow */
     192             :         }
     193             : 
     194           4 :         if (buflen >= len) {
     195           2 :                 memcpy(buf, start_location, len);
     196           2 :                 buf += len;
     197           2 :                 buflen -= len;
     198             :         }
     199             : 
     200           4 :         len = strlen(stop_location)+1;
     201           4 :         pack_len += len;
     202           4 :         if (pack_len < len) {
     203           0 :                 return -1;      /* overflow */
     204             :         }
     205             : 
     206           4 :         if (buflen >= len) {
     207           2 :                 memcpy(buf, stop_location, len);
     208           2 :                 buf += len;
     209           2 :                 buflen -= len;
     210             :         }
     211             : 
     212           4 :         ret = snprintf((char *)buf,
     213             :                        buflen,
     214             :                        "%ju %ju %ju %ju %d %d %"PRIu64"",
     215           4 :                        (uintmax_t)start_time.tv_sec,
     216           4 :                        (uintmax_t)start_time.tv_usec,
     217           4 :                        (uintmax_t)stop_time.tv_sec,
     218           4 :                        (uintmax_t)stop_time.tv_usec,
     219             :                        (int)pid,
     220             :                        (int)state,
     221             :                        user_error);
     222           4 :         if (ret < 0) {
     223           0 :                 return -1;
     224             :         }
     225             : 
     226             :         /*
     227             :          * Take care of the trailing 0. No overflow check, this would
     228             :          * be a VERY small number of bits for "int".
     229             :          */
     230           4 :         ret += 1;
     231             : 
     232           4 :         pack_len += ret;
     233             : 
     234           4 :         return pack_len;
     235             : }
     236             : 
     237           4 : ssize_t tevent_req_profile_pack(
     238             :         const struct tevent_req_profile *profile,
     239             :         uint8_t *buf,
     240             :         size_t buflen)
     241             : {
     242           4 :         const struct tevent_req_profile *sub = NULL;
     243           4 :         size_t num_sub;
     244           4 :         ssize_t pack_len, profile_len;
     245           4 :         int ret;
     246             : 
     247           4 :         num_sub = 0;
     248           4 :         pack_len = 0;
     249             : 
     250           4 :         for (sub = tevent_req_profile_get_subprofiles(profile);
     251           6 :              sub != NULL;
     252           2 :              sub = tevent_req_profile_next(sub)) {
     253           2 :                 num_sub += 1;
     254             :         }
     255             : 
     256           4 :         ret = snprintf((char *)buf, buflen, "%zu ", num_sub);
     257           4 :         if (ret < 0) {
     258           0 :                 return -1;
     259             :         }
     260             : 
     261           4 :         if (buflen > (size_t)ret) {
     262           2 :                 buf += ret;
     263           2 :                 buflen -= ret;
     264             :         }
     265             : 
     266           4 :         pack_len = ret;
     267             : 
     268           4 :         profile_len = tevent_req_profile_pack_one(profile, buf, buflen);
     269           4 :         if (profile_len == -1) {
     270           0 :                 return -1;
     271             :         }
     272             : 
     273           4 :         if (buflen >= (size_t)profile_len) {
     274           2 :                 buf += profile_len;
     275           2 :                 buflen -= profile_len;
     276             :         }
     277             : 
     278           4 :         pack_len += profile_len;
     279           4 :         if (pack_len < profile_len) {
     280           0 :                 return -1;      /* overflow */
     281             :         }
     282             : 
     283           4 :         for (sub = tevent_req_profile_get_subprofiles(profile);
     284           6 :              sub != NULL;
     285           2 :              sub = tevent_req_profile_next(sub)) {
     286             : 
     287           2 :                 profile_len = tevent_req_profile_pack(sub, buf, buflen);
     288           2 :                 if (profile_len == -1) {
     289           0 :                         return -1;
     290             :                 }
     291             : 
     292           2 :                 if (buflen >= (size_t)profile_len) {
     293           1 :                         buf += profile_len;
     294           1 :                         buflen -= profile_len;
     295             :                 }
     296             : 
     297           2 :                 pack_len += profile_len;
     298           2 :                 if (pack_len < profile_len) {
     299           0 :                         return -1;      /* overflow */
     300             :                 }
     301             :         }
     302             : 
     303           0 :         return pack_len;
     304             : }
     305             : 
     306          16 : static bool parse_uintmax(const char *buf,
     307             :                           char delimiter,
     308             :                           uintmax_t *presult,
     309             :                           char **p_endptr)
     310             : {
     311          16 :         uintmax_t result;
     312          16 :         char *endptr;
     313             : 
     314          16 :         result = strtoumax(buf, &endptr, 10);
     315          16 :         if ((result == UINTMAX_MAX) && (errno == ERANGE)) {
     316           0 :                 return false;
     317             :         }
     318          16 :         if (*endptr != delimiter) {
     319           0 :                 return false;
     320             :         }
     321             : 
     322          16 :         *presult = result;
     323          16 :         *p_endptr = endptr+1;
     324             : 
     325          16 :         return true;
     326             : }
     327             : 
     328           2 : static ssize_t tevent_req_profile_unpack_one(
     329             :         const uint8_t *buf,
     330             :         size_t buflen,
     331             :         struct tevent_req_profile *profile)
     332             : {
     333           2 :         const char *orig_buf = (const char *)buf;
     334           2 :         const char *req_name = NULL;
     335           2 :         const char *start_location = NULL;
     336           2 :         const char *stop_location = NULL;
     337           2 :         uintmax_t start_sec, start_usec, stop_sec, stop_usec, pid, state;
     338           2 :         uintmax_t user_error;
     339           2 :         char *next = NULL;
     340           2 :         size_t len;
     341           2 :         bool ok;
     342             : 
     343           2 :         if (buflen == 0) {
     344           0 :                 return -1;
     345             :         }
     346           2 :         if (buf[buflen-1] != '\0') {
     347           0 :                 return -1;
     348             :         }
     349             : 
     350           2 :         req_name = (const char *)buf;
     351           2 :         len = strlen(req_name)+1;
     352             : 
     353           2 :         buf += len;
     354           2 :         buflen -= len;
     355           2 :         if (buflen == 0) {
     356           0 :                 return -1;
     357             :         }
     358             : 
     359           2 :         start_location = (const char *)buf;
     360           2 :         len = strlen(start_location)+1;
     361             : 
     362           2 :         buf += len;
     363           2 :         buflen -= len;
     364           2 :         if (buflen == 0) {
     365           0 :                 return -1;
     366             :         }
     367             : 
     368           2 :         stop_location = (const char *)buf;
     369           2 :         len = strlen(stop_location)+1;
     370             : 
     371           2 :         buf += len;
     372           2 :         buflen -= len;
     373           2 :         if (buflen == 0) {
     374           0 :                 return -1;
     375             :         }
     376             : 
     377           2 :         ok = parse_uintmax((const char *)buf, ' ', &start_sec, &next);
     378           2 :         if (!ok) {
     379           0 :                 return -1;
     380             :         }
     381             : 
     382           2 :         ok = parse_uintmax(next, ' ', &start_usec, &next);
     383           2 :         if (!ok) {
     384           0 :                 return -1;
     385             :         }
     386             : 
     387           2 :         ok = parse_uintmax(next, ' ', &stop_sec, &next);
     388           2 :         if (!ok) {
     389           0 :                 return -1;
     390             :         }
     391             : 
     392           2 :         ok = parse_uintmax(next, ' ', &stop_usec, &next);
     393           2 :         if (!ok) {
     394           0 :                 return -1;
     395             :         }
     396             : 
     397           2 :         ok = parse_uintmax(next, ' ', &pid, &next);
     398           2 :         if (!ok) {
     399           0 :                 return -1;
     400             :         }
     401             : 
     402           2 :         ok = parse_uintmax(next, ' ', &state, &next);
     403           2 :         if (!ok) {
     404           0 :                 return -1;
     405             :         }
     406             : 
     407           2 :         ok = parse_uintmax(next, '\0', &user_error, &next);
     408           2 :         if (!ok) {
     409           0 :                 return -1;
     410             :         }
     411             : 
     412           2 :         ok = tevent_req_profile_set_name(profile, req_name);
     413           2 :         if (!ok) {
     414           0 :                 return -1;
     415             :         }
     416             : 
     417           4 :         ok = tevent_req_profile_set_start(
     418             :                 profile,
     419             :                 start_location,
     420           2 :                 (struct timeval){ .tv_sec=start_sec, .tv_usec=start_usec });
     421           2 :         if (!ok) {
     422           0 :                 return -1;
     423             :         }
     424             : 
     425           4 :         ok = tevent_req_profile_set_stop(
     426             :                 profile,
     427             :                 stop_location,
     428           2 :                 (struct timeval){ .tv_sec=stop_sec, .tv_usec=stop_usec });
     429           2 :         if (!ok) {
     430           0 :                 return -1;
     431             :         }
     432             : 
     433           2 :         tevent_req_profile_set_status(
     434             :                 profile,
     435             :                 pid,
     436             :                 (enum tevent_req_state)state,
     437             :                 user_error);
     438             : 
     439           2 :         return next - orig_buf;
     440             : }
     441             : 
     442           2 : ssize_t tevent_req_profile_unpack(
     443             :         const uint8_t *buf,
     444             :         size_t buflen,
     445             :         TALLOC_CTX *mem_ctx,
     446             :         struct tevent_req_profile **p_profile)
     447             : {
     448           2 :         const uint8_t *orig_buf = buf;
     449           2 :         struct tevent_req_profile *profile = NULL;
     450           2 :         uintmax_t i, num_subprofiles;
     451           2 :         char *next = NULL;
     452           2 :         bool ok;
     453           2 :         ssize_t len;
     454             : 
     455           2 :         errno = 0;
     456             : 
     457           2 :         if (buf[buflen-1] != '\0') {
     458           0 :                 return -1;
     459             :         }
     460             : 
     461           2 :         ok = parse_uintmax((const char *)buf, ' ', &num_subprofiles, &next);
     462           2 :         if (!ok) {
     463           0 :                 return -1;
     464             :         }
     465             : 
     466           2 :         len = (next - (const char *)buf);
     467             : 
     468           2 :         buf += len;
     469           2 :         buflen -= len;
     470             : 
     471           2 :         profile = tevent_req_profile_create(mem_ctx);
     472           2 :         if (profile == NULL) {
     473           0 :                 return -1;
     474             :         }
     475             : 
     476           2 :         len = tevent_req_profile_unpack_one(buf, buflen, profile);
     477           2 :         if (len == -1) {
     478           0 :                 TALLOC_FREE(profile);
     479           0 :                 return -1;
     480             :         }
     481             : 
     482           2 :         buf += len;
     483           2 :         buflen -= len;
     484             : 
     485           3 :         for (i=0; i<num_subprofiles; i++) {
     486           1 :                 struct tevent_req_profile *subprofile;
     487             : 
     488           1 :                 len = tevent_req_profile_unpack(
     489             :                         buf,
     490             :                         buflen,
     491             :                         profile,
     492             :                         &subprofile);
     493           1 :                 if (len == -1) {
     494           0 :                         TALLOC_FREE(profile);
     495           0 :                         return -1;
     496             :                 }
     497           1 :                 buf += len;
     498           1 :                 buflen -= len;
     499             : 
     500           1 :                 tevent_req_profile_append_sub(profile, &subprofile);
     501             :         }
     502             : 
     503           2 :         *p_profile = profile;
     504             : 
     505           2 :         return buf - orig_buf;
     506             : }

Generated by: LCOV version 1.14