Forum: Compiler & IDEs close(STDOUT_FILENO) haengt


von olpo (Gast)


Lesenswert?

Hallo,

mein Code kommt nicht ueber den Befehl
1
close(STDOUT_FILENO);
nicht hinaus.

Leider kann ich nur mit printf debuggen, und ich kann nicht in die 
close()
Funktion reinspringen.

Deshalb: hat jmd eine Vermutung woran das liegen koennte? Irgendwas, das 
mich evtl auf den richtigen Weg fuehrt?

Danke

von CC (Gast)


Lesenswert?

Hängt er wirklich, oder siehst Du nur nichts mehr, weil Du stdout 
(worauf printf schreibt) geschlossen hast? Habe noch nie probiert, ob 
das geht, oder was dann passiert...

Leite die Ausgabe mal in eine Datei um.

von olpo (Gast)


Lesenswert?

Also, das Codestueck ist hier.
1
      info("SID: %i", sid);
2
    if (sid < 0) {
3
        error("setsid() failed: %s", strerror(errno));
4
        exit(EXIT_FAILURE);
5
    }
6
    if (chdir("/") < 0) {
7
          info("chdir failed");
8
        error("chdir() failed: %s", strerror(errno));
9
        exit(EXIT_FAILURE);
10
    }
11
      info("__1");
12
    close(STDIN_FILENO);
13
      info("__2");
14
    close(STDOUT_FILENO);
15
      info("__3");
16
      printf("__3.1");
17
    close(STDERR_FILENO);
18
    is_daemon = 1;
19
      info("__4");
20
    info("process was successfully daemonized: pid=%d sid=%d", pid, sid);
21
}
Konsolenausgabe:
1
c:235: Info: SID: -1
2
c:237: Error: setsid() failed: Operation not permitted
3
c:226: Info: PID: 0
4
zynq> 
5
zynq> c:235: Info: SID: 701
6
exit
7
c:245: Info: __1
8
c:247: Info: __2


Tja, ich bin mir nicht sicher, ob das Ding wirklich haengt, oder ob ich 
mit printf() an meine Grenzen stosse. Denn manchmal hoert die Ausgabe 
schon bei "Error: setsid() failed" auf; ist halt ein forked-Prozess.
Und die letze Zeile "info("process was successfully daemonized" stammt 
nicht von mir, sondern ist regulaerer Code einer geprueften 
Implementierung. Aber die letzte Zeile wird nie ausgegeben.

Vielleicht hat's was mit der BusyBox zu tun...

von CC (Gast)


Lesenswert?

Ich weiß nicht, worauf du arbeitest, aber warum schließt du stdout 
überhaupt? Oder mache nur ich das nicht und es ist schlechter Stil, das 
offen zu lassen?

Ersetze sonst mal die printfs() durch fprintf() in eine Datei. ...Oder 
guck Dir mit strace/gdb an, was dort passiert.

Sieht so aus, als kommt nur nix mehr an. Denn wenn Du eine Tür schließt, 
kannst Du ja auch nicht mehr durchgehen...

von Rolf Magnus (Gast)


Lesenswert?

olpo schrieb:
> Tja, ich bin mir nicht sicher, ob das Ding wirklich haengt, oder ob ich
> mit printf() an meine Grenzen stosse.

Was macht info()? Ist das nur ein printf? Dann wäre das doch genau das 
erwartete Verhalten. Wenn du stdout schließt, kannst du danach natürlich 
nichts mehr nach stdout schreiben, genau wie bei anderen Files. Was 
hättest du denn erwartet?

von Karl H. (kbuchegg)


Lesenswert?

und 'info' hängt hoffentlich an den auszugebenden Text auch noch ein \n 
hinten drann. Denn sonst ist nicht garantiert, dass das gepufferte auch 
noch rausgeschrieben wird, ehe dann der Stream geschlossen wird.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Aus dem Codestück heraus vermute ich mal, du willst einen daemon 
erzeugen? vorher käme noch ein setsid(), und bitte ein doppeltes fork().

Wenn ja, dann bitte nicht stderr schließen.
1
    /* http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16 */
2
3
    pid_t i;
4
    int fd;
5
6
7
    /* Step 1: fork() so that the parent can exit */
8
    i = fork();
9
    if (i < 0) {
10
  error("fork(#1) failed: %s", strerror(errno));
11
  exit(1);
12
    }
13
    if (i != 0)
14
  exit(0);
15
16
    /* Step 2: setsid() to become a process group and session group leader */
17
    setsid();
18
19
    /* Step 3: fork() again so the parent (the session group leader) can exit */
20
    i = fork();
21
    if (i < 0) {
22
  error("fork(#2) failed: %s", strerror(errno));
23
  exit(1);
24
    }
25
    if (i != 0)
26
  exit(0);
27
28
    /* Step 4: chdir("/") to ensure that our process doesn't keep any directory in use */
29
    if (chdir("/") != 0) {
30
  error("chdir(\"/\") failed: %s", strerror(errno));
31
  exit(1);
32
    }
33
34
    /* Step 5: umask(0) so that we have complete control over the permissions of anything we write */
35
    umask(0);
36
37
    /* Step 6: Establish new open descriptors for stdin, stdout and stderr */
38
    /* detach stdin */
