Which bytes should be written to a pty to generate KEY_HOME? - c

I'm trying to test an ncurses application in a pty. Which bytes should be sent to the pty master to trigger key codes for KEY_RESIZE, KEY_HOME, KEY_END, etc.?
There is some code posted below which I truly hope no-one ever wastes time looking at, but will include for completeness. This code behaves as follows:
$ perl -e "print pack('c', 8)" | ./wrappty ./show-key
KEY_BACKSPACE
That is, if I write 0x08 to the pty, the ncurses application treats it as a backspace. What byte sequences should be written to trigger the other key codes? I would hazard a guess that the particular byte sequence depends on the terminal, so I'm wondering if there is a standard for ptys, or if there is a reasonable method to determine the correct byte sequence.
wrappty.c:
#include <assert.h>
#include <ctype.h>
#include <err.h>
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <unistd.h>
#ifdef __linux__
# include <pty.h>
# include <utmp.h>
#else
# include <util.h>
#endif
static void
show_data(const char *t, ssize_t s)
{
for( ; s > 0; t++, s-- ) {
const char *fmt = isprint(*t) ? "%c" : "0x%02x";
fprintf(stderr, fmt, *(unsigned char *)t);
}
fflush(stderr);
}
static ssize_t
send_msg(int fd, int b)
{
char buf[1024];
if( b != EOF ) {
write(fd, &b, 1);
}
ssize_t s;
while( (s = read(fd, buf, sizeof buf)) == sizeof buf ) {
show_data(buf, s);
}
show_data(buf, s);
return s;
}
static void
wait_for(int fd, const char *expect, size_t siz)
{
int rc = 0;
char buf[1024];
char *a = buf;
assert(siz < sizeof buf);
char *end = buf + siz;
while( a < end ) {
ssize_t s = read(fd, a, end - a);
char *e = a + s;
rc += 1;
while( a < e && *a++ == *expect++ ) {
;
}
if( s < 1 || a < e ) {
fprintf(stderr, "Ivalid data\nReceived: ");
show_data(buf, e - buf);
fprintf(stderr, "\nExpected: ");
show_data(expect, siz);
fputc('\n', stderr);
exit(1);
}
}
}
void noop(int sig, siginfo_t *i, void *v) { (void)sig; (void)i; (void)v; }
int
main(int argc, char **argv)
{
int primary, secondary, c;
struct winsize ws = { .ws_row = 24, .ws_col = 80 };
(void) argc;
if( openpty(&primary, &secondary, NULL, NULL, &ws) ) {
err(EXIT_FAILURE, "openpty");
}
switch( fork() ) {
case -1:
err(1, "fork");
break;
case 0:
if( close(primary) ) {
err(EXIT_FAILURE, "close");
}
if( login_tty(secondary) ) {
err(EXIT_FAILURE, "login_tty");
}
execvp(argv[1], argv + 1);
err(EXIT_FAILURE, "execvp %s", argv[1]);
}
/* Parent */
if( close(secondary) ) {
err(EXIT_FAILURE, "close");
}
/* Initialization sequence from ncurses on macos */
char *expected = "\x1b(B\x1b)0\x1b[?1049h\x1b[1;24r\x1b[m\x0f\x1b[4l"
"\x1b[?1h\x1b=\x1b[H\x1b[J";
struct sigaction act;
memset(&act, 0, sizeof act);
act.sa_sigaction = noop;
if( sigaction( SIGALRM, &act, NULL ) ) {
perror("sigaction");
return EXIT_FAILURE;
}
struct timeval tp = {.tv_sec = 0, .tv_usec = 500000 };
struct itimerval t = { .it_interval = tp, .it_value = tp };
setitimer(ITIMER_REAL, &t, NULL);
wait_for(primary, expected, strlen(expected));
while( (c = getchar()) != EOF ) {
send_msg(primary, c);
}
send_msg(primary, EOF);
fputc('\n', stderr);
return 0;
}
show-key.c:
#define _POSIX_C_SOURCE 200809L
#define _XOPEN_SOURCE 600
#define _XOPEN_SOURCE_EXTENDED
#define _DARWIN_C_SOURCE
#include <ctype.h>
#include <curses.h>
#include <err.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
int xopen(const char *path, int flags);
void
handle(int sig, siginfo_t *i, void *v)
{
(void)i;
(void)v;
char *n = NULL;
switch(sig) {
case SIGHUP: n = "SIGHUP\n"; break;
case SIGTERM: n = "SIGTERM\n"; break;
case SIGINT: n = "SIGINT\n"; break;
}
if(n)
write(2, n, strlen(n));
return;
}
int
main(int argc, char **argv)
{
int r;
wint_t w = 0;
if( argc > 1 ) {
int fd = xopen(argv[1], O_WRONLY);
dup2(fd, STDERR_FILENO);
}
unsetenv("COLUMNS");
unsetenv("LINES");
struct sigaction act;
memset(&act, 0, sizeof act);
act.sa_sigaction = handle;
if( sigaction( SIGTERM, &act, NULL ) ) { perror("sigaction"); exit(1); }
if( sigaction( SIGINT, &act, NULL ) ) { perror("sigaction"); exit(1); }
if( sigaction( SIGHUP, &act, NULL ) ) { perror("sigaction"); exit(1); }
if( initscr() == NULL ) {
err(1, "initscr");
}
noecho();
keypad(stdscr, true);
while( (r = get_wch(&w)) != ERR ) {
char *d = NULL;
if( r == KEY_CODE_YES ) switch(w) {
case KEY_RESIZE: d = "KEY_RESIZE"; break;
case KEY_HOME: d = "KEY_HOME"; break;
case KEY_END: d = "KEY_END"; break;
case KEY_PPAGE: d = "KEY_PPAGE"; break;
case KEY_NPAGE: d = "KEY_NPAGE"; break;
case KEY_BACKSPACE: d = "KEY_BACKSPACE"; break;
case KEY_DC: d = "KEY_DC"; break;
case KEY_IC: d = "KEY_IC"; break;
case KEY_BTAB: d = "KEY_BTAB"; break;
case KEY_ENTER: d = "KEY_ENTER"; break;
case KEY_UP: d = "KEY_UP"; break;
case KEY_DOWN: d = "KEY_DOWN"; break;
case KEY_RIGHT: d = "KEY_RIGHT"; break;
case KEY_LEFT: d = "KEY_LEFT"; break;
}
if( d != NULL ) {
/*printw("(%s)", d);*/
fprintf(stderr, "%s", d);
} else {
/*printw("%lc", w);*/
fprintf(stderr, "%lc", w);
}
/*doupdate();*/
fflush(stderr);
}
endwin();
fprintf(stderr, "ERR\n");
return 0;
}
int
xopen(const char *path, int flags)
{
int f = open(path, flags);
if( f == -1 ) {
perror(path);
exit(EXIT_FAILURE);
}
return f;
}

