|
|
|
![]() |
|
Strumenti |
![]() |
#1 |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
fork e console
scusate se la domanda è banalissima per chi ne capisce di Linux e soprattutto scusate se avrei potuto trovarla in mille altri posti, ma credo di fare molto prima a fare una domanda mirata a voi piuttosto che scervellarmi a pensare delle keyword da rifilare a Google che mi pescano quarantamila cose che non ci pigliano una beneamata.
![]() la domanda, come si sarà intuito dal titolo del topic, è la seguente: come fo, su Linux, a fare in modo che un processo da me forkato abbia una nuova console anziché la stessa del padre? perché siccome il programma in questione è un programma che deve sia stampare su stdout che prelevare da stdin, logicamente se due processi hanno la stessa console succede un discreto casino. ![]() grazie ![]() |
![]() |
![]() |
![]() |
#2 |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
ah, e scusate se uso termini microsoftiani, ma naturalmente per "console" intendo una finestra di terminale. il processo forkato deve insomma aprirsi su un nuovo terminale con i suoi stdin e stdout nuovi di zecca.
|
![]() |
![]() |
![]() |
#3 |
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Non credo che esista un modo portabile per fare questo...portabile nel senso di "compatibile con tutte le distro"...
Questo perché non esistono console distinte nell'os che originariamente era in testo...o meglio volendo puoi gestire più console contemporaneamente, ma devi fare 2 login distinti... Quindi la soluzione più logica è quella di forkare il tuo processo tramite l'esecuzione di una nuova console (kterm o gnome-terminal)... |
![]() |
![]() |
![]() |
#4 | |
Senior Member
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
|
Quote:
![]() Per risolvere compiutamente il tuo problema dovresti padroneggiare i pseudoterminali, e con essi dialogare con dei programmi che implementano quella che chiami "console" (ovvero un rettangolo dove viene stampato testo e dove si può scrivere con la tastiera). Ma per fare delle cose semplici, basta un paio di descrittori interconnessi e il gioco è fatto. Un paio di socket vanno benissimo, ad esempio: Codice:
#include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> int main() { int fd[2]; socketpair(AF_UNIX, SOCK_STREAM, 0, fd); if (fork()==0) { char cmd[128]; close(fd[0]); sprintf(cmd, "xterm -Sunused/%d", fd[1]); system(cmd); _exit(0); } else { dup2(fd[0], fileno(stdout)); dup2(fd[0], fileno(stderr)); dup2(fd[0], fileno(stdin)); close(fd[0]); close(fd[1]); printf("Ciao!\n\r"); fflush(stdout); while(1) { char c; if (fread(&c, 1, 1, stdin)!=1) continue; fprintf(stderr, "Hai premuto: %c\n\r", c); } } return 0; } Spero ti sia utile.
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12 Ultima modifica di ilsensine : 26-06-2007 alle 09:31. |
|
![]() |
![]() |
![]() |
#5 |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
uhm uhm
![]() ![]() ma essendo questa l'ottica allora come dovrebbe fare, nel caso tipico, un processo forkato a prendere da stdin? se entrambi i processi si bloccano su una getchar c'è qualche criterio con cui l'input dell'utente va all'uno o all'altro processo (o a entrambi) oppure è una cosa completamente casuale? in questo secondo caso quindi come faccio, sincronizzo con un semaforo? |
![]() |
![]() |
![]() |
#6 | ||
Senior Member
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
|
Quote:
Quote:
![]() Cosa accade se apri un socket, effettui un fork ed entrambi i programmi tentano di leggere dal socket? La stessa cosa accade su stdin. Lancia questo programma e tieni premuto invio; vedrai che i dati vanno o a un processo o all'altro, casualmente: Codice:
#include <stdlib.h> #include <stdio.h> #include <unistd.h> int main() { char buf[128]; if (fork()==0) { fprintf(stderr, "Child\n"); while (1) { fgets(buf, sizeof(buf), stdin); fprintf(stderr, "Child: %s", buf); } } else { fprintf(stderr, "Parent\n"); while (1) { fgets(buf, sizeof(buf), stdin); fprintf(stderr, "Parent: %s", buf); } } return 0; } Tornando a noi, questa versione "rivista" del programma precedente forse ti aiuta a vedere le cose in maniera più simile a windows. Basta con gli hack e usiamo gli pseudoterminali: Codice:
// nb devi linkare con -lutil #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <pty.h> #include <termios.h> #include <signal.h> #include <sys/types.h> #include <sys/wait.h> typedef struct xConsole { int master; int slave; struct termios tios; pid_t process; } xConsole; xConsole *CreateConsole() { xConsole *ret = calloc(sizeof(*ret), 1); openpty(&ret->master, &ret->slave, NULL, &ret->tios, NULL); cfmakeraw(&ret->tios); ret->tios.c_oflag |= OPOST|ONLCR; tcsetattr(ret->master, TCSAFLUSH, &ret->tios); ret->process = fork(); if (ret->process==0) { char cmd[128]; close(ret->slave); sprintf(cmd, "xterm -S/%d", ret->master); free(ret); system(cmd); _exit(0); } usleep(250000); /* Attendi che xterm parta e scriva la sua spazzatura */ return ret; } void DestroyConsole(xConsole *c) { kill(c->process, SIGTERM); waitpid(c->process, NULL, 0); close(c->master); close(c->slave); free(c); } void SelectConsole(xConsole *c) { tcflush(c->master, TCIOFLUSH); dup2(c->slave, fileno(stdout)); dup2(c->slave, fileno(stderr)); dup2(c->slave, fileno(stdin)); } void ExecConsoleApp(const char *app) { if (fork()==0) { xConsole *con = CreateConsole(); con->tios.c_lflag |= (ICANON|ECHO); tcsetattr(con->master, TCSAFLUSH, &con->tios); SelectConsole(con); system(app); DestroyConsole(con); _exit(0); } } int main() { xConsole *con[2]; con[0] = CreateConsole(); con[1] = CreateConsole(); SelectConsole(con[0]); printf("Ciao!\n"); printf("Premi 2 per passare alla seconda console\n"); printf("Premi q per terminare\n"); printf("Premi e per eseguire un programma interattivo (bash)\n"); while(1) { char c; if (fread(&c, 1, 1, stdin)!=1) continue; printf("Hai premuto: %c\n", c); if (c=='1') { SelectConsole(con[0]); printf("Console 1 attivata. Premi 2 per passare alla seconda console\n"); } else if(c=='2') { SelectConsole(con[1]); printf("Console 2 attivata. Premi 1 per passare alla prima console\n"); } else if (c=='q') { break; } else if (c=='e') { ExecConsoleApp("bash"); } } DestroyConsole(con[0]); DestroyConsole(con[1]); return 0; }
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12 |
||
![]() |
![]() |
![]() |
#7 |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
MA LOOOL, hai nominato le funzioni con una nomenclatura Win32 per farmi sentire più a mio agio o cosa?
![]() aspetta che leggo bene ![]() EDIT - comunque grazie dell'interessamento! ![]() EDIT2 - e non te ne andare che la discussione non è ancora finita eh ![]() |
![]() |
![]() |
![]() |
#8 |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
maronn', e dire che Windows mi risolveva tutto con un unico flag da passare alla CreateProcess T_T
lo so che è un modo di ragionare incompatibile con la piattaforma, ma non riesco a fare a meno di pensare al problema che avevo e a come Windows me lo risolva e Linux no ![]() comunque, provando anche a ragionare più compatibilmente con Linux, mi è saltato in testa questo ragionamento: se l'utente del mio programma decide di avviare il sistema operativo senza avviare X (cioè lavora con un unico terminale...) allora non posso pretendere di avere finestre diverse; il sistema però continua ad essere multitasking, e siccome il mio programma deve poter girare anche in questa situazione, ne consegue che devo per forza organizzarmi un qualche sistema di sincronizzazione/gestione dell'unico terminale che ho. quindi a questo punto è solo una questione di design (stavo pensando di tenermi in ogni processo una lista dei processi forkati sui quali è possibile "switchare" la console). perdonami se ti ho fatto scrivere quel quintale di roba ma purtroppo temo di non poterla proprio usare: ![]() ![]() tra l'altro (solo per curiosità a questo punto), quanto sarebbe stato portabile tra una distro e l'altra richiamare xterm? in quali distro dotate di grafica xterm non è presente? |
![]() |
![]() |
![]() |
#9 | |||
Senior Member
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
|
Quote:
![]() Quote:
Anche X usa un tty, normalmente su f6. Puoi anche passare da un tty all'altro, essere informato dal kernel quando l'utente sceglie di cambiare tty, ecc. Non chiedermi altro che non sono pratico della cosa, ma puoi vedere come funziona getty. Quote:
konsole --noclose -e ls
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12 |
|||
![]() |
![]() |
![]() |
#10 | ||
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
Matrix l'ho visto però non mi ricordo cosa faceva la pillola blu e cosa faceva quella rossa
![]() quella rossa lo faceva uscire da Matrix e quella blu lo faceva tornare alla vita di tutti i giorni o il contrario? Quote:
![]() ora mi informo meglio, ma mi suona tanto come se fosse fatta apposta a risolvere tutti i miei problemi (sai quando senti il coro angelico e vedi la soluzione con tutte quelle stelline di magia e un'aura di luce attorno? si esatto, come i biscotti Pan di stelle, solo che col coro angelico anziché la musica pop ![]() Quote:
![]() ma per ora vada per tty. |
||
![]() |
![]() |
![]() |
#11 |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
|
![]() |
![]() |
![]() |
#12 |
Senior Member
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
|
L'enoteca ha già aperto, vedo
![]() Tiè: Codice:
#include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <linux/vt.h> int main() { int vt0 = open("/dev/tty0", O_RDWR); int fd; int req; char vt[64]; ioctl(vt0, VT_OPENQRY, &req); sprintf(vt, "/dev/tty%d", req); fprintf(stderr, "Using vt %s\n", vt); fd = open(vt, O_RDWR); dup2(fd, fileno(stdin)); dup2(fd, fileno(stdout)); dup2(fd, fileno(stderr)); close(fd); ioctl(vt0, VT_ACTIVATE, req); close(vt0); system("bash"); return 0; }
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12 Ultima modifica di ilsensine : 26-06-2007 alle 13:15. |
![]() |
![]() |
![]() |
#13 |
Senior Member
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
|
(ah ovviamente devi essere root per utilizzare i virtual terminal. Se ti viene da chiedermi il perché, prendi 'sta benedetta pillola rossa una buona volta
![]()
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12 |
![]() |
![]() |
![]() |
#14 | |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
Quote:
![]() ma non è che ci sarebbe modo di fare il tutto senza richiamare programmi esterni (nell'ultimo esempio hai richiamato bash), diciamo senza mai utilizzare la funzione system? |
|
![]() |
![]() |
![]() |
#15 | ||
Senior Member
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
|
Quote:
![]() Quote:
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12 |
||
![]() |
![]() |
![]() |
#16 |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
ma cosa dovrebbe succede premendo ctrl+alt+f1, oppure f2, f3... ?
![]() ho provato anche ctrl+alt+f6 su una fedora core 7 (ovviamente in modalità grafica), in tutto il monitor non cambia una virgola... ![]() |
![]() |
![]() |
![]() |
#17 |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
ho anche provato a compilare quel sorgente (l'ultimo, quello in cui lanci bash con system) e a farlo andare dopo aver chiamato su: Linux mi è entrato in modalità testuale e ho provato a premere ctrl+alt+tutti i tasti funzione che ho, uno per volta, manco a dirlo non è cambiato nulla
![]() poi siccome non sapevo come ritornare in modalità grafica da bravo windowsista ho premuto ctrl+alt+canc ( ![]() |
![]() |
![]() |
![]() |
#18 |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
e poi /dev/console che è? se stampo su /dev/console dove mi ritrovo quello che stampo?
corrisponde per caso a /dev/tty0 ? ![]() |
![]() |
![]() |
![]() |
#19 | |
Senior Member
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
|
Quote:
Linux ha un certo numero di terminali "virtuali" (normalmente 63); puoi pensare a un terminale come a un diverso "monitor", dentro il quale puoi eseguire una istanza di X, un programma console, alcuni ci ficcano i log, ecc. In genere (ma ci sono eccezioni) i terminali virtuali da 1 a 6 sono riservati a mgetty (login in modalità console), il 7 (non il 6, mi ero sbagliato) a X; i successivi sono liberi per istanze aggiuntive di X o altri programmi. Per passare da un VT all'altro puoi usare, sotto X, la combinazione ctrl+alt+f1..f12 (per i VT successivi è necessario un programma, chvt). Direi che è alquanto "impossibile" che non ti funzioni, è un pò che non tocco fedora ma è così ovunque...
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12 |
|
![]() |
![]() |
![]() |
#20 |
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
ma posso premere ctrl+alt+fx in un momento qualsiasi, schermata qualsiasi? lo posso fare loggato come utente di uso corrente o devo farlo come root?
io accendo la virtual macchine, si avvia tutto, inerisco username e password dell'account limitato (si chiama "a71104" ![]() ![]() ctrl+alt+f2... idem ctrl+alt+f3... idem ctrl+alt+f4... ![]() |
![]() |
![]() |
![]() |
Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 16:53.