39
    if (freopen("/dev/null", "r", stdin) == NULL) {
40
  error("freopen (/dev/null) failed: %s", strerror(errno));
41
  exit(1);
42
    }
43
44
    /* detach stdout and stderr */
45
    fd = open("/dev/null", O_WRONLY, 0666);
46
    if (fd == -1) {
47
  error("open (/dev/null) failed: %s", strerror(errno));
48
  exit(1);
49
    }
50
    fflush(stdout);
51
    dup2(fd, STDOUT_FILENO);
52
    fflush(stderr);
53
    dup2(fd, STDERR_FILENO);
54
    close(fd);

Nachtrag: Hab grad gesehen dass der link tot ist (den hab ich in 
lcd4linux vor gefühlten 100 Jahren verwendet). Zu finden aber u.a. hier: 
http://www.faqs.org/faqs/unix-faq/programmer/faq/

: Bearbeitet durch User
von Frank K. (frank)


Lesenswert?

Ich rate mal zu meinen Gunsten dass es sich um Linux handelt. Da hilft 
mir oft strace weiter.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Frank K. schrieb:
> Ich rate mal zu meinen Gunsten dass es sich um Linux handelt. Da hilft
> mir oft strace weiter.

strace hilft bei daemons nur begrenzt

von Frank K. (frank)


Lesenswert?

Michael Reinelt schrieb:
> strace hilft bei daemons nur begrenzt

Da müsstest Du jetzt ein wenig präziser werden. Ich habe strace schon 
mit daemons und auch mot Threads benutzt. Man muss da allerdings mit -p 
arbeiten. Welche Limitierungen meinst Du?

von Jim M. (turboj)


Lesenswert?

> strace hilft bei daemons nur begrenzt

Mit den richtigen Optionen kann strace auch Kindprozesse verfolgen, oder 
sich an laufende Prozesse anhängen. Siehe Manpage von strace.

von olpo (Gast)


Lesenswert?

Rolf Magnus schrieb:
> Was macht info()? Ist das nur ein printf? Dann wäre das doch genau das
> erwartete Verhalten. Wenn du stdout schließt, kannst du danach natürlich
> nichts mehr nach stdout schreiben, genau wie bei anderen Files. Was
> hättest du denn erwartet?
Das ist irgendein Makro. Damit bin ich aber zum ersten Mal konfrontiert, 
ich kann das also noch nicht recht lesen.
1
#define info(fmt, ...) tpm_log(TPM_LOG_INFO, "%s:%d: Info: " fmt "\n", \
2
                                __BFILE__, __LINE__, ## __VA_ARGS__)

Michael Reinelt schrieb:
> Aus dem Codestück heraus vermute ich mal, du willst einen daemon
> erzeugen? vorher käme noch ein setsid(), und bitte ein doppeltes fork().
Hmm, nee der macht fork() nur einmal. Wie gesagt, das ist ein opensource 
Projekt, das ich auf ARM und BusyBox laufen lassen will. Ob der Code 
schoen ist, kann ich nicht beurteilen.
http://prdownload.berlios.de/tpm-emulator/tpm_emulator-0.7.4.tar.gz

von olpo (Gast)


Lesenswert?

Ich habe die betreffenden Zeilen jetzt einfach mal auskommentiert. Zwar 
kommt er jetzt bis info(__3), aber die letzte Zeile schafft er immer 
noch nicht. Debuggen mit printf hat wohl seine Grenzen...
1
    info("__1");
2
    close(STDIN_FILENO);
3
    info("__2");
4
 //   close(STDOUT_FILENO);
5
    info("__3");
6
    printf("__3.1");
7
 //   close(STDERR_FILENO);
8
    is_daemon = 1;
9
    info("__4");
10
    info("process was successfully daemonized: pid=%d sid=%d", pid, sid);

von Jim M. (turboj)


Lesenswert?

Einige libc Implementierungen flushen stdout nur wenn sie ein "\n" 
sehen. Häng mal eins an die letzte Zeile.

von Rolf Magnus (Gast)


Lesenswert?

Jim Meba schrieb:
> Einige libc Implementierungen flushen stdout nur wenn sie ein "\n"
> sehen.

Oder halt ein fflush(stdout);

von olpo (Gast)


Lesenswert?

Das Problem war tatsächlich BusyBox.
Das kann kein fork(), sondern nur vfork().
Schlau wie BusyBox ist, wird fork() ohne Warnung(!) einfach mit vfork() 
ausgetauscht & ausgeführt. Und mit vfork() klappt Deamonising nicht.

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

olpo schrieb:
> Das Problem war tatsächlich BusyBox.
> Das kann kein fork(), sondern nur vfork().
> Schlau wie BusyBox ist, wird fork() ohne Warnung(!) einfach mit vfork()
> ausgetauscht & ausgeführt. Und mit vfork() klappt Deamonising nicht.

Ähhh... BusyBox ist doch so eine Art "Micro-Shell" wo viele 
Shell-Kommandos von ein und demselben binary ausgeführt werden.

fork() liegt doch wenn in der libc?

oder hast du da eine "Micro-libc" drauf?

von Rolf Magnus (Gast)


Lesenswert?

Das liegt nicht an Busybox selber, sondern offenbar an deiner 
Hardware-Plattform,  für die Busybox offenbar einen Work-Around 
integriert hat. Siehe http://www.busybox.net/FAQ.html#tips_vfork

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.