Use tigetstr for fetching strings that correspond to the keys. Most are easily related to the curses names (which are listed in the getch manpage):
foo = tigetstr("khome"); // KEY_HOME
It would be nice to have a table, but since the naming convention is intuitive, no one seems to feel the need...

Related

using memfd_create and fexecve to run ELF from memory

I know other people have done it in different languages but I cannot find a C code example at all, the most common was in Perl and it was really confusing because I don't know Perl
and I just want to load a binary file (from disk) into memory and then execute it
https://magisterquis.github.io/2018/03/31/in-memory-only-elf-execution.html
Here you go, an example writen in C (compiled on linux 5.4 and run as expected):
#define _GNU_SOURCE
#define _POSIX_C_SOURCE 200809L
#include <sys/types.h>
#include <sys/mman.h>
#include <unistd.h>
#include <err.h>
#include <errno.h>
size_t min(size_t x, size_t y)
{
return x > y ? y : x;
}
/**
* #param len != 0
*/
void fdput(int fd, const char *str, size_t len)
{
size_t cnt = 0;
do {
ssize_t result = write(fd, str + cnt, min(len - cnt, 0x7ffff000));
if (result == -1) {
if (errno == EINTR)
continue;
err(1, "%s failed", "write");
}
cnt += result;
} while (cnt != len);
}
#define fdputc(fd, constant_str) fdput((fd), (constant_str), sizeof(constant_str) - 1)
int main(int argc, char* argv[])
{
int fd = memfd_create("script", 0);
if (fd == -1)
err(1, "%s failed", "memfd_create");
fdputc(fd, "#!/bin/bash\necho Hello, world!");
{
const char * const argv[] = {"script", NULL};
const char * const envp[] = {NULL};
fexecve(fd, (char * const *) argv, (char * const *) envp);
}
err(1, "%s failed", "fexecve");
}
I also tested with calling fork() just before fexecve, and it also works as expected.
Here's the code (mostly identical to the one provides above):
#define _GNU_SOURCE
#define _POSIX_C_SOURCE 200809L
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <unistd.h>
#include <err.h>
#include <errno.h>
size_t min(size_t x, size_t y)
{
return x > y ? y : x;
}
/**
* #param len != 0
*/
void fdput(int fd, const char *str, size_t len)
{
size_t cnt = 0;
do {
ssize_t result = write(fd, str + cnt, min(len - cnt, 0x7ffff000));
if (result == -1) {
if (errno == EINTR)
continue;
err(1, "%s failed", "write");
}
cnt += result;
} while (cnt != len);
}
#define fdputc(fd, constant_str) fdput((fd), (constant_str), sizeof(constant_str) - 1)
int main(int argc, char* argv[])
{
int fd = memfd_create("script", 0);
if (fd == -1)
err(1, "%s failed", "memfd_create");
fdputc(fd, "#!/bin/bash\necho Hello, world!");
pid_t pid = fork();
if (pid == 0) {
const char * const argv[] = {"script", NULL};
const char * const envp[] = {NULL};
fexecve(fd, (char * const *) argv, (char * const *) envp);
err(1, "%s failed", "fexecve");
} else if (pid == -1)
err(1, "%s failed", "fork");
wait(NULL);
return 0;
}

