FreeBSD: Gradle failure of PosixFileFunctions.chmod

When I was building my Java project with Gradle on FreeBSD 10.3/amd64, the gradlew failed.

$ ./gradlew build
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar

FAILURE: Build failed with an exception.

* What went wrong:
net.rubygrapefruit.platform.internal.jni.PosixFileFunctions.chmod(Ljava/lang/String;ILnet/rubygrapefruit/platform/internal/FunctionResult;)V

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 3.733 secs

When I gave an -S option, I got:

:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar

FAILURE: Build failed with an exception.

* What went wrong:
net.rubygrapefruit.platform.internal.jni.PosixFileFunctions.chmod(Ljava/lang/Str
ing;ILnet/rubygrapefruit/platform/internal/FunctionResult;)V

* Try:
Run with --info or --debug option to get more log output.

* Exception is:
java.lang.UnsatisfiedLinkError: net.rubygrapefruit.platform.internal.jni.PosixFi
leFunctions.chmod(Ljava/lang/String;ILnet/rubygrapefruit/platform/internal/Funct
ionResult;)V
        at net.rubygrapefruit.platform.internal.jni.PosixFileFunctions.chmod(Nat
ive Method)
        at net.rubygrapefruit.platform.internal.DefaultPosixFiles.setMode(Defaul
tPosixFiles.java:39)
        at org.gradle.internal.nativeintegration.filesystem.services.NativePlatformBackedChmod.chmod(NativePlatformBackedChmod.java:32)
        at org.gradle.internal.nativeintegration.filesystem.services.GenericFileSystem.chmod(GenericFileSystem.java:69)
        at org.gradle.api.internal.file.AbstractFileTreeElement.copyTo(AbstractFileTreeElement.java:76)
        at org.gradle.api.internal.file.collections.MapFileTree$FileVisitDetailsImpl.getFile(MapFileTree.java:144)
        at org.gradle.api.internal.file.AbstractFileTree$1.visitFile(AbstractFileTree.java:39)
        at org.gradle.api.internal.file.AbstractFileTree$FilteredFileTree$1.visitFile(AbstractFileTree.java:145)
        at org.gradle.api.internal.file.collections.MapFileTree$Visit.visit(MapFileTree.java:113)
        at org.gradle.api.internal.file.collections.MapFileTree.visit(MapFileTree.java:75)
        at org.gradle.api.internal.file.collections.FileTreeAdapter.visit(FileTreeAdapter.java:96)
        at org.gradle.api.internal.file.AbstractFileTree$FilteredFileTree.visit(AbstractFileTree.java:136)
        at org.gradle.api.internal.file.AbstractFileTree.getFiles(AbstractFileTree.java:37)
        at org.gradle.api.internal.file.CompositeFileCollection.getFiles(CompositeFileCollection.java:39)
        at org.gradle.api.internal.changedetection.state.DefaultFileCollectionSnapshotter.snapshot(DefaultFileCollectionSnapshotter.java:47)
        at org.gradle.api.internal.changedetection.rules.TaskUpToDateState.(TaskUpToDateState.java:55)
        at org.gradle.api.internal.changedetection.changes.DefaultTaskArtifactStateRepository$TaskArtifactStateImpl.getStates(DefaultTaskArtifactStateRepository.java:126)
        at org.gradle.api.internal.changedetection.changes.DefaultTaskArtifactStateRepository$TaskArtifactStateImpl.isUpToDate(DefaultTaskArtifactStateRepository.java:69)
        at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:52)
        at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
        at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:42)
        at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
        at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:53)
        at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
        at org.gradle.api.internal.AbstractTask.executeWithoutThrowingTaskFailure(AbstractTask.java:305)
        at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.executeTask(AbstractTaskPlanExecutor.java:79)
        at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:63)
        at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:51)
        at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:23)
        at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:88)
        at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:29)
        at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:62)
        at org.gradle.execution.DefaultBuildExecuter.access$200(DefaultBuildExecuter.java:23)
        at org.gradle.execution.DefaultBuildExecuter$2.proceed(DefaultBuildExecuter.java:68)
        at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
        at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:62)
        at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:55)
        at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:149)
        at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:106)
        at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:86)
        at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:80)
        at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:33)
        at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:24)
        at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:36)
        at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:26)
        at org.gradle.launcher.cli.RunBuildAction.run(RunBuildAction.java:51)
        at org.gradle.internal.Actions$RunnableActionAdapter.execute(Actions.java:171)
        at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:237)
        at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:210)
        at org.gradle.launcher.cli.JavaRuntimeValidationAction.execute(JavaRuntimeValidationAction.java:35)
        at org.gradle.launcher.cli.JavaRuntimeValidationAction.execute(JavaRuntimeValidationAction.java:24)
        at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:206)
        at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:169)
        at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:33)
        at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:22)
        at org.gradle.launcher.Main.doAction(Main.java:33)
        at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:45)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:54)
        at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:35)
        at org.gradle.launcher.GradleMain.main(GradleMain.java:23)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.gradle.wrapper.BootstrapMainStarter.start(BootstrapMainStarter.java:30)
        at org.gradle.wrapper.WrapperExecutor.execute(WrapperExecutor.java:127)
        at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:56)


