fork/exec clobbers write. I need ideas why...

On my *nix box, I have a telegram program.

When I go like
tel person "la\nla\nla\n"

the person sees
"la\nla\nla\n"

However, when I have a program that forks and execs tel like:

pid = fork();
if (pid < 0) {
perror("fork failed");
exit(EXIT_FAILURE);
}
if (pid == 0) {
execlp("tel", "tel", user, what, (char *)0);
perror("execlp tel failed");
exit(EXIT_FAILURE);
}

and pass the string "la\nla\nla\n" to execlp()

The person sees
la
la
la

I'm pretty sure the exec() is clobbering tel. In the source code for tel, I see

void dotelegram(bool nl)
{
int ch;

/* Ask the user for a message if we don't already have one */
if \(telmsg == NULL || telmsg[0] == '\\0' || telmsg[0] == '\\n'\)
\{
    if \(nl\) putchar\('\\n'\);
    printf\("Msg: "\);
    fgets\(telmsg= linebuf, LBSIZE, stdin\);
    if \(telmsg[0] == '\\n'\) done\(0\);
\}

/* slow down if we are sending stuff too fast */
if \(f_wrthist != NULL\)
\{
    sleep\(check_flood\(\)\);
    register_tel\(\);
\}

/* send him a banner, if we weren't writing him already */
if \(!nested_write\(\)\)
        sendbanner\(\);

/* Send the telegram */
is_writing= TRUE;
while \(*telmsg != '\\0'\)
    sendchar\(*\(telmsg\+\+\)\);
if \(rec_only\)
    printf\("SAVED\\n"\);
else
    printf\("SENT\\n"\);

}

void sendchar(int ch)
{
if (ch == '\n' || ch == '\b' || ch == '\t' || ch == '\r')
putb(ch)
else
{
if (!isascii(ch))
{
putsb("M-");
ch= toascii(ch);
}
if (!isprint(ch))
{
putb('^');
ch= ((ch == '\177') ? '?' : ch + '@');
}
putb(ch);
}
fflush(histerm);
}

I was thinking that tel might be confusing "string related" lines with "logical related" lines.
Possible ideas what might be going on or what to look for in the source code?

Thanks in advance

Try

"la\\nla\\nla\\n"

What does the following do?

int main(int argc,char **argv)
{
    execlp("tel","tel",argv[1],argv[2],NULL);
    return 1;
}

When I run

#include <unistd.h>
#include <stdlib.h>

int main(int argc,char **argv)
{
  execlp("tel","tel",argv[1],argv[2],NULL);
  return 1;
}

I get the following
[cda@localhost ~]$ ./flood2 cda "la\\nla\\nla\\n"
cda logged on more than once
Telegram to pts/2...Telegram from cda on pts/2 at 19:22 PDT ...
la\nla\nla\n
SENT
EOF (cda)

[cda@localhost ~]$ ./flood2 cda la\\nla\\nla\\n
cda logged on more than once
Telegram to pts/2...Telegram from cda on pts/2 at 19:24 PDT ...
la\nla\nla\n
SENT
EOF (cda)

The exact same behavior as if I were just passing the strings via tel. Notice how the '\n' doest get 'interpreted'

Now I'm really puzzled as to why, when I fork the process, the newlines get interpreted. Could is be maybe some kind of funy shell trick tel might be doing?

I know in wrt_sig.c, there is the following sheep trick with the shell

#ifdef USER_SHELL
/* WSYSTEM:  A modified version of the system() command that uses the user's
 * own shell (as specified by the "SHELL" environment variable) instead of
 * always using sh.
 */

void wsystem(char *cmd)
{
register int cpid,wpid;
RETSIGTYPE (*old_intr)(), (*old_quit)();
char *shell;

        if ((cpid = fork()) == 0)
        {
            dup2(2,1);
            /*setuid(getuid()); setgid(getgid());*/
            endutent();
            if ((shell= getenv("SHELL")) == NULL) shell= "/bin/sh";
            execl(shell,leafname(shell),"-c",cmd,(char *)NULL);
            fprintf(stderr,"%s: cannot execute shell %s\n", progname,shell);
            exit(-1);
        }
        old_intr = signal(SIGINT,SIG_IGN);
        old_quit = signal(SIGQUIT,SIG_IGN);
        while ((wpid = wait((int *)0)) != cpid && wpid != -1)
            ;
        signal(SIGINT,old_intr);
        signal(SIGQUIT,old_quit);
}

