Search code examples
cvariadic-functionssystemdvariadic

How to wrap a variadic function in C


I'm trying to wrap a variadic function to validate the input beforehand. To be precise i need to call sd_notifyf(int unset_environment, const char *format, ...).

https://www.freedesktop.org/software/systemd/man/sd_notify.html

But before calling sd_notifyf I want to validate the input for the format and then call sd_notify() in the wrapped function.

Currently I've tried the following:

void wrapperFunc(int unset_environment, const char *format, ...) {
  va_list list;
  va_start(list, format);

  //validation of va_args

  sd_notifyf(unset_environment, format, list);

  va_end(list);
}

int main(int argc, char *argv[]) {
  wrapperFunc(0, "STATUS=args: '%s' : '%s'", "arg1", "arg2");
}

In the real code, wrapperFunc() will be called when starting a service, so you can understand why I'm trying to call sd_notifyf().

With my current implementation the following is returned when checking the status of the service: STATUS=args: '^P' : 'arg2'

Why does it only show the second argument properly? And how can I achieve to wrap sd_notifyf() properly?


Solution

  • The behaviour of your code is undefined.

    sd_notifyf is a variadic function not a function taking as the last parameter va_list

    int sd_notifyf( int unset_environment,
        const char *format,
        …);
    

    I am afraid that you can not write the wrapper function as there is no version of the sd_notify function which takes va_list

    You can only use the macro definition for that.

    #define wrapperMacro(unset_environment, format, ...)\
        do{\
            /* do some stuff */\
             sd_notifyf(unset_environment, format, __VA_ARGS__);\
        }while(0)
    

    You can also use string printf function (in this case vsnprintf):

    #define LARGE_ENOUGH_TO_ACCOMODATE_THE_STRING 64
    
    void wrapperFunc(int unset_environment, const char *format, ...) {
      va_list list;
      va_start(list, format);
      char buff[LARGE_ENOUGH_TO_ACCOMODATE_THE_STRING];
    
      vsnprintf(buff, sizeof(buff), format, list);
    
      sd_notify(unset_environment, buff);
    
      va_end(list);
    }