BUILD FAILED

Total time: 3.752 secs

Some people are saying that I need gcc. I fixed this problem by:

$ sudo pkg install gcc6

Android Studio: Cannot execute aidl

When I built my Android application on Ubuntu Linux 16.04 in my amd64 machine with Andriod Studio, the Android Studio caused an error. The Andrdoid Studio said:

Error:Execution failed for task ':foobarbazquux:compileDebugAidl'.
> java.lang.RuntimeException: org.gradle.process.internal.ExecException: A problem occurred starting process 'command '/home/tom/Android/Sdk/build-tools/21.1.2/aidl''

Because the Sdk/build-tools/21.1.2/aidl is a 32bit application.

$ file aidl
aidl: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.15, not stripped

This executable needs 32bit libraries to work. I installed these with:

$ sudo apt-get install lib32z1 lib32ncurses5 libbz2-1.0:i386 lib32stdc++6

After this, the aidl got usable.

$ ./aidl
INPUT required
usage: aidl OPTIONS INPUT [OUTPUT]
       aidl --preprocess OUTPUT INPUT...

OPTIONS:
   -I<DIR>    search path for import statements.
   -d<FILE>   generate dependency file.
   -a         generate dependency file next to the output file with the name based on the input file.
   -p<FILE>   file created by --preprocess to import.
   -o<FOLDER> base output folder for generated files.
   -b         fail when trying to compile a parcelable.

INPUT:
   An aidl interface file.

OUTPUT:
   The generated interface files.
   If omitted and the -o option is not used, the input filename is used, with the .aidl extension changed to a .java extension.
   If the -o option is used, the generated files will be placed in the base output folder, under their package folder

FreeBSD: missing /usr/local/sbin/pkg

I have installed FreeBSD 10.3/amd64 to my machine. The new significant feature of FreeBSD is pkg.

pkg initialized itself at first time of executing. This process must give me /usr/local/sbin/pkg, but I did not get. What I had was only /usr/local/sbin/pkg-static.

I fixed this problem with

# pkg-static upgrade -f pkg

cLayz 1/6 のの (Nono)

Done.

のの (Nono) is a character in ぽぽたん (Popotan). Unboxing review of this kit is in my blog.

I took some photos of the legs before assembling.

The skin color is Pale Orange over Carrot Orange of 美少女フィギュア・フレッシュ セット (Cutie Girls Figure Fresh Color Set). 袴 (hakama, the red pant) is painted with Mr. Color 79 Shine Red. The blue of the hair is mixed of Mr. Color 1 White and Mr. Color 110 Character Blue. I painted the white cloth with Mr. Color 107 Character White over a layer of Smalt Blue in Mr. Color みるきぃぱすてるカラーセット ブルーver. (Milky Pastel Color Set Blue Ver.).

Simple daemon example using kqueue

The below code is a simple daemon. This daemon listens the port of number 4,226. When a client connects to this, this daemon disconnects immediately. This daemon stops for SIGTERM. This daemon works on FreeBSD.

I wrote this daemon to investigate other software, but I found that this is helpful to start writing a new daemon using kqueue(2).

This code is also available in Gist.

/*
 * This is public domain.
 */
