MINIX 3 - server print information - c

I am trying to modify the sched server and have been attempting to have it print out some information to stdout or stderr but without luck. I tried printf, fprintf, sprintf, puts, fputs. Any ideas on how I should do this? I am starting to think that for whatever reason it's not possible to have the server print something out even though it has printfs in it.
I tried adding these in schdule_process, start_scheduling and balance_queues.
#include <stdio.h>
static void balance_queues(minix_timer_t *tp)
{
struct schedproc *rmp;
int proc_nr;
printf("Test prinf\n");
fprintf(stdout, "Test fprintf stdout\n");
fprintf(stderr, "Test fprintf stderr\n");
puts("Test puts\n");
fputs("Test fputs stdout", stdout);
fputs("Test fputs stderr", stderr);
for (proc_nr=0, rmp=schedproc; proc_nr < NR_PROCS; proc_nr++, rmp++) {
if (rmp->flags & IN_USE) {
if (rmp->priority > rmp->max_priority) {
rmp->priority -= 1; /* increase priority */
schedule_process_local(rmp);
}
}
}
set_timer(&sched_timer, balance_timeout, balance_queues, 0);
}
Here's the balance_queues function I tried. I am pretty sure this is not a problem with my code instead something with minix which I don't yet understand. I've spend the last 2 hours reading and searching Tanenbaums and Woodhulls "The Minix book - Operating Systems, design and implementation" third edition but couldn't find anything. From what I understand this function should be called every 5 seconds to balance the queues but I there's nothing being printed to the command line!

Related

Why the printf( ) is working strangely after reopening stdout stream

After reopening STDOUT stream, the message does not display on my screen if calling print() like this:
printf("The message disappeared\n")
The snippet code for explaining the problem:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
int main(void)
{
printf("Display a message\n");
int fd, fd_copy, new_fd;
FILE *old_stream = stdout;
fd = STDOUT_FILENO;
fd_copy = dup(fd);
fclose(old_stream);
new_fd = dup2(fd_copy, fd);
close(fd_copy);
FILE *new_stream = fdopen(fd, "w");
stdout = new_stream;
printf("test %d\n", 1);
fprintf(stdout, "test 2\n");
int rc = printf("test 3\n");
printf("Test 4 Why the message disappeared\n");
printf("Error message is [%s]\n", strerror(errno));
return 0;
}
Why only the test 4 cannot display on my screen. Don't they all use stdout as output?
Output:
# gcc main.c; ./a.out
Display a message
test 1
test 2
test 3
Error message is [Bad file descriptor]
The code snippet above comes from the LVM2 library function.
int reopen_standard_stream(FILE **stream, const char *mode)
/* https://github.com/lvmteam/lvm2/blob/master/lib/log/log.c */
The dynamic library I designed:
I wrap up a dynamic library it includes the LVM dynamic library for other processes uses. One of the functions is this (output all PVs in the system):
char global_buffer[0x1000];
void show_pvs_clbk_fn(int level, const char *file, int line,
int dm_errno, const char *format)
{
/* Extract and process output here rather than printing it */
if (level != LVM2_LOG_PRINT)
return;
sprintf(global_buffer, "%s%s\n", global_buffer, format)
}
int show_all_PV(char *out_buffer)
{
void *handle = lvm2_init();
lvm2_log_fn(show_pvs_clbk_fn);
int rc = lvm2_run(handle, "pvs");
lvm2_exit(handle);
if (rc != LVM2_COMMAND_SUCCEEDED) {
return -1;
}
strcpy(out_buffer, global_buffer)
return 0;
}
A caller may calls show_all_PV() API like this:
int main(void)
{
char tmp[0x1000];
if (!show_all_PV(tmp)) {
printf("====== PVS are ======\n");
printf("%s\n", tmp);
}
}
Output:
====== PVS are ======
PV VG Fmt Attr PSize PFree
/dev/nvme1n1p1 vg1 lvm2 a-- <1.2t 1.1t
Some caller maybe mess up the stdout:
I found a stranger thing is that if the caller defines a function which includes vfprintf(stdout, ) system call. they never get output from normal print() API.
#inclide <stdlin.h>
#inclide <stdio.h>
#inclide <unistd.h>
#inclide <stdarg.h>
#if 1
int a_function_never_be_called(const char *formatP, ...)
{
va_list ap;
va_start(ap, formatP);
vfprintf(stdout, formatP, ap);
va_end(ap);
return 0;
}
#endif
int main(void)
{
char tmp[0x1000];
if (!show_all_PV(tmp)) {
printf("====== PVS are ======\n");
printf("%s\n", tmp);
}
}
The string "====== PVS are ======" disappeared and the caller got an IO error Bad file descripto.
Output:
PV VG Fmt Attr PSize PFree
/dev/nvme1n1p1 vg1 lvm2 a-- <1.2t 1.1t
Assigning to stdout (or stdin or stderr) is Undefined Behaviour. And in the face of undefined behaviour, odd things happen.
Technically, no more needs to be said. But after I wrote this answer, #zwol noted in a comment that the glibc documentation claims to allow reassignment of standard IO streams. In those terms, this behaviour is a bug. I accept this fact, but the OP was not predicated on the use of glibc, and there are many other standard library implementations which don't make this guarantee. In some of them, assigning to stdout will raise an error at compile time; in others, it will simply not work or not work consistently. In other words, regardless of glibc, assigning to stdout is Undefined Behaviour, and software which attempts to do so is, at best, unportable. (And, as we see, even on glibc it can lead to unpredictable output.)
But my curiosity was aroused so I investigated a bit. The first thing is to look at the actual code generated by gcc and see what library function is actually being called by each of those output calls:
printf("test %d\n", 1); /* Calls printf("test %d\n", 1); */
fprintf(stdout, "test 2\n"); /* Calls fwrite("test 2\n", 1, 7, stdout); */
int rc = printf("test 3\n"); /* Calls printf("test 3\n"); */
printf("Test 4 Why the message disappeared\n");
/* Calls puts("Test 4...disappeared"); */
printf("Error message is [%s]\n", strerror(errno));
/* Calls printf("..."); */
Note that GCC is trying hard to optimise the calls. In lines 2 and 4, it is able to find a non-printf library call, avoiding run-time parsing of the format string.
But note that it does not do that in the case of line 3, which looks the same as line 4. Why not? Because you are using the return value of printf, which is the number of characters sent to stdout. But that's not the same as the return value of puts, which just returns a "non-negative number" on success. So the substitution is impossible.
Suppose we remove int rc = from line 3, and recompile. Now we get this:
printf("test %d\n", 1); /* Calls printf("test %d\n", 1); */
fprintf(stdout, "test 2\n"); /* Calls fwrite("test 2\n", 1, 7, stdout); */
printf("test 3\n"); /* Calls puts("test 3"); */
printf("Test 4 Why the message disappeared\n");
/* Calls puts("Test 4...disappeared"); */
printf("Error message is [%s]\n", strerror(errno));
/* Calls printf("..."); */
So without the use of the return value, GCC can substitute printf with puts. (Note also that when it does that substitution, it also removes the \n from the string literal, because puts automatically adds a newline to the end of its output.)
When we run the modified program, we see this:
Display a message
test 1
test 2
Error message is [Bad file descriptor]
Now, two lines have disappeared, which are precisely the two lines for which GCC used puts.
After the shenanigans at the beginning, puts no longer works, presumably because it relies on stdout not having been reassigned. Which it's allowed to do, because reassigning stdout is Undefined Behaviour. (You can use freopen if you want to reopen stdout.)
Final note:
Unsurprisingly, it turns out that the glibc team did accept it as a bug; it was reported as bug 24051 and a similar issue with stdin as bug 24153. Both were fixed in glibc v2.30, released in August of 2019. So if you have a recently upgraded Linux install, or you are reading this answer years after I wrote it, you might not see this bug.

Streaming output to stdout, in-place status updates to stderr

I have a program that should produce output on stdout, and transient status information on stderr. Programs with similar results might include rsync or apt (though their output is sufficiently complex that reducing it to the essentials I need is daunting).
This program seems like it should work as described, but does not:
#include <stdio.h>
#include <limits.h>
void *work () {
for (long i = 0; i < LONG_MAX; i++) {
if (i % 100000000 == 0) {
fprintf(stdout, "%ld\n", i);
}
fprintf(stderr, "\rrunning %ld", i);
}
return 0;
}
int main() {
work(0);
fprintf(stderr, "\ndone\n");
return 0;
}
The status info is updated in place via stderr as desired, but only a single line of output appears via stdout. If the stderr status fprintf is removed, then all stdout output appears as expected.
What is going on here?
This code is correct (well, the void * return from work() is bad form--void would be far better).
I suspect that the problem is simply that you are not waiting long enough--it takes time to iterate through 100,000,000 iterations, especially with output each time through the loop (remember--you will be blocking on output once you fill the stdout buffer).
I estimate it will take a minimum of 3 minutes before you get the second output to stdout.

scanf() without displaying on screen

Is there any function in C on Linux that permit to wait an user input without displaying on terminal what he is typing ? (like when you enter your password on terminal on Linux)
I found getch() but it's not working on Linux ... :(
I found this but it's too complicated ... :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
int main(void)
{
char buffer[100];
struct termios infos;
int size;
if (tcgetattr(STDIN_FILENO, &infos) == -1)
{
fprintf(stderr, "Erreur tcgetattr.\n");
return (EXIT_FAILURE);
}
infos.c_lflag &= ~ECHO;
if (tcsetattr(STDIN_FILENO, TCSANOW, &infos) == -1)
{
fprintf(stderr, "Erreur tcsetattr.\n");
return (EXIT_FAILURE);
}
if ((size = read(STDIN_FILENO, buffer, sizeof(char) * 100)) == -1)
{
fprintf(stderr, "Erreur durant la lecture.\n");
return (EXIT_FAILURE);
}
buffer[size - 1] = '\0';
printf("le buffer contient [%s]\n", buffer);
return (EXIT_SUCCESS);
}
It's not scanf that is displaying the characters on screen, it's the terminal emulation which is echoing characters you type. You can disable that using the technique you suggested (or use a library to hide this), but no amount of fiddling with other functions to read STDIN is going to help.
The getpass function is not reliably present and has "obsolete, avoid" warnings in its manpage; however, it does essentially what you want. (I suspect it was obsoleted because it's not reentrant and doesn't allow the entry of an arbitrarily long password, which is kind of important nowadays.) The readpassphrase function is even less portable and has its own quirks (most of the flags should not be used, for instance) but does let you control how big the read buffer is. And gnulib has getpass-gnu, which adheres to the getpass calling convention but returns a malloced string rather than a pointer to static storage, thus fixing the major problems with the original getpass.
In a serious program I would probably start with the gnulib getpass, rename the function (to avoid potential conflicts with libc) and then hack out some of the more dubious features (like reading from stdin if /dev/tty is unavailable - the Right Thing there is to fail hard, but provide some other way of getting a passphrase into the program for scripting use). Or, if feasible, I would build the program around SSH keys rather than passwords.

popen() with sleep() call does not work

