Inhaltsverzeichnis

März 2005

Aufgabe 1

→ Wenn zu einem Zeitpunkt nur ein Prozeß reell laufen kann, weil nur ein Prozessor da ist, und wenn dabei keine Verdrängung stattfinden kann, kommt keine Nebenläufigkeit zustande. Also müssen die Zugriffe nicht koordiniert werden.

Aufgabe 2

/* includes */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <sys/stat.h>
 
/* Funktionsdeklarationen, globale Variablen */
 
#define MAX_LEN 128
 
int main(int argc, char **argv);
static void serve(int sock);
static void prattr(char *filename);
static void error(char *msg);
static void sighandler(int sig);
 
/* Funktion main */
 
int main(int argc, char **argv)
{
	/* lokale Variablen und was man sonst am Anfang so vorbereitet */
 
	int port;
	int sock;
	struct sockaddr_in addr;
	struct sockaddr_in client_addr;
	int client_addr_len = sizeof(struct sockaddr_in);
	int client_sock;
	int pid;
	struct sigaction action;
 
	if (argc != 2) {
		printf("usage: fileattrd PORT\n");
		exit(1);
	}
	port = atoi(argv[1]);
 
	/* Ein Signal-Handler für SIGCHLD (ein Kindprozess stirbt) wird installiert. So können Zombies mit waitpid abgeholt werden. */
	action.sa_handler = sighandler;
	sigemtpyset(&action.sa_mask);
	action.flags = SA_RESTART;
	sigaction(SIGCHLD, &action, NULL);
 
	/* Socket oeffnen */
 
	sock = socket(PF_INET, SOCK_STREAM, 0);
	if (sock == -1) error("creating socket failed");
 
	/* Socket an angegebenen Port und beliebige IP-Adressen binden */
 
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	if (bind(sock, (const struct sockaddr *) &addr, sizeof(struct sockaddr_in)) == -1) error("binding socket failed");
 
	/* Warteschlange ankommender Verbindungen auf 5 einstellen */
 
	if (listen(sock, 5) == -1) error("listening failed");
 
	/* Server-Schleife */
 
	while (1) {
 
		/* Verbindung aufnehmen */
 
		client_sock = accept(sock, (struct sockaddr *) &client_addr, &client_addr_len);
		if (client_sock == -1) error("accepting failed");
 
		/* Prozess zur Kommandoausführung erzeugen */
 
		pid = fork();
		switch(pid) {
 
		/* Fehler bei Prozesserzeugung */
 
		case -1:
			error("forking failed");
			break;
 
		/* Sohnprozess */
 
		case 0:
			serve(client_sock);
			break;
 
		/* Vaterprozess */
 
		default:
			break;
		}
	}
 
} /* Ende Funktion main */
 
/* serve-Funktion */
 
static void serve(int sock) {
	FILE *f;
	char buffer[MAX_LEN + 2];
 
	f = fdopen(sock, "rw");
	if (f == NULL) error("opening socket for reading failed");
 
	errno = 0;
	while (fgets(buffer, MAX_LEN + 1, f) != NULL) {
		buffer[strlen(buffer) - 1] = '\0';
		prattr(buffer);
		errno = 0;
	}
	if (errno != 0) error("reading string failed");
 
	fclose(f);
	close(sock);
 
	exit(0);
}
 
/* prattr-Funktion */
 
static void prattr(char *filename) {
	struct stat info;
 
	if (stat(filename, &info) == -1) {
		printf("%s %s\n", filename, strerror(errno));
		return;
	}
 
	if (S_ISREG(info.st_mode)) {
		printf("%s F %i\n", filename, info.st_size);
	} else if (S_ISDIR(info.st_mode)) {
		printf("%s D\n", filename);
	} else {
		printf("%s X\n", filename);
	}
}
 
/* weitere Funktionen, falls benoetigt */
 
static void error(char *msg) {
	perror(msg);
	exit(1);
}
 
