История изменений
Исправление firkax, (текущая версия) :
Исходник для проверки теорий на этот счёт
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <dirent.h>
static int send_fd(int s, int fd) {
struct iovec iov = {.iov_base = "", .iov_len = 1};
union {
char buf[CMSG_SPACE(sizeof(fd))];
struct cmsghdr align;
} u;
struct msghdr msg = {.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = u.buf,
.msg_controllen = sizeof(u.buf)};
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
*cmsg = (struct cmsghdr){.cmsg_level = SOL_SOCKET,
.cmsg_type = SCM_RIGHTS,
.cmsg_len = CMSG_LEN(sizeof(fd))};
bcopy(&fd, CMSG_DATA(cmsg), sizeof(fd));
return sendmsg(s, &msg, 0);
}
static int recv_fd(int s) {
int fd;
char b0[1];
struct iovec iov;
struct msghdr msg;
union {
char buf[CMSG_SPACE(sizeof(fd))];
struct cmsghdr align;
} u;
struct cmsghdr *cmsg;
bzero(&msg, sizeof(msg));
iov.iov_base = b0; iov.iov_len = 1;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = u.buf;
msg.msg_controllen = sizeof(u.buf);
if(recvmsg(s, &msg, 0)<0) { fprintf(stderr, "recvmsg() error %d (%s)\n", errno, strerror(errno)); return -1; }
if(msg.msg_controllen!=sizeof(u.buf)) { fprintf(stderr, "wrong recv\n"); return -1; }
if(!(cmsg = CMSG_FIRSTHDR(&msg))) { fprintf(stderr, "wrong recv 2\n"); return -1; }
if(cmsg->cmsg_level!=SOL_SOCKET || cmsg->cmsg_type!=SCM_RIGHTS || cmsg->cmsg_len!=CMSG_LEN(sizeof(fd))) { fprintf(stderr, "wrong recv 2\n"); return -1; }
bcopy(CMSG_DATA(cmsg), &fd, sizeof(fd));
return fd;
}
static int do_listen(char const * spath, char const * fpath) {
int lfd, afd, fd;
struct sockaddr_un sa;
struct stat sb;
bzero(&sa, sizeof(sa));
sa.sun_family = AF_UNIX;
strncpy(sa.sun_path,spath,sizeof(sa.sun_path)-1);
if(lstat(spath,&sb)>=0 && S_ISSOCK(sb.st_mode)) unlink(spath);
if((lfd = socket(PF_UNIX, SOCK_STREAM, 0))<0) { fprintf(stderr, "socket() error %d (%s)\n", errno, strerror(errno)); return -1; }
if(bind(lfd, (struct sockaddr*)&sa, sizeof(sa))<0) { fprintf(stderr, "bind() error %d (%s)\n", errno, strerror(errno)); return -1; }
if(listen(lfd, 1)<0) { fprintf(stderr, "listen() error %d (%s)\n", errno, strerror(errno)); return -1; }
if((fd = open(fpath,O_RDONLY))<0) { fprintf(stderr, "open() error %d (%s)\n", errno, strerror(errno)); return -1; }
while(1) {
if((afd = accept(lfd, NULL, NULL))<0) { fprintf(stderr, "accept() error %d (%s)\n", errno, strerror(errno)); sleep(1); continue; }
if(send_fd(afd, fd)<0) fprintf(stderr, "send_fd() error %d (%s)\n", errno, strerror(errno));
sleep(1);
close(afd);
}
}
static int do_connect(char const * spath) {
int fd;
struct sockaddr_un sa;
bzero(&sa, sizeof(sa));
sa.sun_family = AF_UNIX;
strcpy(sa.sun_path,spath);
if((fd = socket(PF_UNIX, SOCK_STREAM, 0))<0) { fprintf(stderr, "socket() error %d (%s)\n", errno, strerror(errno)); return -1; }
if(connect(fd, (struct sockaddr*)&sa, sizeof(sa))<0) { fprintf(stderr, "connect() error %d (%s)\n", errno, strerror(errno)); return -1; }
return fd;
}
static int do_read(int fd) {
char buf[1024];
int l;
while((l=read(fd,buf,sizeof(buf)))>0) write(1,buf,l);
if(l<0) { fprintf(stderr, "read error %d (%s)\n", errno, strerror(errno)); return -1; }
return 0;
}
static int do_ls(int fd) {
DIR * dp;
struct dirent * de;
if(!(dp=fdopendir(fd))) { fprintf(stderr, "fdopendir error %d (%s)\n", errno, strerror(errno)); return -1; }
while(errno=0,de=readdir(dp)) {
printf("%s\n", de->d_name);
}
if(errno) { fprintf(stderr, "readdir error %d (%s)\n", errno, strerror(errno)); return -1; }
return 0;
}
static int do_lsp(int fd) {
DIR * dp;
struct dirent * de;
if((fd=openat(fd,"..",O_RDONLY))<0) { fprintf(stderr, "open error %d (%s)\n", errno, strerror(errno)); return -1; }
if(!(dp=fdopendir(fd))) { fprintf(stderr, "fdopendir error %d (%s)\n", errno, strerror(errno)); return -1; }
while(errno=0,de=readdir(dp)) {
printf("%s\n", de->d_name);
}
if(errno) { fprintf(stderr, "readdir error %d (%s)\n", errno, strerror(errno)); return -1; }
return 0;
}
int main(int argc, char * * argv) {
int fd, rfd;
if(argc==4 && !strcmp(argv[1],"listen")) return do_listen(argv[2],argv[3]);
if(argc!=3 || !strcmp(argv[1],"listen")) return -1;
if((fd = do_connect(argv[2]))<0) return -1;
if((rfd = recv_fd(fd))<0) return -1;
fprintf(stderr, "rfd = %d\n", rfd);
if(!strcmp(argv[1],"read")) do_read(rfd);
if(!strcmp(argv[1],"ls")) do_ls(rfd);
if(!strcmp(argv[1],"lsp")) do_lsp(rfd);
return 0;
}
Исходная версия firkax, :
Исходник для проверки теорий на этот счёт
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <dirent.h>
static int send_fd(int s, int fd) {
struct iovec iov = {.iov_base = "", .iov_len = 1};
union {
char buf[CMSG_SPACE(sizeof(fd))];
struct cmsghdr align;
} u;
struct msghdr msg = {.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = u.buf,
.msg_controllen = sizeof(u.buf)};
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
*cmsg = (struct cmsghdr){.cmsg_level = SOL_SOCKET,
.cmsg_type = SCM_RIGHTS,
.cmsg_len = CMSG_LEN(sizeof(fd))};
bcopy(&fd, CMSG_DATA(cmsg), sizeof(fd));
return sendmsg(s, &msg, 0);
}
static int recv_fd(int s) {
int fd;
char b0[1];
struct iovec iov;
struct msghdr msg;
union {
char buf[CMSG_SPACE(sizeof(fd))];
struct cmsghdr align;
} u;
struct cmsghdr *cmsg;
bzero(&msg, sizeof(msg));
iov.iov_base = b0; iov.iov_len = 1;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = u.buf;
msg.msg_controllen = sizeof(u.buf);
if(recvmsg(s, &msg, 0)<0) { fprintf(stderr, "recvmsg() error %d (%s)\n", errno, strerror(errno)); return -1; }
if(msg.msg_controllen!=sizeof(u.buf)) { fprintf(stderr, "wrong recv\n"); return -1; }
if(!(cmsg = CMSG_FIRSTHDR(&msg))) { fprintf(stderr, "wrong recv 2\n"); return -1; }
if(cmsg->cmsg_level!=SOL_SOCKET || cmsg->cmsg_type!=SCM_RIGHTS || cmsg->cmsg_len!=CMSG_LEN(sizeof(fd))) { fprintf(stderr, "wrong recv 2\n"); return -1; }
bcopy(CMSG_DATA(cmsg), &fd, sizeof(fd));
return fd;
}
static int do_listen(char const * spath, char const * fpath) {
int lfd, afd, fd;
struct sockaddr_un sa;
struct stat sb;
bzero(&sa, sizeof(sa));
sa.sun_family = AF_UNIX;
strcpy(sa.sun_path,spath);
if(lstat(spath,&sb)>=0 && S_ISSOCK(sb.st_mode)) unlink(spath);
if((lfd = socket(PF_UNIX, SOCK_STREAM, 0))<0) { fprintf(stderr, "socket() error %d (%s)\n", errno, strerror(errno)); return -1; }
if(bind(lfd, (struct sockaddr*)&sa, sizeof(sa))<0) { fprintf(stderr, "bind() error %d (%s)\n", errno, strerror(errno)); return -1; }
if(listen(lfd, 1)<0) { fprintf(stderr, "listen() error %d (%s)\n", errno, strerror(errno)); return -1; }
if((fd = open(fpath,O_RDONLY))<0) { fprintf(stderr, "open() error %d (%s)\n", errno, strerror(errno)); return -1; }
while(1) {
if((afd = accept(lfd, NULL, NULL))<0) { fprintf(stderr, "accept() error %d (%s)\n", errno, strerror(errno)); sleep(1); continue; }
if(send_fd(afd, fd)<0) fprintf(stderr, "send_fd() error %d (%s)\n", errno, strerror(errno));
sleep(1);
close(afd);
}
}
static int do_connect(char const * spath) {
int fd;
struct sockaddr_un sa;
bzero(&sa, sizeof(sa));
sa.sun_family = AF_UNIX;
strcpy(sa.sun_path,spath);
if((fd = socket(PF_UNIX, SOCK_STREAM, 0))<0) { fprintf(stderr, "socket() error %d (%s)\n", errno, strerror(errno)); return -1; }
if(connect(fd, (struct sockaddr*)&sa, sizeof(sa))<0) { fprintf(stderr, "connect() error %d (%s)\n", errno, strerror(errno)); return -1; }
return fd;
}
static int do_read(int fd) {
char buf[1024];
int l;
while((l=read(fd,buf,sizeof(buf)))>0) write(1,buf,l);
if(l<0) { fprintf(stderr, "read error %d (%s)\n", errno, strerror(errno)); return -1; }
return 0;
}
static int do_ls(int fd) {
DIR * dp;
struct dirent * de;
if(!(dp=fdopendir(fd))) { fprintf(stderr, "fdopendir error %d (%s)\n", errno, strerror(errno)); return -1; }
while(errno=0,de=readdir(dp)) {
printf("%s\n", de->d_name);
}
if(errno) { fprintf(stderr, "readdir error %d (%s)\n", errno, strerror(errno)); return -1; }
return 0;
}
static int do_lsp(int fd) {
DIR * dp;
struct dirent * de;
if((fd=openat(fd,"..",O_RDONLY))<0) { fprintf(stderr, "open error %d (%s)\n", errno, strerror(errno)); return -1; }
if(!(dp=fdopendir(fd))) { fprintf(stderr, "fdopendir error %d (%s)\n", errno, strerror(errno)); return -1; }
while(errno=0,de=readdir(dp)) {
printf("%s\n", de->d_name);
}
if(errno) { fprintf(stderr, "readdir error %d (%s)\n", errno, strerror(errno)); return -1; }
return 0;
}
int main(int argc, char * * argv) {
int fd, rfd;
if(argc==4 && !strcmp(argv[1],"listen")) return do_listen(argv[2],argv[3]);
if(argc!=3 || !strcmp(argv[1],"listen")) return -1;
if((fd = do_connect(argv[2]))<0) return -1;
if((rfd = recv_fd(fd))<0) return -1;
fprintf(stderr, "rfd = %d\n", rfd);
if(!strcmp(argv[1],"read")) do_read(rfd);
if(!strcmp(argv[1],"ls")) do_ls(rfd);
if(!strcmp(argv[1],"lsp")) do_lsp(rfd);
return 0;
}