Skip to content

Instantly share code, notes, and snippets.

@julp
Created May 21, 2016 15:33
Show Gist options
  • Save julp/6d8de0763831ae909dbca79c2bb82e32 to your computer and use it in GitHub Desktop.
Save julp/6d8de0763831ae909dbca79c2bb82e32 to your computer and use it in GitHub Desktop.
A basic standalone implementation of pushd/popd based on shared memory
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define PERM 0600
#define MAX_DEPTH 32
extern char *__progname;
int main(int argc, char **argv)
{
char *shmem;
const char *errstr;
int shid, ret, push;
#define failure(x) \
do { \
errstr = x; \
goto end; \
} while (0);
shid = -1;
ret = EXIT_SUCCESS;
#if 1
push = 0 == strcmp("pushd", __progname); // ln .../bin/pushd .../bin/popd
#else
push = 1 != argc;
#endif
//printf("%s\n", push ? "pushd" : "popd");
if (1 + push != argc) {
ret = EXIT_FAILURE;
} else {
int created;
size_t size;
created = 0;
size = MAX_DEPTH * PATH_MAX;
if (-1 == (shid = shmget(getppid(), size, PERM))) {
if (push && ENOENT == errno) {
if (-1 == (shid = shmget(getppid(), size, PERM | IPC_CREAT))) {
failure("shmget");
} else {
created = 1;
}
} else {
failure("shmget");
}
}
if (-1 != shid) {
if (((void *) -1) == (shmem = shmat(shid, 0, 0))) {
failure("shmat");
} else {
char newcwd[PATH_MAX];
#if 0
{
size_t i;
for (i = 0; i < MAX_DEPTH && '\0' != *(((char (*)[PATH_MAX]) shmem)[i]); i++) {
printf("%zu: >%s<\n", i, ((char (*)[PATH_MAX]) shmem)[i]);
}
}
#endif
if (created) {
bzero(shmem, size);
}
if (push) {
memmove(shmem + PATH_MAX, shmem, size - PATH_MAX);
if (NULL == realpath(argv[1], newcwd)) {
failure("realpath");
}
strlcpy(shmem, newcwd, PATH_MAX);
// strlcpy(newcwd, shmem, PATH_MAX);
} else {
strlcpy(newcwd, shmem, PATH_MAX);
memmove(shmem, shmem + PATH_MAX, size - PATH_MAX);
if ('\0' == *(((char (*)[PATH_MAX]) shmem)[0])) {
if (-1 == shmctl(shid, IPC_RMID, NULL)) {
failure("IPC_RMID");
}
}
}
if (-1 == chdir(newcwd)) {
failure("chdir");
} else {
puts(newcwd);
}
}
}
}
if (0) {
end:
ret = EXIT_FAILURE;
perror(errstr);
}
if (-1 != shid) {
if (-1 == shmdt(shmem)) {
perror("shmdt");
}
}
return ret;
}
#if 0
int
wait4all(pid_t *pids, size_t len)
{
int fd, i, nproc, ec;
struct kevent *evts, evt;
if ( (fd = kqueue()) == -1 )
return -1;
evts = xmalloc(sizeof(struct kevent) * len);
for ( i = 0; i < len; i++ ) {
EV_SET(&evts[i], pids[i], EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, 0);
}
i = kevent(fd, evts, len, NULL, 0, 0);
free(evts);
if ( i == -1 )
return -1;
nproc = len;
ec = 0;
while ( nproc > 0 ) {
if ( kevent(fd, NULL, 0, &evt, 1, 0) <= 0 )
return -1;
if ( evt.ident == pids[len - 1] )
ec = evt.data;
nproc -= 1;
}
return ec;
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment