• # alternative

    Posté par (courriel, site web personnel) . En réponse au journal Editer en parallèle les paramètres BIOS de plusieurs machines grâce à tmux. Évalué à 4.

    J'ai écrit ça il y a quelques temps qui fait un truc similaire pour les gens qui ont pas tmux (comme c'était le cas de tout le monde en 2006) : http://cretonnerre.krunch.be/~krunch/src/tcpmux.c

    // A select()-based TCP multiplexer. It will accept connections
    // on the specified port and send its stdin to connected clients.
    // This has nothing to do with the tcpmux service.
    // 
    // $ cc -Wall -W -pedantic -std=c99 -o tcpmux tcpmux.c
    // 
    // TODO: select() sucks, use something better
    // TODO: turn this into a netcat patch
    // TODO: _XOPEN_SOURCE should be in Makefile
    // TODO: RESEND should be a command line option
    // TODO: are all error conditions checked ?
    //
    // Copyright (c) 2006 Adrien Kunysz
    //
    // Permission is hereby granted, free of charge, to any person obtaining a
    // copy of this software and associated documentation files (the "Software"),
    // to deal in the Software without restriction, including without limitation
    // the rights to use, copy, modify, merge, publish, distribute, sublicense,
    // and/or sell copies of the Software, and to permit persons to whom the
    // Software is furnished to do so, subject to the following conditions:
    //
    // The above copyright notice and this permission notice shall be included in
    // all copies or substantial portions of the Software.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
    // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
    // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    // DEALINGS IN THE SOFTWARE.
    #define _XOPEN_SOURCE 500
    //#define RESEND // data sent by clients are resent to other clients
    //#define NDEBUG // less verbosity
    #include <stdio.h> // stderr, fprintf()
    #include <stdlib.h> // exit(), EXIT_*, atoi(), NULL
    #include <string.h> // memset()
    #include <errno.h> // errno
    #include <sys/types.h> // size_t, ssize_t
    #include <sys/socket.h> // socket(), bind(), listen(), accept(), send(),...
    #include <sys/time.h> // select(), FD_*, fd_set
    #include <arpa/inet.h> // htons()
    #include <netinet/in.h> // INADDR_ANY, sockaddr_in
    #include <unistd.h> // STDIN_FILENO, STDERR_FILENO, close(), read()
    #include <fcntl.h> // fcntl(), F_SETFL, O_NONBLOCK
    #define MAX_UNACCEPTED_CONNS 5 // listen()'s second argument
    #define MAX_CLIENTS 32
    #define BUFSZ 1024
    #if MAX_CLIENTS + 2 > FD_SETSIZE
    # error MAX_CLIENTS is too high
    #endif
    #ifdef NDEBUG
    # define debug(...)
    # define wdebug(buf, len)
    #else
    # define debug(...) fprintf(stderr, __VA_ARGS__)
    # define wdebug(buf, len) write(STDERR_FILENO, buf, len)
    #endif
    #define err(...) do { \
     fprintf(stderr, __VA_ARGS__); \
     exit(EXIT_FAILURE); \
     } while (0)
    int setup_socket(int portnum)
    {
     int res = -1;
     if (-1 == (res = socket(AF_INET, SOCK_STREAM, 0)))
     err("Unable to create socket.\n");
     int yes = 1;
     if (-1 == setsockopt(res, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)))
     fprintf(stderr, "Unable to set SO_REUSEADDR option.\n");
     struct sockaddr_in myaddr = {
     .sin_family = AF_INET,
     .sin_addr.s_addr = INADDR_ANY,
     .sin_port = htons(portnum)
     };
     memset(&(myaddr.sin_zero), '0円', 8);
     if (-1 == bind(res, (struct sockaddr *)&myaddr, sizeof(myaddr)))
     err("Unable to bind address to socket.\n");
     if (-1 == listen(res, MAX_UNACCEPTED_CONNS))
     err("Unable to listen on socket.\n");
     return res;
    }
    int accept_client(int serverfd)
    {
     struct sockaddr_in clientaddr;
     socklen_t addrlen = sizeof(clientaddr);
     int res = accept(serverfd, (struct sockaddr *)&clientaddr, &addrlen);
     if (-1 == res)
     err("accept() failure\n");
     if (-1 == fcntl(res, F_SETFL, O_NONBLOCK))
     fprintf(stderr, "Unable to set non blocking mode on fd.\n");
     return res;
    }
    size_t sendall(int fd, char *buf, size_t len)
    {
     size_t sent = 0;
     while (sent < len) {
     errno = 0;
     ssize_t this_block = send(fd, &buf[sent], len - sent, 0);
     if (0 > this_block) {
     if (EAGAIN == errno || EWOULDBLOCK == errno)
     fprintf(stderr, "Output buffer is full ?\n");
     break;
     }
     sent += (size_t)this_block;
     }
     return sent;
    }
    int main(int argc, char **argv)
    {
     if (2 != argc)
     err("Usage: %s PORT\n", argv[0]);
     const int port = atoi(argv[1]);
     const int inputfd = STDIN_FILENO;
     const int serverfd = setup_socket(port);
     static int clientsfds[MAX_CLIENTS];
     for (unsigned int i = 0; i < MAX_CLIENTS; i++)
     clientsfds[i] = -1;
     static fd_set allfds;
     FD_ZERO(&allfds);
     FD_SET(serverfd, &allfds);
     FD_SET(inputfd, &allfds);
     while (1) {
     static fd_set selectfds;
     selectfds = allfds;
     if (-1 == select(FD_SETSIZE, &selectfds, NULL, NULL, NULL))
     err("select() failure\n");
     if (FD_ISSET(serverfd, &selectfds)) { // client connection
     debug("Got new client.\n");
     unsigned int fdidx;
     for (fdidx = 1; fdidx < MAX_CLIENTS; fdidx++)
     if (-1 == clientsfds[fdidx])
     break;
     if (MAX_CLIENTS+1 == fdidx)
     fprintf(stderr, "Too many clients.\n");
     clientsfds[fdidx] = accept_client(serverfd);
     FD_SET(clientsfds[fdidx], &allfds);
     continue;
     }
     static char buf[BUFSZ];
     if (FD_ISSET(inputfd, &selectfds)) { // input is readable
     ssize_t len = read(inputfd, buf, sizeof(buf));
     if (0 > len)
     err("mysterious read failure\n");
     if (0 == len) // EOF
     exit(EXIT_SUCCESS);
     size_t ulen = (size_t)len;
     for (unsigned int i = 0; i < MAX_CLIENTS; i++) {
     if (-1 == clientsfds[i])
     continue;
     if (ulen != sendall(clientsfds[i], buf, ulen))
     fprintf(stderr, "send() failure\n");
     }
     continue;
     }
     // a client sent something
     unsigned int fdidx;
     for (fdidx = 0; fdidx < MAX_CLIENTS; fdidx++) {
     if (clientsfds[fdidx] == -1)
     continue;
     if (FD_ISSET(clientsfds[fdidx], &selectfds))
     break;
     }
     if (MAX_CLIENTS == fdidx) { // wtf ? no readable client found
     fprintf(stderr, "select() lied ?\n");
     continue;
     }
     ssize_t len = read(clientsfds[fdidx], buf, sizeof(buf));
     if (0 > len)
     fprintf(stderr, "failed to read from client\n");
     if (0 == len) { // client closed connection
     FD_CLR(clientsfds[fdidx], &allfds);
     close(clientsfds[fdidx]);
     clientsfds[fdidx] = -1;
     debug("Client disconnected.\n");
     continue;
     }
     wdebug(buf, (size_t)len);
     #ifdef RESEND
     for (unsigned int i = 0; i < MAX_CLIENTS; i++)
     if (-1 != clientsfds[i] && i != fdidx)
     sendall(clientsfds[i], buf, (size_t)len);
     #endif
     }
    }

    pertinent adj. Approprié : qui se rapporte exactement à ce dont il est question.