#include <sys/types.h>
#include <sys/event.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <errno.h>
#include <libgen.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>

static void
die(const char *fmt, ...)
{
	va_list ap;
	int errnum;
	char buf[8192], buf2[8192];

	errnum = errno;

	va_start(ap, fmt);
	vsnprintf(buf, sizeof(buf), fmt, ap);
	va_end(ap);
	snprintf(buf2, sizeof(buf2), "%s: %s", buf, strerror(errnum));

	fputs(buf2, stderr);
	syslog(LOG_ERR, "%s", buf2);

	exit(1);
}

#define	array_sizeof(a)	(sizeof((a)) / sizeof((a)[0]))
#define	PORT		4226

int
main(int argc, const char *argv[])
{
	struct sockaddr_storage addr;
	struct sockaddr_in *paddr;
	struct kevent changelist[2], eventlist[2];
	sigset_t set;
	uintptr_t ident;
	int fd, i, kq, level, nchanges, nev, nevents, optname, optval, sock;
	u_short flags;
	char buf[256];

	strncpy(buf, argv[0], sizeof(buf));
	openlog(basename(buf), LOG_PID, LOG_DAEMON);

	sock = socket(PF_INET, SOCK_STREAM, 0);
	if (sock == -1)
		die("cannot socket(2)");
	level = SOL_SOCKET;
	optname = SO_REUSEADDR;
	optval = 1;
	if (setsockopt(sock, level, optname, &optval, sizeof(optval)) == -1)
		die("cannot setsockopt(2)");
	paddr = (struct sockaddr_in *)&addr;
	paddr->sin_len = sizeof(*paddr);
	paddr->sin_family = AF_INET;
	paddr->sin_port = htons(PORT);
	paddr->sin_addr.s_addr = INADDR_ANY;
	if (bind(sock, (struct sockaddr *)paddr, paddr->sin_len) == -1)
		die("cannot bind(2)");
	if (listen(sock, 0) == -1)
		die("cannot listen(2)");

	if (daemon(1, 0) == -1)
		die("cannot daemon(3)");
	syslog(LOG_INFO, "started");

	kq = kqueue();
	if (kq == -1)
		die("cannot kqueue(2)");
	flags = EV_ADD | EV_ENABLE;
	EV_SET(&changelist[0], sock, EVFILT_READ, flags, 0, 0, NULL);
	EV_SET(&changelist[1], SIGTERM, EVFILT_SIGNAL, flags, 0, 0, NULL);
	nchanges = array_sizeof(changelist);
	if (kevent(kq, changelist, nchanges, NULL, 0, NULL) == -1)
		die("cannot kevent(2)");

	if (sigemptyset(&set) == -1)
		die("cannot sigemptyset(3)");
	if (sigaddset(&set, SIGTERM) == -1)
		die("cannot sigaddset(3)");
	if (sigprocmask(SIG_BLOCK, &set, NULL) == -1)
		die("cannot sigprocmask(2)");

	nevents = array_sizeof(eventlist);
	while (0 < (nev = kevent(kq, NULL, 0, eventlist, nevents, NULL)))
		for (i = 0; i < nev; i++)
			switch (eventlist[i].filter) {
			case EVFILT_READ:
				if ((fd = accept(sock, NULL, 0)) == -1)
					die("cannot accept(2)");
				syslog(LOG_INFO, "connected");
				if (close(fd) == -1)
					die("cannot close(2)");
				break;
			case EVFILT_SIGNAL:
				goto exit;
			default:
				break;
			}

exit:
	close(kq);
	close(sock);
	syslog(LOG_INFO, "exit");
	closelog();

	return (0);
}

Bandai 1/144 HGUC Ball

ball_010

I built a ball with metallic paints.

This kit has some ABS parts. I coated them as a first layer with the primer of Tamiya. And I painted it with

  • Mr. Color 8, silver (for the body)
  • Mr. Color 75, metallic red (for the red parts)
  • Mr. Color 28, steel (for the canon)

A build custom GP base is applicable to this. The manual is saying that you can also use an Action Base 2.

File descriptor passing with sendmsg(2) and recvmsg(2) over Unix domain socket

Overview

