Andreas Flückiger: fork & Co.

Hallo!

Ich habe Probleme mit fork und setsid. Das Beispiel-Script von Erik Tews (http://www.teamone.de/selfhtml/sfarchiv/1999_2/t03884.htm#a18773) läuft bei mir über Telnet ohne Probleme. Wenn ich es aber über CGI aufrufe, trennt sich das Script nicht ab. Die Meldung, dass das Programm gestartet wurde erscheint erst nach 2 Minuten.
Wisst ihr, was ich dagegen machen könnte, oder gibt es Alternativen?
Vielen Dank im Voraus.

Gruss Andreas

  1. Hallo!

    Ich habe Probleme mit fork und setsid. Das Beispiel-Script von Erik Tews (<../../sfarchiv/1999_2/t03884.htm#a18773>) läuft bei mir über Telnet ohne Probleme. Wenn ich es aber über CGI aufrufe, trennt sich das Script nicht ab. Die Meldung, dass das Programm gestartet wurde erscheint erst nach 2 Minuten.
    Wisst ihr, was ich dagegen machen könnte, oder gibt es Alternativen?
    Vielen Dank im Voraus.

    Wie sieht dein Code aus, und auf welchem Unix läuft das Script?

    1. Wie sieht dein Code aus, und auf welchem Unix läuft das Script?

      Ich bekomme diese beiden Zeilen beim Telnet-Login. Ich hoffe, dass dies das Richtige ist.
      Cobalt Linux release 4.0 (Fargo)
      Kernel 2.0.34 on a mips

      Den Code übernahm ich 1:1 von deinem Beispielscript, also:

      #!/usr/bin/perl
      use POSIX qw(setsid);
      if (!defined($Pid = fork()))
      {
      die "Fork konnte nicht ausgeführt werden. Vielleicht unterstützt ihr Betriebssystem diesen Aufruf nicht.";
      }
      elsif ($Pid == 0)
      {
          setsid();
          sleep (120);
          open (TESTDATEI, ">still");
          print TESTDATEI "Test\n";
          close(TESTDATEI);
          close (TESTDATEI);
          exit(0);
      }
      else
      {
          print "Content-type: text/html\n\n";
          print "Ok, das Programm läuft jetzt.";
          exit (0);
      }

      1. Hm, verstehe ich nicht. Sollte eigendlich gehen. Versuch doch mal folgendes Beispiel von der manpage perlipc auszuführen:

        Complete Dissociation of Child from Parent

        In some cases (starting server processes, for instance)
               you'll want to completely dissociate the child process
               from the parent.  This is often called daemonization.  A
               well behaved daemon will also chdir() to the root
               directory (so it doesn't prevent unmounting the filesystem
               containing the directory from which it was launched) and
               redirect its standard file descriptors from and to
               /dev/null (so that random output doesn't wind up on the
               user's terminal).

        use POSIX 'setsid';

        sub daemonize {
                       chdir '/'               or die "Can't chdir to /: $!";
                       open STDIN, '/dev/null' or die "Can't read /dev/null: $!";
                       open STDOUT, '>/dev/null'
                                               or die "Can't write to /dev/null: $!";
                       defined(my $pid = fork) or die "Can't fork: $!";
                       exit if $pid;
                       setsid                  or die "Can't start a new session: $!";
                       open STDERR, '>&STDOUT' or die "Can't dup stdout: $!";
                   }

        The fork() has to come before the setsid() to ensure that
               you aren't a process group leader (the setsid() will fail
               if you are).  If your system doesn't have the setsid()
               function, open /dev/tty and use the TIOCNOTTY ioctl() on
               it instead.  See the tty(4) manpage for details.

        Non-Unix users should check their Your_OS::Process module
               for other solutions.

        Wenn das auch nicht geht, liegt es an der dortigen Serverinstallation.

        1. Hm, verstehe ich nicht. Sollte eigendlich gehen. Versuch doch mal folgendes Beispiel von der manpage perlipc auszuführen:
          ...

          Fork und setsid starten zwar einen neuen Prozess (auch bei deinem Script), aber das Hauptprogramm wird erst nach dem neuem Prozess beendet. Das ist auch nicht weiter schlimm, wenn ich verhindern könnte, dass die Ausgabe nicht mehr an den Browser gesendet wird. Leider gelingt mir auch das nicht. Auch die Zeile
          open STDOUT, '>/dev/null';
          hilft nichts. Konkret möchte ich die Ausgabe (Password: ) folgender Zeilen verhindern:

          open(SU,"su $username");
          print SU $password;
          close(SU);

          Kennst du (ihr) eine Lösung?

          Gruss
          Andreas

          1. Fork und setsid starten zwar einen neuen Prozess (auch bei deinem Script), aber das Hauptprogramm wird erst nach dem neuem Prozess beendet. Das ist auch nicht weiter schlimm, wenn ich verhindern könnte, dass die Ausgabe nicht mehr an den Browser gesendet wird. Leider gelingt mir auch das nicht. Auch die Zeile
            open STDOUT, '>/dev/null';
            hilft nichts. Konkret möchte ich die Ausgabe (Password: ) folgender Zeilen verhindern:

            open(SU,"su $username");
            print SU $password;
            close(SU);

            Kennst du (ihr) eine Lösung?

            Also irgendwas geht da bei dir ganz gewaltig schief. Aber versuch doch mal folgende Zeilen:

            open (SU, "su $username > /dev/null");

            Dann sollte jede Ausgabe unterdrückt werden. Oder dann gibt es noch so ne Funktion namens IPC::open2, oder so was ähnliches.

            1. Also irgendwas geht da bei dir ganz gewaltig schief. Aber versuch doch mal folgende Zeilen:

              open (SU, "su $username > /dev/null");

              Dann sollte jede Ausgabe unterdrückt werden. Oder dann gibt es noch so ne Funktion namens IPC::open2, oder so was ähnliches.

              Funktioniert leider beides nicht. Merkwürdig finde ich auch die Ausgabe des folgenden Scriptes:

              print STDOUT "<!--";
              sleep 10;
              open(SU,"su $username");
              print SU $password;
              close(SU);
              print STDOUT "-->";

              Ausgabe: Password: <!---->

              1. Hi!

                Funktioniert leider beides nicht. Merkwürdig finde ich auch die Ausgabe des folgenden Scriptes:
                Ausgabe: Password: <!---->

                Dies liegt vermutlich daran, dass die Ausgabe noch in den Perl-Puffern haengt. Normalerweise wird erst nach einem \n dieser Puffer geleert (flushed). (Naeheres in perlvar bei $.) Wenn Du keines schreiben willst, koennte folgendes helfen:

                $ = 1;

                print STDOUT "<!--";
                sleep 10;
                open(SU,"su $username");
                print SU $password;
                close(SU);
                print STDOUT "-->";

                $ = 0;

                Bye, Calocybe