static void sighandler(int sig) {
	int pid;
	int status;
 
	while ((pid = waitpid(-1, &status, WNOHANG)) != 0) {
		if (pid == -1) error("waiting for zombies failed");
	}
}

Alternative Lösung: Diese schreibt die angeforderte Information auch wieder auf den socket zurück

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
 
/* fehlende includes */
#include <sys/stat.h>
#include <string.h>
 
#define DEFAULT_PORT 31337
 
static void serve(int socket);
static void prattr(char *filename);
static void sigchld_handler_install(void);
static void sigchld_handler(int sig);
 
int main(int argc, char *argv[]) {
    int sock;
    unsigned short port;
    struct sockaddr_in saddr;
 
    if (argc > 1) {
        port = atoi(argv[1]);
    } else {
        port = DEFAULT_PORT;
    }
 
    sigchld_handler_install();
 
    sock = socket(PF_INET, SOCK_STREAM, 0);
    if (sock < 0) {
        perror("socket");
        return EXIT_FAILURE;
    }
 
    saddr.sin_family = AF_INET;
    saddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    saddr.sin_port = htons(port);
 
    if (bind(sock, (struct sockaddr *) &saddr, sizeof(saddr)) == -1) {
        perror("bind");
        return EXIT_FAILURE;
    }
 
    if (listen(sock, 5) == -1) {
        perror("listen");
        return EXIT_FAILURE;
    }
 
    printf("Listening on port %d\n", port);
 
    while (1) {
        pid_t pid;
        int clsock;
        struct sockaddr clsaddr;
        socklen_t clsaddr_len = sizeof(clsaddr);
 
        clsock = accept(sock, &clsaddr, &clsaddr_len);
        if (clsock == -1) {
            perror("accept");
            continue;
        }
 
        switch(pid = fork()) {
            case -1:
                /* error */
                perror("fork");
                return EXIT_FAILURE;
 
                break;
            case 0:
                /* child */
                close(sock);
 
                serve(clsock);
 
                close(clsock);
                exit(EXIT_SUCCESS);
 
                break;
            case 1:
                /* parent */
                close(clsock);
 
                break;
        }
    }
 
    return EXIT_SUCCESS;
}
 
static void serve(int socket) {
    char file[128+2];
    FILE *fd = fdopen(socket, "r+");
 
    if (dup2(socket, fileno(stdout)) == -1) {
        perror("dup2");
        exit(EXIT_FAILURE);
    }
 
    while(fgets(file, 128+2, fd) != NULL) {
        file[strlen(file)-1] = '\0';
 
        prattr(file);
    }
}
 
static void prattr(char *filename) {
    struct stat statbuf;
 
    if (stat(filename, &statbuf) == -1) {
        printf("%s %s\n", filename, strerror(errno));
    } else {
        if (S_ISDIR(statbuf.st_mode)) {
            printf("%s D\n", filename);
        } else if (S_ISREG(statbuf.st_mode)) {
            printf("%s F %ld\n", filename, (unsigned long) statbuf.st_size);
        } else {
            printf("%s X\n", filename);
        }
    }
    fclose(fd);
}
 
static void sigchld_handler_install(void) {
    struct sigaction sa;
 
    sigemptyset(&sa.sa_mask);
    sa.sa_handler = sigchld_handler;
    sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
        perror("sigaction");
        exit(EXIT_FAILURE);
    }
}
 
static void sigchld_handler(int sig) {
    int errsvr;
    int status;
    pid_t pid;
 
    errsvr = errno;
 
    while((pid = waitpid(-1, &status, WNOHANG)) != 0) {
        if (pid == -1) {
            if (errno == ECHILD) {
                break;
            }
            perror("waitpid");
            break;
        }
    }
 
    errno = errsvr;
}
fileattrd: fileattrd.o

.PHONY: clean
clean:
	$(RM) fileattrd fileattrd.o

#restliche regeln sind alle implizit vorhanden

Aufgabe 3

Aufgabe 4