*nix Documentation Project
·  Home
 +   man pages
·  Linux HOWTOs
·  FreeBSD Tips
·  *niX Forums

  man pages->HP-UX 11i man pages -> ptrace (2)              
Title
Content
Arch
Section
 

Contents


 ptrace(2)                                                         ptrace(2)
                          PA Only; TO BE OBSOLETED



 NAME    [Toc]    [Back]
      ptrace() - process trace

 SYNOPSIS    [Toc]    [Back]
      #include <sys/ptrace.h>

      long ptrace(
           int request,
           pid_t pid,
           long addr,
           long data,
           long addr2
      );

    Remarks    [Toc]    [Back]
      ptrace() is not available on Itanium(R)-based systems.  Its use is
      discouraged because it is targeted for removal from HP-UX.  Please use
      ttrace(2) instead.

      Much of the functionality of ptrace() is highly dependent on the
      underlying hardware.  An application that uses this system call should
      not be expected to be portable across architectures or implementations.

 DESCRIPTION    [Toc]    [Back]
      The ptrace() system call provides a means by which a process can
      control the execution of another process.  Its primary use is for the
      implementation of a breakpoint debugging mechanism (see adb(1)) and
      involves a tracing and a traced process.  The traced process behaves
      normally until it encounters a signal (see signal(2) for the list) at
      which time it enters a stopped state and the tracing process is
      notified via wait() (see wait(2)).

      A traced process may also enter the stopped state without encountering
      a signal.  This can happen if the traced process stops in response to
      specific events that it encounters during the course of its execution.
      To make this happen, the tracing process has to set specific event
      flags in the context of the traced process.  This mechanism will be
      described later in greater detail.

      When the traced process is in the stopped state, the tracing process
      can use ptrace() to examine and modify the "core image".  Also, the
      tracing process can cause the traced process to either terminate or
      continue, with the possibility of ignoring the signal that caused it
      to stop.

      To forestall possible fraud, ptrace() inhibits the set-user-ID
      facility on subsequent exec*() calls.  If a traced process calls
      exec*() it stops before executing the first instruction of the new
      image, showing signal SIGTRAP.





 Hewlett-Packard Company            - 1 -   HP-UX 11i Version 2: August 2003






 ptrace(2)                                                         ptrace(2)
                          PA Only; TO BE OBSOLETED



      The request argument determines the precise action to be taken by
      ptrace().

      The following request argument is used by the child process that will
      be traced.

           PT_SETTRC      This request must be issued by a child process if
                          it is to be traced by its parent.  It turns on the
                          child's trace flag which stipulates that the child
                          should be left in a stopped state upon receipt of
                          a signal rather than the state specified by func
                          (see signal(2)).  The pid, addr, data, and addr2
                          arguments are ignored and a return value is not
                          defined for this request.  Peculiar results occur
                          if the parent does not expect to trace the child.

      The remainder of the request arguemnt values can only be used by the
      tracing process.  For each, pid is the process ID of the process being
      traced which must be in a stopped state before these requests are
      made.  The responsibility of ensuring that the traced process is in a
      stopped state before a request is issued lies with the tracing
      process.

           PT_RDUSER    [Toc]    [Back]
           PT_RIUSER      The word specified by the address in the addr
                          argument in the address space of the traced
                          process is returned to the tracing process.  If
                          the instruction (I) and data (D) space are
                          separated, request PT_RIUSER returns a word from I
                          space and request PT_RDUSER returns a word from D
                          space.  If I and D space are not separated, either
                          request produces equivalent results.  The data and
                          addr2 arguments are ignored.

                          These two requests fail if addr is not the start
                          address of a word, in which case a value of -1 is
                          returned to the tracing process and errno is set
                          to [EIO].

           PT_RUAREA      The word specified by the address in the addr
                          argument in the user area of the traced process in
                          the system's address space (see <sys/user.h>) is
                          returned to the tracing process.  The addresses in
                          this area are system dependent but start at zero
                          and the limit can be obtained from <sys/user.h>.
                          The data and addr2 arguments are ignored.

                          This request fails if addr is not the starting
                          address of a word or is outside the user area, in
                          which case the value of -1 is returned to the
                          tracing process and errno is set to [EIO].



 Hewlett-Packard Company            - 2 -   HP-UX 11i Version 2: August 2003






 ptrace(2)                                                         ptrace(2)
                          PA Only; TO BE OBSOLETED



           PT_WDUSER    [Toc]    [Back]
           PT_WIUSER      The value in the data argument is written into the
                          address space of the traced process at the
                          location specified in the addr argument.
                          PT_WIUSER writes a word into I space and PT_WDUSER
                          writes a word in D space.  Upon successful
                          completion, the value written into the address
                          space of the traced process is returned to the
                          tracing process.  The addr2 argument is ignored.

                          These two requests fail if addr is not the
                          starting address of a word.  It will also fail if
                          the addr argument is a location in a pure
                          procedure space and either another process is
                          executing in that space or the tracing process
                          does not have write access to the executable file
                          corresponding to that space.  A value of -1 is
                          returned to the tracing process if it fails and
                          errno is set to [EIO].

           PT_WUAREA      This request is not supported and returns a -1,
                          along with setting errno to [EIO] (no affect upon
                          the user area of the traced process).

           PT_RUREGS      The word at the location specified by the addr
                          argument in the save_state structure at the base
                          of the per-process kernel stack is returned to the
                          tracing process.  The addr argument must be wordaligned
 and less than STACKSIZE*NBPG (see
                          <sys/param.h> and <machine/param.h>).  The
                          save_state structure contains the registers and
                          other information about the process.  The data and
                          addr2 arguments are ignored.

           PT_WUREGS      The word at the location specified by the addr
                          argument in the save_state structure at the base
                          of the per-process kernel stack is updated.  Only
                          a few locations can be written in this way: the
                          general registers, most floating-point registers,
                          a few control registers and certain bits of the
                          interruption processor status word.  The addr2
                          argument is ignored.

           PT_RDDATA    [Toc]    [Back]
           PT_RDTEXT      These requests are identical to PT_RDUSER and
                          PT_RIUSER except that the data argument specifies
                          the number of bytes to read and the addr2 argument
                          specifies where to store that data in the tracing
                          process.





 Hewlett-Packard Company            - 3 -   HP-UX 11i Version 2: August 2003






 ptrace(2)                                                         ptrace(2)
                          PA Only; TO BE OBSOLETED



           PT_WRDATA    [Toc]    [Back]
           PT_WRTEXT      These requests are identical to PT_WDUSER and
                          PT_WIUSER except that the data argument specifies
                          the number of bytes to write and the addr2
                          argument specifies where to read that data in the
                          tracing process.

           PT_CONTIN      This request causes the traced process to resume
                          execution.  If the data argument is 0, all pending
                          signals including the one that caused the traced
                          process to stop, are canceled before it resumes
                          execution.  If the data argument is a valid signal
                          number, the traced process resumes execution as if
                          it had incurred that signal and any other pending
                          signals are canceled.  The addr2 argument is
                          ignored.

                          If the addr argument is not 1, the Instruction
                          Address Offset Queue (program counter) is loaded
                          with the values addr and addr+4 before execution
                          resumes.  Otherwise, execution resumes from the
                          point where it was interrupted.

                          Upon successful completion, the value of the data
                          argument is returned to the tracing process.

                          This request fails if the data argument is not 0
                          or a valid signal number and a value of -1 is
                          returned to the tracing process and errno is set
                          to [EIO].

           PT_EXIT        This request causes the traced process to
                          terminate in the same manner as doing a exit()
                          call.  The addr, data and addr2 arguments are
                          ignored.

           PT_SINGLE      This request causes a flag to be set so that an
                          interrupt occurs upon the completion of one
                          machine instruction.  It then executes the same
                          way as listed for request PT_CONTIN, effectively
                          allowing the single-stepping of the traced
                          process.  If the processor does not provide a
                          trace bit, this request returns an error.

                          Whether or not the trace bit remains set after
                          this interrupt is a function of the hardware.

           PT_ATTACH      This request stops the process specified by the
                          pid argument and allows the calling process to
                          trace it.  The process does not have to be a child
                          of the calling process but the effective user ID



 Hewlett-Packard Company            - 4 -   HP-UX 11i Version 2: August 2003






 ptrace(2)                                                         ptrace(2)
                          PA Only; TO BE OBSOLETED



                          of the calling process must match the real and
                          saved user ID of process pid unless the effective
                          user ID of the tracing process is a superuser.
                          The calling process can use the wait() system call
                          to wait for process pid to stop.  The addr, data,
                          and addr2 arguments are ignored.

           PT_DETACH      This request detaches the traced process specified
                          by the pid argument and allows it to continue its
                          execution in the manner of PT_CONTIN.

                          If the addr argument is not 1, the Instruction
                          Address Offset Queue (program counter) is loaded
                          with the values from the addr and addr2 arguments.

           PT_CONTIN1     This request causes the traced process to resume
                          execution with all its pending signals intact.  If
                          the data argument is 0, the signal that caused the
                          traced process to stop is canceled before the
                          traced process resumes execution.  If the data
                          argument is a valid signal number, the traced
                          process resumes execution as if it had received
                          that signal.  The addr argument must be equal to 1
                          for this request and the addr2 argument is
                          ignored.  Upon successful completion, the value of
                          data is returned to the tracing process.

                          This request fails if data is not 0 or a valid
                          signal number and a value of -1 is returned to the
                          tracing process and errno is set to [EIO].

           PT_SINGLE1     This request causes a flag to be set so that an
                          interrupt occurs upon the completion of one
                          machine instruction.  It then executes the same
                          steps as listed above for request PT_CONTIN1 and
                          provides the single stepping of the traced
                          process.  If the processor does not provide a
                          trace bit, this request returns an error.

                          Whether or not the trace bit remains set after
                          this interrupt is a function of the hardware.

      As noted earlier, a tracing process can set event flags in the context
      of the traced process to make it respond to specific events during its
      execution.  These events are:

           PTRACE_SIGNAL       This event flag indicates that when
                               processing signals, the traced process needs
                               to examine signal mask bits set in its
                               context by the tracing process.  See the
                               ptrace_event structure description under



 Hewlett-Packard Company            - 5 -   HP-UX 11i Version 2: August 2003






 ptrace(2)                                                         ptrace(2)
                          PA Only; TO BE OBSOLETED



                               PT_SET_EVENT_MASK for further details.

                               If the signal being processed has its signal
                               mask bit set, signal processing continues as
                               though the process was not traced.  The
                               traced process is not stopped and the tracing
                               process is not notified of the signal.  If
                               the signal mask bit is not set for the signal
                               being processed, the traced process is
                               stopped and the tracing process is notified
                               via a wait() call (see wait(2)).

                               Note that the SIGKILL signal is an exception
                               to this rule in that it can never be
                               unmasked; it behaves as though its mask bit
                               were always set, whether or not it is
                               actually set.  Consequently, a SIGKILL signal
                               cannot be used to stop a traced process.

                               In this respect, a SIGTRAP signal is also
                               special in that it is specifically used to
                               stop traced processes.  A SIGTRAP signal
                               should therefore never be masked.  Setting a
                               mask bit for SIGTRAP will result in
                               unexpected system behavior.

           PTRACE_FORK         This event flag indicates that the traced
                               process needs to take special action when it
                               invokes the fork() call.  When set, both the
                               parent and child processes stop (the child
                               after marking itself as the traced process
                               and adopting its parent's debugger).  Both
                               processes log the fact that they stopped in
                               response to a PTRACE_FORK event.  Further,
                               the child's pid argument value is logged in
                               the parent's context and the parent's pid
                               argument value is logged in the child's
                               context.  The child does not inherit its
                               parent's event flags.  See the ptrace_state
                               structure description under
                               PT_GET_PROCESS_STATE for further details.

           PTRACE_VFORK        This event flag indicates that the traced
                               process needs to take special action when it
                               invokes vfork().  When set, the child process
                               stops after marking itself as a traced
                               process and adopting its parent's debugger.
                               The fact that a PTRACE_VFORK event was
                               handled is logged in the context of both the
                               parent and child processes.  Further, the
                               child's pid argument value is logged in the



 Hewlett-Packard Company            - 6 -   HP-UX 11i Version 2: August 2003






 ptrace(2)                                                         ptrace(2)
                          PA Only; TO BE OBSOLETED



                               parent's context and the parent's pid
                               argument value is logged in the child's
                               context.  The child does not inherit its
                               parent's event flags.  See the ptrace_state
                               structure description under
                               PT_GET_PROCESS_STATE for further details.

                               It is important to note that the warnings
                               with respect to vfork() (see vfork(2)),
                               continue to apply here.  It needs to be
                               remembered that when the child process stops,
                               its parent process is suspended and that the
                               child borrows the parent's memory and thread
                               of control until a call is done to either
                               exec*() or exit(), or it exits abnormally
                               (see exec(2) and exit(2)).

           PTRACE_EXEC         This event flag indicates that the traced
                               process needs to take special action when it
                               invokes exec*().  When set, the traced
                               process stops after logging the fact that it
                               stopped in response to a PTRACE_EXEC event.
                               It also logs information pertaining to the
                               path or file argument of exec*().  This
                               includes a pointer to the path name string
                               and the length of the path name string.  See
                               the ptrace_state structure description under
                               PT_GET_PROCESS_STATE for further details.

           PTRACE_EXIT         This event flag indicates that the traced
                               process needs to take special action when it
                               invokes exit().  When set the traced process
                               stops after logging the PTRACE_EXIT event.

           PT_SET_EVENT_MASK   This request is used by the calling process
                               to specify event flags and signal mask values
                               that it wants the traced process to respond
                               to.  It does so by writing the contents of
                               the ptrace_event data structure in the user
                               space pointed to by the addr argument into
                               the context of the traced process.  The data
                               argument specifies the number of bytes to be
                               transferred.  The addr2 argument is ignored.

                               The request fails if the number of bytes
                               specified is less than zero or greater than
                               the size of the ptrace_event structure and
                               results in errno being set to [EIO].  The
                               typedef for the ptrace_event data structure
                               is shown below:




 Hewlett-Packard Company            - 7 -   HP-UX 11i Version 2: August 2003






 ptrace(2)                                                         ptrace(2)
                          PA Only; TO BE OBSOLETED



                               typedef struct ptrace_event{
                                    sigset_t  pe_signals;
                                    events_t  pe_set_event;
                                    char     pe_spare[28];
                               } ptrace_event_t;

                               Event flags are set in the pe_set_event
                               member of the ptrace_event data structure.
                               An event flag is set when the tracing process
                               wants the traced process to respond to a
                               particular event.  As detailed earlier, the
                               event flags defined are PTRACE_EXEC,
                               PTRACE_EXIT, PTRACE_FORK, PTRACE_SIGNAL and
                               PTRACE_VFORK.  See the definition of events_t
                               in <sys/ptrace.h> for more details.

                               Signal mask values are set in the pe_signals
                               member of the ptrace_event structure.  This
                               member is activated by a PTRACE_SIGNAL event
                               flag being set in the pe_set_event member.
                               Mask values set in the pe_signals member
                               correspond to signals that need to be masked
                               from the tracing process that the traced
                               process received; that is, these are signals
                               received by the traced process that the
                               tracing process does not want to be informed
                               about.  The pe_signals member is described by
                               the type definition sigset_t which is defined
                               in <signal.h>.

           PT_GET_EVENT_MASK   This request is used by the calling process
                               to determine the event flags and signal mask
                               values that have been set in the traced
                               process's context by the last
                               PT_SET_EVENT_MASK request.  The data argument
                               specifies the number of bytes to be read from
                               the traced process' context into the
                               ptrace_event data structure pointed to by
                               addr argument.  The addr2 argument is
                               ignored.

                               The request fails if the number of bytes
                               requested is less than zero or greater than
                               the size of the ptrace_event structure which
                               results in errno being set to [EIO].

           PT_GET_PROCESS_STATE    [Toc]    [Back]
                               This request is used by the calling process
                               to access state information logged by the
                               traced process after it has responded to an
                               event.  The request reads data bytes of data



 Hewlett-Packard Company            - 8 -   HP-UX 11i Version 2: August 2003






 ptrace(2)                                                         ptrace(2)
                          PA Only; TO BE OBSOLETED



                               from the traced process's context into the
                               ptrace_state data structure pointed to by the
                               addr argument.  The addr2 argument is
                               ignored.

                               The ptrace_state data structure is defined in
                               <sys/ptrace.h> and has the structure:

                               typedef struct ptrace_state{
                                    events_t  pe_report_event;
                                    int       pe_path_len;
                                    pid_t     pe_other_pid;
                               } ptrace_state_t;

                               The event that the traced process responded
                               to and stopped for is logged in the
                               pe_report_event member.  One of the following
                               structure members PTRACE_EXEC, PTRACE_EXIT,
                               PTRACE_FORK, PTRACE_SIGNAL, or PTRACE_VFORK
                               is logged here.  See the definition of
                               events_t in <sys/ptrace.h> for more details.

                               If the event that the traced process
                               responded to was PTRACE_EXEC, then the
                               pe_path_len member provides the length of the
                               path name string (i.e. the executable file
                               path name) not including the null terminating
                               character.

                               If the event that the traced process
                               responded to was PTRACE_FORK or PTRACE_VFORK,
                               then the pe_other_pid member provides the
                               parent's pid when accessed from the child's
                               context, and the child's pid when accessed
                               from the parent's context.

                               The request fails if the number of bytes
                               requested is less than zero or greater than
                               the size of the ptrace_event structure and
                               results in errno being set to [EIO].

           PT_GET_PROCESS_PATHNAME    [Toc]    [Back]
                               If the traced process is responded to and
                               stopped for a PTRACE_EXEC event, then the
                               calling process uses this request to access
                               the path name of the executable file that is
                               provided as a path or file argument to
                               exec*().  The request reads the number of
                               bytes of the path name string specified by
                               the data argument from the traced process's
                               context into the data buffer in user space



 Hewlett-Packard Company            - 9 -   HP-UX 11i Version 2: August 2003






 ptrace(2)                                                         ptrace(2)
                          PA Only; TO BE OBSOLETED



                               pointed to by the addr argument.  The addr2
                               argument is ignored.  In the typical case,
                               value in the data argument is equal to the
                               value of the pe_path_len member of the
                               ptrace_state structure returned via the
                               PT_GET_PROCESS_STATE request.

                               If the number of bytes requested is greater
                               than zero but less than the length of the
                               path name string, then the number of bytes
                               requested is returned.  If the number of
                               bytes requested is greater than the length of
                               the path name string, then the full path name
                               string (including the null terminating
                               character) is returned.

                               The request fails if the number of bytes
                               requested is less than zero and results in
                               errno being set to [EIO].

 EXAMPLES    [Toc]    [Back]
      The following example illustrates the use of some of the ptrace()
      calls by a tracing process.

      #include <stdio.h>
      #include <signal.h>
      #include <sys/wait.h>
      #include <sys/ptrace.h>
      #define BUFSIZ  1024
      #define MAXPATH 1024

      pid_t           npid, cpid, pid;
      int             status, errors=0, pathlength;
      ptrace_event_t  *event_addr;
      ptrace_state_t  *state_addr;
      char            *buf_addr;
      size_t          event_len, state_len;
      int             filed[2];

      child()
      {
          int n, bar;

          close(filed[1]);
          /* Wait for parent to write to pipe */
          while ((n = read(filed[0], &bar, BUFSIZ)) == 0);

          /* Now the child can exec. */
          if (execlp("ls", "ls", (char *)0) < 0)   /* error during exec */
                  printf("Child: exec failed\n");
          exit(0);



 Hewlett-Packard Company           - 10 -   HP-UX 11i Version 2: August 2003






 ptrace(2)                                                         ptrace(2)
                          PA Only; TO BE OBSOLETED



      }

      parent()
      {
          close(filed[0]);

          /* Before child does an exec, attach it and set its event flag. */
          if (ptrace(PT_ATTACH,pid))  /* failed to attach process */
              printf("Parent: Failed to attach child\n");
          if (pid != wait(&status))   /* wait failed */
              printf("Parent: attach failed with wrong wait status\n");
          if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
              printf("Parent: SIGTRAP didn't stop child\n");

          /*
           * The child process has now stopped.  Set its event flag indicating
           * that it needs to trigger on a PTRACE_EXEC event.
           */
          event_addr->pe_set_event = PTRACE_EXEC;
          if (ptrace(PT_SET_EVENT_MASK, pid, event_addr, event_len))
              printf("Parent: PT_SET_EVENT_MASK ptrace request failed\n");
          if (pid != wait(&status))   /* wait failed */
              printf("Parent: wait() failed with wrong wait status\n");

          /*
           * Send the child a message so it can break out of the while loop.
           * Get it running so it can exec.
           */
          write(filed[1], "now run", 7);
          if (ptrace(PT_CONTIN, pid, 1, 0) != 0)
              printf("Parent: failed to get child process running\n");
          /*
           * Wait for the traced child to stop after the exec system call in
           * response to an exec event set in its ptrace_event structure.
           */
          if (pid != (npid = wait(&status)))   /* wait failed */
              printf("Parent: wait() failed with wrong status\n");
          if (!WIFSTOPPED(status))
              printf("Parent: invalid wait() completion\n");

          /*
           * Child has stopped; fetch its process state and examine state
           * information.
           */
          if (ptrace(PT_GET_PROCESS_STATE, pid, state_addr, state_len) < 0)
              printf("Parent: PT_GET_PROCESS_STATE ptrace request failed\n");
          if (pid != wait(&status))   /* wait failed */
              printf("Parent: wait() failed with wrong wait status\n");

          /* Check if the pathlength value returned is non-zero */
          if ((pathlength = state_addr->pe_path_len) == 0)



 Hewlett-Packard Company           - 11 -   HP-UX 11i Version 2: August 2003






 ptrace(2)                                                         ptrace(2)
                          PA Only; TO BE OBSOLETED



              printf("Parent: zero length pathname returned\n");

          /* Fetch exec'd file pathname and store it in the buffer. */
          if (ptrace(PT_GET_PROCESS_PATHNAME, pid, buf_addr, (pathlength+1))
              < 0){
              printf("Parent: Failed to get exec pathname\n");
          } else {
              printf("Parent: the exec pathname is %s\n", buf_addr);
              if (pid != wait(&status))   /* wait failed */
                  printf("Parent: wait() failed with wrong status\n");
          }
      }

      main()
      {
          event_len = sizeof(ptrace_event_t);
          state_len = sizeof(ptrace_state_t);
          event_addr = calloc(event_len, 1);
          state_addr = calloc(state_len, 1);
          buf_addr = calloc(MAXPATH, 1);
          pipe(filed);
          switch (pid = fork()) {
              case -1:
                  exit(1);
              case 0:
                  child();
                  break;
              default:
                  parent();
                  break;
          }
      }

 ERRORS    [Toc]    [Back]
      If the ptrace() call fails, errno is set to one of the following
      values:

           [EACCES]       The executable image of the process being attached
                          resides across an interruptible NFS mount.

           [EIO]          Argument request contains an illegal number.

           [EIO]          The PT_SETTRC request is called with a data
                          argument that is less than zero, not a multiple of
                          four or contains an address that is not wordaligned.


           [EIO]          Attempting to write to a memory segment of the
                          traced process that is not writable, attempting to
                          write to page 0 or the request argument is out of
                          range.



 Hewlett-Packard Company           - 12 -   HP-UX 11i Version 2: August 2003






 ptrace(2)                                                         ptrace(2)
                          PA Only; TO BE OBSOLETED



           [EIO]          The PT_CONTIN request is being used with an
                          invalid data signal number argument.

           [EIO]          Attempting to write to the user area via the
                          PT_WUAREA request.

           [EPERM]        The specified process cannot be attached for
                          tracing.

           [EPERM]        The process specified in the pid argument is
                          already being traced or refers to the calling
                          process itself.

           [ESRCH]        pid specifies a process to be traced that does not
                          exist or has not executed a ptrace() call that has
                          done a PT_SETTRC request.

 SEE ALSO    [Toc]    [Back]
      adb(1), exec(2), exit(2), signal(2), ttrace(2), wait(2).

 STANDARDS CONFORMANCE    [Toc]    [Back]
      ptrace(): SVID2, SVID3, XPG2


 Hewlett-Packard Company           - 13 -   HP-UX 11i Version 2: August 2003
[ Back ]
      
      
 Similar pages
Name OS Title
ptrace Tru64 Trace the execution of a child process
moptrace OpenBSD MOP Trace Utility
trpt Tru64 Transliterates protocol trace
trpt FreeBSD transliterate protocol trace
truss FreeBSD trace system calls
vxtrace HP-UX trace operations on volumes
voltrace Tru64 Trace operations on volumes
trpt OpenBSD transliterate protocol trace
kdump FreeBSD display kernel trace data
kdump OpenBSD display kernel trace data
Copyright © 2004-2005 DeniX Solutions SRL
newsletter delivery service