aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bus.c161
-rw-r--r--src/bus.h22
-rw-r--r--src/cmdline.c12
3 files changed, 146 insertions, 49 deletions
diff --git a/src/bus.c b/src/bus.c
index 5965a14..5607dbf 100644
--- a/src/bus.c
+++ b/src/bus.c
@@ -30,6 +30,9 @@
#include <errno.h>
#include <string.h>
#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#include <sys/ipc.h>
#include <sys/sem.h>
@@ -40,37 +43,37 @@
/**
* Semaphore used to signal `bus_write` that `bus_read` is ready
*/
-#define S 0
+#define S 0
/**
* Semaphore for making `bus_write` wait while `bus_read` is reseting `S`
*/
-#define W 1
+#define W 1
/**
* Binary semaphore for making `bus_write` exclusively locked
*/
-#define X 2
+#define X 2
/**
* Semaphore used to cue `bus_read` that it may read the shared memory
*/
-#define Q 3
+#define Q 3
/**
* The number of semaphores in the semaphore array
*/
-#define BUS_SEMAPHORES 4
+#define BUS_SEMAPHORES 4
/**
* Decrease the value of a semaphore by 1
*
- * @param bus:const bus_t * The bus
- * @param semaphore:unsigned short The index of the semaphore, `S`, `W`, `X` or `Q`
- * @param flags:short `SEM_UNDO` if the action should be undone when the program exits
- * @return :int 0 on success, -1 on error
+ * @param bus:const bus_t * The bus
+ * @param semaphore:int The index of the semaphore, `S`, `W`, `X` or `Q`
+ * @param flags:int `SEM_UNDO` if the action should be undone when the program exits
+ * @return :int 0 on success, -1 on error
*/
#define acquire_semaphore(bus, semaphore, flags) \
semaphore_op(bus, semaphore, -1, flags)
@@ -78,10 +81,10 @@
/**
* Increase the value of a semaphore by 1
*
- * @param bus:const bus_t * The bus
- * @param semaphore:unsigned short The index of the semaphore, `S`, `W`, `X` or `Q`
- * @param flags:short `SEM_UNDO` if the action should be undone when the program exits
- * @return :int 0 on success, -1 on error
+ * @param bus:const bus_t * The bus
+ * @param semaphore:int The index of the semaphore, `S`, `W`, `X` or `Q`
+ * @param flags:int `SEM_UNDO` if the action should be undone when the program exits
+ * @return :int 0 on success, -1 on error
*/
#define release_semaphore(bus, semaphore, flags) \
semaphore_op(bus, semaphore, +1, flags)
@@ -89,9 +92,9 @@
/**
* Wait for the value of a semphore to become 0
*
- * @param bus:const bus_t * The bus
- * @param semaphore:unsigned short The index of the semaphore, `S`, `W`, `X` or `Q`
- * @return :int 0 on success, -1 on error
+ * @param bus:const bus_t * The bus
+ * @param semaphore:int The index of the semaphore, `S`, `W`, `X` or `Q`
+ * @return :int 0 on success, -1 on error
*/
#define zero_semaphore(bus, semaphore) \
semaphore_op(bus, semaphore, 0, 0)
@@ -167,7 +170,7 @@ create_semaphores(bus_t *bus)
}
/* Initialise the array. */
- values.array = calloc(BUS_SEMAPHORES, sizeof(unsigned short));
+ values.array = calloc((size_t)BUS_SEMAPHORES, sizeof(unsigned short));
values.array[X] = 1;
if (!values.array)
goto fail;
@@ -210,7 +213,7 @@ create_shared_memory(bus_t *bus)
bus->key_shm = (key_t)r + 1;
if (bus->key_shm == IPC_PRIVATE)
continue;
- id = shmget(bus->key_shm, BUS_MEMORY_SIZE, IPC_CREAT | IPC_EXCL | 0600);
+ id = shmget(bus->key_shm, (size_t)BUS_MEMORY_SIZE, IPC_CREAT | IPC_EXCL | 0600);
if (id != -1)
break;
if ((errno != EEXIST) && (errno != EINTR))
@@ -252,7 +255,7 @@ static int
remove_shared_memory(const bus_t *bus)
{
struct shmid_ds _info;
- int id = shmget(bus->key_shm, BUS_MEMORY_SIZE, 0600);
+ int id = shmget(bus->key_shm, (size_t)BUS_MEMORY_SIZE, 0600);
return ((id == -1) || (shmctl(id, IPC_RMID, &_info) == -1)) ? -1 : 0;
}
@@ -267,13 +270,13 @@ remove_shared_memory(const bus_t *bus)
* @return 0 on success, -1 on error
*/
static int
-semaphore_op(const bus_t *bus, unsigned short semaphore, short delta, short flags)
+semaphore_op(const bus_t *bus, int semaphore, int delta, int flags)
{
struct sembuf op;
- op.sem_op = delta;
- op.sem_num = semaphore;
- op.sem_flg = flags;
- return semop(bus->sem_id, &op, 1);
+ op.sem_num = (unsigned short)semaphore;
+ op.sem_op = (short)delta;
+ op.sem_flg = (short)flags;
+ return semop(bus->sem_id, &op, (size_t)1);
}
@@ -286,11 +289,11 @@ semaphore_op(const bus_t *bus, unsigned short semaphore, short delta, short flag
* @return 0 on success, -1 on error
*/
static int
-write_semaphore(const bus_t *bus, unsigned short semaphore, int value)
+write_semaphore(const bus_t *bus, unsigned semaphore, int value)
{
union semun semval;
semval.val = value;
- return semctl(bus->sem_id, semaphore, SETVAL, semval);
+ return semctl(bus->sem_id, (unsigned short)semaphore, SETVAL, semval);
}
@@ -306,7 +309,7 @@ open_shared_memory(bus_t *bus, int flags)
{
int id;
void *address;
- t(id = shmget(bus->key_shm, BUS_MEMORY_SIZE, 0600));
+ t(id = shmget(bus->key_shm, (size_t)BUS_MEMORY_SIZE, 0600));
address = shmat(id, NULL, (flags & BUS_RDONLY) ? SHM_RDONLY : 0);
if ((address == (void *)-1) || !address)
goto fail;
@@ -334,21 +337,48 @@ fail:
}
+/**
+ * Get a random ASCII letter or digit
+ *
+ * @return A random ASCII letter or digit
+ */
+static char
+randomchar(void)
+{
+ int rint = rand();
+ double r = (double)rint;
+ r /= (double)RAND_MAX + 1;
+ r *= 10 + 26 + 26;
+ return "0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"[(int)r];
+}
+
+
/**
* Create a new bus
*
- * @param file The pathname of the bus, `NULL` to create a random one
- * @param flags `BUS_EXCL` (if `file` is not `NULL`) to fail if the file
- * already exists, otherwise if the file exists, nothing
- * will happen
- * @return The pathname of the bus, `NULL` on error
+ * @param file The pathname of the bus, `NULL` to create a random one
+ * @param flags `BUS_EXCL` (if `file` is not `NULL`) to fail if the file
+ * already exists, otherwise if the file exists, nothing
+ * will happen;
+ * `BUS_INTR` to fail if interrupted
+ * @param out_file Output parameter for the pathname of the bus
+ * @return 0 on success, -1 on error
*/
-const char *
-bus_create(const char *file, int flags)
+int
+bus_create(const char *file, int flags, char **out_file)
{
- int saved_errno;
+ int fd = -1, saved_errno;
bus_t bus;
+ char buf[1 + 2 * (3 * sizeof(ssize_t) + 2)];
+ size_t ptr, len;
+ ssize_t wrote;
+ char *genfile = NULL;
+ const char *env;
+
+ if (out_file)
+ *out_file = NULL;
+
bus.sem_id = -1;
bus.key_sem = -1;
bus.key_shm = -1;
@@ -356,11 +386,60 @@ bus_create(const char *file, int flags)
srand((unsigned int)time(NULL) + (unsigned int)rand());
- /* TODO */ (void) file; (void) flags;
+ if (file) {
+ fd = open(file, O_CREAT | O_EXCL);
+ if (fd == -1) {
+ if ((errno != EEXIST) || (flags & BUS_EXCL))
+ return -1;
+ goto done;
+ }
+ } else {
+ env = getenv("XDG_RUNTIME_DIR");
+ if (!env || !*env)
+ env = "/run";
+ genfile = malloc((strlen(env) + 6 + 7 + 30) * sizeof(char));
+ if (!genfile)
+ goto fail;
+ if (out_file)
+ *out_file = genfile;
+ sprintf(genfile, "%s/run/random.", env);
+ len = strlen(genfile);
+ genfile[len + 30] = '\0';
+ retry:
+ for (ptr = 0; ptr < 30; ptr++)
+ genfile[len + ptr] = randomchar();
+ fd = open(genfile, O_CREAT | O_EXCL);
+ if (fd == -1) {
+ if (errno == EEXIST)
+ goto retry;
+ return -1;
+ }
+ }
t(create_semaphores(&bus));
t(create_shared_memory(&bus));
- return NULL;
+
+ sprintf(buf, "%zi\n%zi\n", (ssize_t)(bus.key_sem), (ssize_t)(bus.key_shm));
+ for (len = strlen(buf), ptr = 0; ptr < len;) {
+ wrote = write(fd, buf + ptr, len - ptr);
+ if (wrote < 0) {
+ if ((errno == EINTR) && (flags & BUS_INTR))
+ goto fail;
+ } else {
+ ptr += (size_t)wrote;
+ }
+ }
+ close(fd);
+
+done:
+ if (out_file && !*out_file) {
+ len = strlen(file) + 1;
+ *out_file = malloc(len * sizeof(char));
+ memcpy(*out_file, file, len * sizeof(char));
+ } else if (!out_file) {
+ free(genfile);
+ }
+ return 0;
fail:
saved_errno = errno;
@@ -368,8 +447,14 @@ fail:
remove_semaphores(&bus);
if (bus.key_shm)
remove_shared_memory(&bus);
+ if (fd == -1)
+ close(fd);
+ if (out_file)
+ *out_file = NULL;
+ free(genfile);
+ unlink(file);
errno = saved_errno;
- return NULL;
+ return -1;
}
diff --git a/src/bus.h b/src/bus.h
index 4068909..267cac9 100644
--- a/src/bus.h
+++ b/src/bus.h
@@ -25,6 +25,9 @@
#define BUS_H
+#ifndef _DEFAULT_SOURCE
+# define _DEFAULT_SOURCE
+#endif
#include <sys/types.h>
@@ -49,6 +52,11 @@
*/
#define BUS_EXCL 2
+/**
+ * Fail if interrupted
+ */
+#define BUS_INTR 4
+
/**
@@ -91,13 +99,15 @@ typedef struct bus
/**
* Create a new bus
*
- * @param file The pathname of the bus, `NULL` to create a random one
- * @param flags `BUS_EXCL` (if `file` is not `NULL`) to fail if the file
- * already exists, otherwise if the file exists, nothing
- * will happen
- * @return The pathname of the bus, `NULL` on error
+ * @param file The pathname of the bus, `NULL` to create a random one
+ * @param flags `BUS_EXCL` (if `file` is not `NULL`) to fail if the file
+ * already exists, otherwise if the file exists, nothing
+ * will happen;
+ * `BUS_INTR` to fail if interrupted
+ * @param out_file Output parameter for the pathname of the bus
+ * @return 0 on success, -1 on error
*/
-const char *bus_create(const char *file, int flags);
+int bus_create(const char *file, int flags, char **out_file);
/**
* Remove a bus
diff --git a/src/cmdline.c b/src/cmdline.c
index fbee2d6..40d0136 100644
--- a/src/cmdline.c
+++ b/src/cmdline.c
@@ -21,11 +21,12 @@
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
+#include "bus.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
-
-#include "bus.h"
+#include <string.h>
@@ -108,18 +109,19 @@ int
main(int argc, char *argv[])
{
bus_t bus;
+ char *file;
argv0 = *argv;
/* Create a new bus with selected name. */
if ((argc == 3) && !strcmp(argv[1], "create")) {
- t(bus_create(argv[2], 0) ? 0 : -1);
+ t(bus_create(argv[2], 0, NULL));
/* Create a new bus with random name. */
} else if ((argc == 2) && !strcmp(argv[1], "create")) {
- const char *file = bus_create(NULL, 0);
- t(file ? 0 : -1);
+ t(bus_create(NULL, 0, &file));
printf("%s\n", file);
+ free(file);
/* Remove a bus. */
} else if ((argc == 3) && !strcmp(argv[1], "remove")) {