Two processes connected with Unix domain socket can share file descriptors with sendmsg(2) and recvmsg(2) even if the file descriptors are created after fork(2).

This article is for FreeBSD, but I guess that this method is available on Linux.

Description

If two or more processes want to share a file descriptor, the most usual way is fork(2) after creating the file descriptor with open(2), pipe(2) and so on.

But when the processes are connected with Unix domain socket, you can use sendmsg(2) and recvmsg(2), too. If you use these system calls, you can open the file to share after calling fork(2).

What you need to send the file descriptor are:

  1. giving SOL_SOCKET to cmsg_level of a struct cmsghdr
  2. giving SCM_RIGHTS to cmsg_type of the struct cmsghdr
  3. placing the file descriptor at last of the struct cmsghdr
  4. assigning the struct cmsghdr to msg_control of a struct msghdr
  5. passing the struct msghdr to sendmsg(2) with the Unix domain socket

Using CMSG_DATA is easy to get a pointer to last of the struct cmsghdr for 3.

To have the file descriptor, you must call recvmsg(2) with a struct msghdr pointing a struct cmsghdr including SOL_SOCKET, SCM_RIGHTS and space to store the file descriptor. If recvmsg(2) successes, you will have the file descriptor at this space.

Sample code

This code is also available in Gist.

#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define	SIG	SIGUSR1

static void
diec(int error, const char *msg)
{

	fprintf(stderr, "%s: %s\n", msg, strerror(error));
	exit(1);
}

static void
die(const char *msg)
{

	diec(errno, msg);
}

#if 0
static void
print_alive_fd(const char *tag)
{
	struct stat sb;
	int i;

	for (i = 0; i < 32; i++) {
		if (fstat(i, &sb) == -1)
			continue;
		printf("%s: fd %d is alive.\n", tag, i);
	}
}
#endif

static int
do_sendmsg(int sock, const char *sockpath, int fd)
{
	struct msghdr msg;
	struct cmsghdr *cmsghdr;
	struct iovec iov[1];
	ssize_t nbytes;
	int i, *p;
	char buf[CMSG_SPACE(sizeof(int))], c;

	c = '*';
	iov[0].iov_base = &c;
	iov[0].iov_len = sizeof(c);
	memset(buf, 0x0b, sizeof(buf));
	cmsghdr = (struct cmsghdr *)buf;
	cmsghdr->cmsg_len = CMSG_LEN(sizeof(int));
	cmsghdr->cmsg_level = SOL_SOCKET;
	cmsghdr->cmsg_type = SCM_RIGHTS;
	msg.msg_name = NULL;
	msg.msg_namelen = 0;
	msg.msg_iov = iov;
	msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
	msg.msg_control = cmsghdr;
	msg.msg_controllen = CMSG_LEN(sizeof(int));
	msg.msg_flags = 0;
	p = (int *)CMSG_DATA(buf);
	*p = fd;
	printf("sendmsg: %d\n", fd);

	nbytes = sendmsg(sock, &msg, 0);
	if (nbytes == -1)
		return (1);

	return (0);
}

static int
server_main(pid_t ppid, const char *sockpath)
{
	struct sockaddr_storage storage;
	struct sockaddr_un *addr;
	int error, fd, s, sock;
	const char *filepath = "fd_passing.txt";

	sock = socket(PF_LOCAL, SOCK_STREAM, 0);
	if (sock == -1)
		die("socket(2)");
	addr = (struct sockaddr_un *)&storage;
	addr->sun_family = AF_LOCAL;
	strlcpy(addr->sun_path, sockpath, sizeof(addr->sun_path));
	addr->sun_len = SUN_LEN(addr);
	if (bind(sock, (struct sockaddr *)addr, addr->sun_len) == -1)
		die("bind(2)");
	if (listen(sock, 0) == -1)
		goto fail;
	if (kill(ppid, SIG) == -1)
		goto fail;
	if ((s = accept(sock, NULL, 0)) == -1)
		goto fail;
	if (unlink(filepath) == -1)
		goto fail;
	if ((fd = open(filepath, O_WRONLY | O_CREAT, 0644)) == -1)
		goto fail;

	if (do_sendmsg(s, sockpath, fd) != 0)
		goto fail;

	if (close(fd) == -1)
		goto fail;
	if (close(s) == -1)
		goto fail;
	if (close(sock) == -1)
		goto fail;
	if (unlink(sockpath) == -1)
		goto fail;

	return (0);

fail:
	error = errno;
	unlink(sockpath);
	diec(error, "");

	/* NOTREACHED */
	return (1);
}