I have tested the below code to sort the strings.
Reason i added sleep to check, if sort program will wait on its read pipe for the information to sort. Below program works without sleep() call, why?
#include <stdio.h>
#define MAXSTRS 5
int main(void)
{
int cntr;
FILE *pipe_fp;
char *strings[MAXSTRS] = { "echo", "bravo", "alpha",
"charlie", "delta"};
/* Create one way pipe line with call to popen() */
if (( pipe_fp = popen("sort", "w")) == NULL)
{
perror("popen");
exit(1);
}
//printf("sleeping\n");
//sleep(10);
/* Processing loop */
for(cntr=0; cntr<MAXSTRS; cntr++) {
fputs(strings[cntr], pipe_fp);
fputc('\n', pipe_fp);
}
/* Close the pipe */
pclose(pipe_fp);
return(0);
}
You probably are just running in a limitation of the site you are using to test your code. With smaller values for the sleep() (e. g. 1) this works just fine. I guess that the test site is applying timeouts to the programs it compiles and runs in order to have a decently reactive web site.
Get a decent unix and try it there; you probably will have as little trouble executing it as I did.

C code runs in Eclipse-Kepler but fails to run in Codeblocks IDE

I am a newbie at C programming and new on Stackoverflow as well.
I have some c code that compiles and runs in Eclipse Kepler (Java EE IDE); I installed the C/C++ plugin and Cygwin Gcc compiler for c.
Everything runs ok in Eclipse IDE; however, when my friend tries to run the same code on his Codeblocks IDE, he doesn't get any output. At some point, he got some segmentation error, which we later learned was due to our program accessing memory space that didn't belong to our program.
Codeblocks IDE is using Gcc compiler not cygwin gcc, but I don't think they're that different to cause this sort of problem.
I am aware that C is extremely primitive and non-standardized, but why would my code run in eclipse with cygwin-gcc compiler but not run in Codeblocks IDE with gcc compiler?
Please help, it's important for our class project.
Thanks to all.
[EDIT] Our code is a little large to paste in here but here's a sample code of what would RUN SUCCESSFULLY in eclipse but FAIL in codeblocks, try it yourself if you have codeblocks please:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
int main(void) {
char *traceEntry1;
FILE *ifp;
traceEntry1 = malloc(200*sizeof(char));
ifp = fopen("./program.txt", "r");
while (fgets(traceEntry1, 75, ifp))
printf("String input is %s \n", traceEntry1);
fclose(ifp);
}
It simply doesn't give any outputs in codeblocks, sometimes just results in a segmentation fault error.
I have no idea what the problem is.
We need your help please, thanks in advance.
Always and ever test the results of all (revelant) calls. "relevant" at least are those call which return results which are unusable if the call failed.
In the case of the OP's code they are:
malloc()
fopen()
fclose()
A save version of the OP's code could look like this:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int result = EXIT_SUCCESS; /* Be optimistic. */
char * traceEntry1 = NULL; /* Always initialise your variables, you might remove this during the optimisation phase later (if ever) */
FILE * ifp = NULL; /* Always initialise your variables, you might remove this during the optimisation phase later (if ever) */
traceEntry1 = malloc(200 * sizeof(*traceEntry1)); /* sizeof(char) is always 1.
Using the dereferenced target (traceEntry1) on the other hand makes this
line of code robust against modifications of the target's type declaration. */
if (NULL == traceEntry1)
{
perror("malloc() failed"); /* Log error. Never ignore useful and even free informaton. */
result = EXIT_FAILURE; /* Flag error and ... */
goto lblExit; /* ... leave via the one and only exit point. */
}
ifp = fopen("./program.txt", "r");
if (NULL == ifp)
{
perror("fopen() failed"); /* Log error. Never ignore useful and even free informaton. */
result = EXIT_FAILURE; /* Flag error ... */
goto lblExit; /* ... and leave via the one and only exit point. */
}
while (fgets(traceEntry1, 75, ifp)) /* Why 75? Why not 200 * sizeof(*traceEntry1)
as that's what was allocated to traceEntr1? */
{
printf("String input is %s \n", traceEntry1);
}
if (EOF == fclose(ifp))
{
perror("fclose() failed");
/* Be tolerant as no poisened results are returned. So do not flag error. It's logged however. */
}
lblExit: /* Only have one exit point. So there is no need to code the clean-up twice. */
free(traceEntry1); /* Always clean up, free what you allocated. */
return result; /* Return the outcome of this exercise. */
}

Resources