Authentication error on pam application without asking password

I have an application running on an unprivileged user, but at some point this program needs to run another one as a root, would be nice if I can reuse a configured PAM module, like, su, sudo, login or anyone.
So I am trying to write some code to authenticate the root and run this program using PAM, like sudo does, but I cant ask for password, it needs to be automatic. This unprivileged program in a specific time will have the access to root password.
Tried this example here https://www.netbsd.org/docs/guide/en/chap-pam.html but on pam_authenticate, it always return PAM_AUTH_ERR, I have tried all configured modules on my ubuntu 18.04.
#include <security/pam_appl.h>
#include <security/pam_misc.h>
#include <stdio.h>
#include <sys/wait.h>
#include <err.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <grp.h>
#include <assert.h>
#include <string>
#include <vector>
int converse(int n, const struct pam_message **msg, struct pam_response **resp, void *data)
{
struct pam_response *aresp;
char buf[PAM_MAX_RESP_SIZE];
int i;
data = data;
if (n <= 0 || n > PAM_MAX_NUM_MSG)
return (PAM_CONV_ERR);
if ((aresp = (struct pam_response *) calloc(n, sizeof *aresp)) == NULL)
return (PAM_BUF_ERR);
for (i = 0; i < n; ++i) {
aresp[i].resp_retcode = 0;
aresp[i].resp = NULL;
switch (msg[i]->msg_style) {
case PAM_PROMPT_ECHO_OFF:
//aresp[i].resp = strdup(getpass(msg[i]->msg));
aresp[i].resp = strdup("mypass");
aresp[i].resp_retcode = 0;
if (aresp[i].resp == NULL)
goto fail;
break;
case PAM_PROMPT_ECHO_ON:
fputs(msg[i]->msg, stderr);
if (fgets(buf, sizeof buf, stdin) == NULL)
goto fail;
aresp[i].resp = strdup(buf);
if (aresp[i].resp == NULL)
goto fail;
break;
case PAM_ERROR_MSG:
fputs(msg[i]->msg, stderr);
if (strlen(msg[i]->msg) > 0 &&
msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
fputc('\n', stderr);
break;
case PAM_TEXT_INFO:
fputs(msg[i]->msg, stdout);
if (strlen(msg[i]->msg) > 0 &&
msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n')
fputc('\n', stdout);
break;
default:
goto fail;
}
}
*resp = aresp;
return (PAM_SUCCESS);
fail:
for (i = 0; i < n; ++i) {
if (aresp[i].resp != NULL) {
memset(aresp[i].resp, 0, strlen(aresp[i].resp));
free(aresp[i].resp);
}
}
memset(aresp, 0, n * sizeof *aresp);
*resp = NULL;
return (PAM_CONV_ERR);
}
static struct pam_conv conv = {
converse,
//misc_conv,
NULL
};
extern char **environ;
static pam_handle_t *pamh;
static struct pam_conv pamc;
static void
usage(void)
{
fprintf(stderr, "Usage: su [login [args]]\n");
exit(1);
}
int
main(int argc, char *argv[])
{
char hostname[64];
const char *user, *tty;
char **args, **pam_envlist, **pam_env;
struct passwd *pwd;
int o, pam_err, status;
pid_t pid;
while ((o = getopt(argc, argv, "h")) != -1)
switch (o) {
case 'h':
default:
usage();
}
argc -= optind;
argv += optind;
if (argc > 0) {
user = *argv;
--argc;
++argv;
} else {
user = "root";
}
int pam_status = PAM_SUCCESS;
/* initialize PAM */
//pamc.conv = &openpam_ttyconv;
if ((pam_status = pam_start("passwd", user, &conv, &pamh)) != PAM_SUCCESS)
{
assert(false);
}
/* set some items */
gethostname(hostname, sizeof(hostname));
if ((pam_err = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS)
{
assert(false);
}
user = getlogin();
if ((pam_err = pam_set_item(pamh, PAM_RUSER, user)) != PAM_SUCCESS)
{
assert(false);
}
tty = ttyname(STDERR_FILENO);
if ((pam_err = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS)
{
assert(false);
}
/* authenticate the applicant */
pam_err = pam_authenticate(pamh, PAM_SILENT);
if (pam_err != PAM_SUCCESS)
{
printf("Pam Error (%d)\n", pam_err);
warn("pam_authenticate");
assert(false);
}
printf("AUTHENTICATED ;-)");
assert(false);
if ((pam_err = pam_acct_mgmt(pamh, 0)) == PAM_NEW_AUTHTOK_REQD)
pam_err = pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
if (pam_err != PAM_SUCCESS)
{
assert(false);
}
/* establish the requested credentials */
if ((pam_err = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS)
{
assert(false);
}
/* authentication succeeded; open a session */
if ((pam_err = pam_open_session(pamh, 0)) != PAM_SUCCESS)
{
assert(false);
}
/* get mapped user name; PAM may have changed it */
pam_err = pam_get_item(pamh, PAM_USER, (const void **)&user);
if (pam_err != PAM_SUCCESS || (pwd = getpwnam(user)) == NULL)
{
assert(false);
}
/* export PAM environment */
if ((pam_envlist = pam_getenvlist(pamh)) != NULL) {
for (pam_env = pam_envlist; *pam_env != NULL; ++pam_env) {
putenv(*pam_env);
free(*pam_env);
}
free(pam_envlist);
}
std::vector<std::string> arguments;
arguments.resize(argc + 2);
char * args_ptr [arguments.size()];
arguments[0] = pwd->pw_shell;
args_ptr[argc +1] = NULL;
args_ptr[0] = (char *)arguments[0].c_str();
for (int i = 0; i < argc; i++)
{
arguments[i + 1] = argv[i];
args_ptr[i+1] = (char *)arguments[i+1].c_str();
}
/* set uid and groups */
if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
warn("initgroups()");
_exit(1);
}
if (setgid(pwd->pw_gid) == -1) {
warn("setgid()");
_exit(1);
}
if (setuid(pwd->pw_uid) == -1) {
warn("setuid()");
_exit(1);
}
execve(args_ptr[0], args_ptr, environ);
warn("execve()");
_exit(1);
pamerr:
fprintf(stderr, "Sorry\n");
err:
pam_end(pamh, pam_err);
exit(1);
}
I expect to fork in a elevated child and run my new program, without asking for password.

Message Queue Callback

I'm trying to learn and understand what is message queue. I got the code here (I copied them from the internet and change them a little bit to relevant to my example). They are send.c which will allow you to enter some simple operations in text and send it to the message queue. The file receive.c will receive those operations, calculate it and print result to the screen.
What I want to do next (but I don't know how) is to make receive.c calculate operations and then it will send each result to each message from send.c. So please help me out, I'm kinda stuck :(
send.c:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct my_msgbuf {
long mtype;
char mtext[200];
};
int main() {
struct my_msgbuf buf;
int msqid;
key_t key;
if ((key = ftok("send.c", 'B')) == -1) {
perror("ftok");
exit(1);
}
if ((msqid = msgget(key, 0777 | IPC_CREAT)) == -1) {
perror("msgget");
exit(1);
}
printf("Enter lines of message, ^D to quit:\n");
buf.mtype = 1;
while(fgets(buf.mtext, sizeof buf.mtext, stdin) != NULL) {
int len = strlen(buf.mtext);
if (buf.mtext[len-1] == '\n') {
buf.mtext[len-1] = '\0';
}
if (msgsnd(msqid, &buf, len+1, 0) == -1) {
perror("msgsnd");
}
}
if (msgctl(msqid, IPC_RMID, NULL) == -1) {
perror("msgctl");
exit(1);
}
return 0;
}
receive.c:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
struct my_msgbuf {
long mtype;
char mtext[200];
};
int calculate(char mtext[200]) {
int result = 0;
char number_1[20];
char number_2[20];
char operator;
int pos = 0;
for (int i = 0; i < strlen(mtext); i++) {
if (mtext[i] == '+' || mtext[i] == '-' || mtext[i] == '*' || mtext[i] == '/') {
operator = mtext[i];
pos = i + 2;
break;
}
number_1[i] = mtext[i];
}
number_1[pos-3] = '\0';
for (int j = pos; j <= strlen(mtext); j++) {
number_2[j - pos] = mtext[j];
}
switch(operator) {
case '+':
result = atoi(number_1) + atoi(number_2);
break;
case '-':
result = atoi(number_1) - atoi(number_2);
break;
case '*':
result = atoi(number_1) * atoi(number_2);
break;
case '/':
result = atoi(number_1) / atoi(number_2);
break;
}
return result;
}
int main() {
struct my_msgbuf buf;
int msqid;
key_t key;
if ((key = ftok("send.c", 'B')) == -1) {
perror("ftok");
exit(1);
}
if ((msqid = msgget(key, 0777 | IPC_CREAT)) == -1) {
perror("msgget");
exit(1);
}
printf("Ready to receive messages...\n");
for(;;) {
if (msgrcv(msqid, &buf, sizeof buf.mtext, 0, 0) == -1) {
perror("msgrcv");
exit(1);
}
int result = calculate(buf.mtext);
printf("%s = %d\n", buf.mtext, result);
}
return 0;
}
When you run those file they will look like this:
As I understand, you need:
a request queue to let sender sends computation requests to receiver
an channel for each sender to let receiver sends its results to the requester.
For this, the sender has to create an appropriate channel (whatever you like, even a specific message queue if you want), and send within its request an id for the channel to answer on.
In real life that could correspond to a scenario like: you call a service at number N and give your request + "call me back at number M when finished please".

Issues with pthread in C

I have a problem with the compiling of my program, when I test something like "./philo -p 3 -e 4" I get the error
philo: tpp.c:62: __pthread_tpp_change_priority: Assertion `new_prio == -1 || (new_prio >= __sched_fifo_min_prio && new_prio <= __sched_fifo_max_prio)' failed.
Aborted
But I don't understand where it does come from, as it's working sometimes, for exemple if I test "./philo -p 2 -e 4" it doesn't crash.
The two .h
#ifndef _PHILO_H_
# define _PHILO_H_
#include <pthread.h>
typedef struct s_philosop
{
pthread_t philosophers;
pthread_mutex_t *chopsticks1;
pthread_mutex_t *chopsticks2;
int nbr_occ;
} t_philosop;
int parse_arg(char **argv, int *philo, int *occ);
int create_threads_mutex(int nbr_philo, int occurences);
void *start_routine(void *arg);
void philosoph_eating_chopsticks(t_philosop *philosop);
#endif /* !_PHILO_H_ */
#ifndef __LIBRICEFEREE_EXTERN__
# define __LIBRICEFEREE_EXTERN__
#include <pthread.h>
int RCFStartup(int ac, char **av);
void RCFCleanup();
int lphilo_eat();
int lphilo_sleep();
int lphilo_think();
int lphilo_take_chopstick(const pthread_mutex_t *mutex_id);
int lphilo_release_chopstick(const pthread_mutex_t *mutex_id);
#endif /* __LIBRICEFEREE_EXTERN__ */
And this is my .c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include "philo.h"
#include "extern.h"
void philosoph_comportement(t_philosop *philosop)
{
int i = 0;
if ((pthread_mutex_lock(philosop->chopsticks1)) == 0)
{
printf("%s\n", "Taking left stick");
lphilo_take_chopstick(philosop->chopsticks1);
i++;
}
if ((pthread_mutex_lock(philosop->chopsticks2)) == 0)
{
printf("%s\n", "Taking right stick");
lphilo_take_chopstick(philosop->chopsticks2);
i++;
}
if (i == 2)
{
printf("%s\n", "Eat");
lphilo_eat();
sleep(1);
printf("%s\n", "Sleep");
pthread_mutex_unlock(philosop->chopsticks1);
pthread_mutex_unlock(philosop->chopsticks2);
lphilo_release_chopstick(philosop->chopsticks1);
lphilo_release_chopstick(philosop->chopsticks2);
lphilo_sleep();
}
}
void *start_routine(void *arg)
{
t_philosop *philosop;
int i;
i = 0;
philosop = (t_philosop *)arg;
while (i != philosop->nbr_occ)
{
philosoph_comportement(philosop);
i++;
}
return (0);
}
int create_threads_mutex(int nbr_philo, int occurences)
{
int i;
t_philosop *philosop;
pthread_mutex_t *chopsticks;
i = -1;
if ((chopsticks = malloc(sizeof(pthread_mutex_t) * nbr_philo)) == NULL)
return (2);
if ((philosop = malloc(sizeof(t_philosop) * nbr_philo)) == NULL)
return (2);
while (++i != nbr_philo)
{
philosop[i].nbr_occ = occurences;
philosop[i].chopsticks1 = &chopsticks[i];
if (i - 1 < 0)
philosop[i].chopsticks2 = &chopsticks[nbr_philo];
else
philosop[i].chopsticks2 = &chopsticks[i - 1];
}
i = -1;
while (++i != nbr_philo)
pthread_create(&philosop[i].philosophers, NULL, start_routine, &philosop[i]);
i = -1;
while (++i != nbr_philo)
{
printf("Philo number : %d\n", i);
pthread_join(philosop[i].philosophers, NULL);
}
return (0);
}
int parse_arg(char **argv, int *philo, int *occ)
{
if (strcmp(argv[1], "-p") == 0 && strcmp(argv[3], "-e") == 0 &&
argv[2] != NULL && argv[4] != NULL)
{
*philo = atoi(argv[2]);
*occ = atoi(argv[4]);
}
else if (strcmp(argv[1], "-e") == 0 && strcmp(argv[3], "-p") == 0 &&
argv[2] != NULL && argv[4] != NULL)
{
*philo = atoi(argv[4]);
*occ = atoi(argv[2]);
}
else
return (2);
return (0);
}
int main(int argc, char **argv)
{
int philo;
int occurences;
philo = 0;
occurences = 0;
if (argc != 5)
return (2);
if ((parse_arg(argv, &philo, &occurences)) == 2)
return (2);
RCFStartup(argc, argv);
if ((create_threads_mutex(philo, occurences)) == 2)
return (2);
RCFCleanup();
return (0);
}
You don't initialize any of your mutexes with pthread_mutex_init.
And assuming lphilo_release_chopstick does nothing but unlock a mutex, this code is wrong as it will try to unlock each mutex twice:
pthread_mutex_unlock(philosop->chopsticks1);
pthread_mutex_unlock(philosop->chopsticks2);
lphilo_release_chopstick(philosop->chopsticks1);
lphilo_release_chopstick(philosop->chopsticks2);

Testing how semaphores work

I am trying to test the action of semaphores by calling them in my program with manual switches. I have the functions ready to go, but am failing to codinate them during the calling. I using UNIX system.
Please NOTE: the function defitions are fine, put them here for quick refence.The problem is with the caline below these function. I will be greatful for any assistance.
//----------------semmaphore.h ---------------------------------
#define SEM_NAME "semaphore.h",'a'
#define SEM_MAX 3
#define FREE 0
#define DATA 1
#define ROOM 2
#define S_WAIT -1
#define S_SIGNAL 1
#define NO_EVENT -1
int sem_config(int, int);
int sem_wait(int, int);
int sem_signal(int, int);
//----------------semmaphore.c ---------------------------------
#include <assert.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include "semaphore.h"
static int sem_id;
static union semun
{
int val; /* value for SETVAL */
struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */
ushort array[1];
} sem_attr;
static struct sembuf asem[1];
static key_t s_key;
int sem_config(int event, int init_val)
{
int x;
s_key = ftok(SEM_NAME);
if ( -1 == (sem_id = semget(s_key, SEM_MAX, 0666|IPC_CREAT ) ) {
perror("semget");
return -1;
}
if ( event == NO_EVENT )
return 0;
sem_attr.val = init_val;
if ( -1 == semctl(sem_id, event, SETVAL, sem_attr ) )
{
perror("semctl SETVAL");
return -1;
}
if ( -1 == ( x = semctl(sem_id, event, GETVAL, sem_attr ) ) )
{
perror("semctl GETVAL");
return -1;
}
assert( x == init_val );
return 0;
}
//------------------------------------------------------------
int sem_wait(int event, int nwaits)
{
asem[0].sem_num = event;
asem[0].sem_op = nwaits * S_WAIT;
asem[0].sem_flg = 0;
if ( event == NO_EVENT ) /*remove semaphore set*/
if ( -1 == semctl(sem_id, 0, IPC_RMID, sem_attr ) )
{
perror("semctl IPC_RMID");
return -1;
}
else
return 0;
if ( -1 == semop(sem_id, asem, 1 ) )
{
perror("semop");
return -1;
}
return 0;
}
//------------------------------------------------------------
int sem_signal(int event, int nsignals)
{
asem[0].sem_num = event;
asem[0].sem_op = nsignals * S_SIGNAL;
asem[0].sem_flg = 0;
if ( event == NO_EVENT )
if ( -1 == semctl(sem_id, 0, IPC_RMID, sem_attr ) )
{
perror("semctl IPC_RMID");
return -1;
}
else
return 0;
if ( -1 == semop(sem_id, asem, 1 ) )
{
perror("semop");
return -1;
}
return 0;
}
//========================PROBLEM STARTS HERE=================
#include <stdio.h>
#include "semaphore.h"
main()
{
char op, discard;
int event, nval;
do {
printf("Enter semaphore operation ");
printf("s(ignal)/w(ait)/i(nit)/f(ind)/c(leanup)");
scanf("%c%c", &op, &discard);
printf("Enter semaphore no and initial value :");
scanf("%d%d%c",&event,&nval,&discard);
switch ( op )
{
case 'i':
// Get semaphore for the forks
sem_config(event, nval);
printf("Initialized semaphore\n");
break;
case 'f':
break;
case 's':
sem_signal(event, 1)
break;
case 'w':
sem_wait(event, nval)
break;
case 'c':
break;
default:
if ( -1 == sem_wait(NO_EVENT, 0) )
{
printf("semctl IPC_RMID failed\n");
exit(1);
}
printf("done\n");
exit(0);
}
} while (1);
return 0;
}
Semaphores are for interprocess communication. So you need at least two processes. Testing them with only a single process is pointless :-)
Start your program twice and then type the appropriate commands (wait in #1, signal in #2, etc).

Resources