static int
do_recvmsg(int sock)
{
	struct msghdr msg;
	struct cmsghdr *cmsghdr;
	struct iovec iov[1];
	FILE *fp;
	ssize_t nbytes;
	int i, *p;
	char buf[CMSG_SPACE(sizeof(int))], c;

	iov[0].iov_base = &c;
	iov[0].iov_len = sizeof(c);
	memset(buf, 0x0d, sizeof(buf));
	cmsghdr = (struct cmsghdr *)buf;
	cmsghdr->cmsg_len = CMSG_LEN(sizeof(int));
	cmsghdr->cmsg_level = SOL_SOCKET;
	cmsghdr->cmsg_type = SCM_RIGHTS;
	msg.msg_name = NULL;
	msg.msg_namelen = 0;
	msg.msg_iov = iov;
	msg.msg_iovlen = sizeof(iov) / sizeof(iov[0]);
	msg.msg_control = cmsghdr;
	msg.msg_controllen = CMSG_LEN(sizeof(int));
	msg.msg_flags = 0;

	nbytes = recvmsg(sock, &msg, 0);
	if (nbytes == -1)
		return (1);

	p = (int *)CMSG_DATA(buf);
	printf("recvmsg: %d\n", *p);
	fp = fdopen(*p, "w");
	fprintf(fp, "OK\n");
	fclose(fp);

	return (0);
}

static int
client_main(pid_t pid, const char *sockpath)
{
	struct sockaddr_storage sockaddr;
	struct sockaddr_un *addr;
	sigset_t set;
	int sig, sock, status;
	const char *signame;

	if (sigemptyset(&set) == -1)
		die("sigemptyset(3)");
	if (sigaddset(&set, SIG) == -1)
		die("sigaddset(3)");
	if (sigwait(&set, &sig) != 0)
		die("sigwait(2)");
	if (sig != SIG)
		return (2);
	sock = socket(PF_LOCAL, SOCK_STREAM, 0);
	if (sock == -1)
		die("socket(2)");
	addr = (struct sockaddr_un *)&sockaddr;
	addr->sun_family = AF_LOCAL;
	strlcpy(addr->sun_path, sockpath, sizeof(addr->sun_path));
	addr->sun_len = SUN_LEN(addr);
	if (connect(sock, (struct sockaddr *)addr, addr->sun_len) == -1)
		die("connect(2)");

	if (do_recvmsg(sock) == -1)
		return (3);

	if (close(sock) == -1)
		die("close(2)");
	if (wait4(pid, &status, 0, NULL) == -1)
		die("wait4(2)");
	if (!WIFEXITED(status))
		return (4);
	if (WEXITSTATUS(status) != 0)
		return (32 + WEXITSTATUS(status));

	return (0);
}

int
main(int argc, const char *argv[])
{
	sigset_t set;
	pid_t pid, ppid;
	char sockpath[MAXPATHLEN];

	if (sigfillset(&set) == -1)
		die("sigfillset(3)");
	if (sigprocmask(SIG_BLOCK, &set, NULL) == -1)
		die("sigprocmask(2)");

	ppid = getpid();
	snprintf(sockpath, sizeof(sockpath), "%d.sock", ppid);

	pid = fork();
	switch (pid) {
	case -1:
		die("fork(2)");
	case 0:
		return (server_main(ppid, sockpath));
	default:
		break;
	}

	return (client_main(pid, sockpath));
}

This program fork(2)s. The child process will make a Unix domain socket, and the parent process will connect to it.

The child process opens a file (fd_passing.txt) after the fork(2). The process will call sendmsg(2) to send the file descriptor to the parent over the Unix domain socket. The parent will write message (“OK”) to the file after receiving the file descriptor.

This program will output like:

sendmsg: 5
recvmsg: 4

This means that the child process sent a file descriptor of 5, and the parent received it as a file descriptor of 4.