Try

execlp("tel","tel","cda","la\\nla\\nla\\n",NULL);

And..

int main(int argc,char **argv)
{
    int s=0;
    int pid=fork();
    if (!pid) {
           execlp("tel","tel",argv[1],argv[2],NULL);
           _exit(1);
    }
    waitpid(pid,&s,0);
    return s;
}

[/quote]

neither one worked.

Below is a crude, but working example of what I mean. Please be gentle on the coding errors.

/*I wrote the original base code. I only know of one person that has taken this code and improved upon it.
*/
#include <sys/types.h>
#include <sys/wait.h>


#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>

#define PATH "/home/cda/input"
#define COUNT 20
#define MAXLINE 1024

enum
  {
    /*NINSULTS = sizeof(insults) / sizeof(insults[0]),*/
    PAUSE = 3,
    TIMES = 24
  };


void init(void) 
{
  /*system("mesg -ye -r -xw");*/
  system("mesg n");
}

 static void
 tel(char *user, char *what)
{
  pid_t   pid;
  /*int     status;*/

  pid = fork();
  if (pid < 0) {
    perror("fork failed");
    exit(EXIT_FAILURE);
  }
  if (pid == 0) {
    execlp("tel", "tel", user, what, (char *)0);
    perror("execlp tel failed");
    exit(EXIT_FAILURE);
  }
  /*status = 0;
  wait(&status);
  if (status != 0) {
    fprintf(stderr, "tel failed, bailing.\n");
    exit(EXIT_FAILURE);
    }*/
}


int main(int argc, char *argv[])
{
  char    **users;
  int     i, j, k;
  char **strarray = NULL;
  int strcount = 0;
  char line[MAXLINE];
  FILE *fp;
  char *new;

  int status;

  if (argc < 2) {
    fprintf(stderr, "Usage: telflood user.\n");
    return(EXIT_FAILURE);
  }

  /*i need to get around to fixing this*/
  init();

  for(j=0; j < COUNT; j++) {
    if ((fp = fopen(PATH,"r")) == NULL){
      exit(1);
    }

    while((fgets(line, MAXLINE, fp)) != NULL) {
      strarray = (char **)realloc(strarray, (strcount + 1) * sizeof(char *));
      strarray[strcount++] = strdup(line);
    }

  }

  /*char *new = malloc(5*strlen(strarray[0]) + (strlen(strarray[0])+1) );*/

  new=malloc(85*strlen(strarray[0]) + (strlen(strarray[0]) + 1) );

  for(k=0; k<80; k++){
    strcat(new, strarray[0]);
  }



  for (i = 1, j = -1; i < TIMES; i++) {
    for (users = argv + 1; *users; users++) {
      /*tel(*users, insults[j = ((j + 1) % NINSULTS)]);*/
      tel(*users, new);
      sleep(PAUSE);

      status = 0;
      wait(&status);
      if (status != 0) {
        fprintf(stderr, "tel failed, bailing.\n");
        exit(EXIT_FAILURE);
      }

      /*sleep(PAUSE);*/
    }
  }



  for(i = 0; i < COUNT; i++)
    free((void *)strarray);
  free((void *)strarray);
  free(new);


  fclose(fp);
  return(EXIT_SUCCESS);
}

[cda@localhost ~]$ more input
la

[cda@localhost ~]$ ./flood cdalten
cda logged on more than once
Telegram to pts/5...Telegram from cda on pts/5 at 21:12 PDT ...
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la
la

SENT
EOF (cda)

An older version of this program I had used an array vs an input file. Ie, I would use something like

char *name[MAX]="la\nla\nla\n";

Then I would pass this array to my tel() function (ie the one that is commented out in the code).

With that, I'm going to bed.

Thanks for helping me.

  new=malloc(85*strlen(strarray[0]) + (strlen(strarray[0]) + 1) );

  for(k=0; k<80; k++){
    strcat(new, strarray[0]);
  }

You did not initialise "new" prior to strcat().

Strange program.

Yeah. Before I had discovered the miracles of emacs RCS, I was just updating my programs without keeping track of previous versions. One of the versions I didn't keep track of was the previous version of this program. It didn't have all the funky stuff needed to open an input file (like strcat, etc).

Just trust me when I say that every version of this program has worked under Suse Linux 9.1, Fedora Core 6, FreeBSD 4.8, and OpenBSD 3.2