[systemd-devel] [PATCH 01/12] fsckd daemon for inter-fsckd communication

Lennart Poettering lennart at poettering.net
Wed Jan 28 12:16:14 PST 2015


On Wed, 28.01.15 14:20, Didier Roche (didier.roche at canonical.com) wrote:

>  static int process_progress(int fd) {
> -        _cleanup_fclose_ FILE *console = NULL, *f = NULL;
> +        _cleanup_fclose_ FILE *f = NULL;
>          usec_t last = 0;
> -        bool locked = false;
> -        int clear = 0;
> +        _cleanup_close_ int fsckd_fd;
> +        static const union sockaddr_union sa = {
> +                .un.sun_family = AF_UNIX,
> +                .un.sun_path = FSCKD_SOCKET_PATH,
> +        };
> +
> +        fsckd_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);

Please always specifiy SOCK_CLOEXEC. In fact, *all* our fs should be
opened in CLOEXEC mode these days, except for the very few case where
that's explicitly not desired.

> -                for (j = 0; j < (unsigned) clear; j++)
> -                        fputc(' ', console);
> -                fputc('\r', console);
> -                fflush(console);
> +                n = send(fsckd_fd, &progress, sizeof(FsckProgress), 0);
> +                if (n < 0 || (size_t) n < sizeof(FsckProgress))
> +                        log_warning_errno(n, "Cannot communicate
> -                fsck progress to fsckd: %m");

Hmm, this error check is incorrect. The first argument of
log_warning_errno() should carry an errno integer of some kind, but
the raw glibc send() does not return that, it returns a size...

> +
> +#define IDLE_TIME_MINUTES 1
> +
> +typedef struct Clients {
> +        int fd;
> +        char device[PATH_MAX];

Hmm, no, please don't. Please never use fixed size arrays for these
things unless the string is really fixed size. Please use char* here,
and allocate the data. 

> +        last_activity = now(CLOCK_MONOTONIC);
> +
> +        for (;;) {
> +                int new_client_fd = 0;
> +                Clients *current;
> +                _cleanup_free_ char *console_message = NULL;
> +                double current_percent = 100;
> +                int current_numdevices = 0, m = 0;
> +                usec_t t;
> +
> +                /* Initialize and list new clients */
> +                new_client_fd = accept4(socket_fd, NULL, NULL, SOCK_NONBLOCK);
> +                if (new_client_fd > 0) {
> +                        log_debug("new fsck client connected to fd: %d", new_client_fd);
> +                        current = alloca0(sizeof(Clients));

It's not OK to invoke alloca() in loops. This cannot work. Please use
normal heap memoy for this.

> +                        current->fd = new_client_fd;
> +                        if (!first)
> +                                LIST_INIT(clients, current);
> +                        else
> +                                LIST_PREPEND(clients, first, current);
> +                        first = current;


LIST_PREPEND(clients, first, current) already does all of the five
lines above.

> +                        current = NULL;
> +                }
> +
> +                LIST_FOREACH(clients, current, first) {
> +                       FsckProgress fsck_data;
> +                       int rc = 0;
> +
> +                        if (current->fd > 0)
> +                                rc = recv(current->fd, &fsck_data, sizeof(FsckProgress), 0);
> +
> +                        if ((current->fd != 0) && (rc == 0)) {
> +                                log_debug("fsck client connected to
> fd %d disconnected", current->fd);

Please print propery exit codes.

> +                                current->fd = 0;
> +                                current->percent = 100;
> +                        } else if ((rc < 0) && (errno !=
> EWOULDBLOCK)) {

EWOULDBLOCK is a windows name. Please use EAGAIN.

> +                if ((fabs(current_percent - percent) > 0.000001) || (current_numdevices != numdevices)) {
> +                        numdevices = current_numdevices;
> +                        percent = current_percent;
> +
> +                        asprintf(&console_message, "Checking in
> progress on %d disks (%3.1f%% complete)",
> +                                 numdevices, percent);

Missing oom check.

> +
> +                        /* write to console */
> +                        fprintf(console, "\r%s\r%n", console_message, &m);
> +                        fflush(console);

Hmm, what's the reason for first writing this to an alocated buffer,
and then to the console? You can write this directly to the console, no?


> +static int create_socket(void) {
> +        /* Create the socket manually for testing */
> +        union {
> +                struct sockaddr sa;
> +                struct sockaddr_un un;
> +        } sa;

Please use sockaddr_union for this.

> +        int fd;
> +
> +        fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
> +        if (fd < 0)
> +                return log_error_errno(errno, "socket() failed:
> %m");

SOCK_CLOEXEC, please.

> +
> +        memset(&sa, 0, sizeof(sa));
> +        sa.un.sun_family = AF_UNIX;

Please initialize fields with constant values when you declare the
variable already.

> +        strncpy(sa.un.sun_path, FSCKD_SOCKET_PATH, sizeof(sa.un.sun_path));
> +        unlink(FSCKD_SOCKET_PATH);
> +        if (bind(fd, &sa.sa, sizeof(sa)) < 0)
> +                return log_error_errno(errno, "binding %s failed:
> %m", FSCKD_SOCKET_PATH);

This not the right way to listen on an AF_UNIX path. You need to
calculate the size of the sockaddr properly, as "offsetof(sa,
un.sun_path) + strlen(sa.un.sun_path)". Otherwise the kernel will
including all those trailing NULs in the socket address! 

Lennart

-- 
Lennart Poettering, Red Hat


More information about the systemd-devel mailing list