linux terminal output - linux

Hi I wrote a simple c prog to just accept a password while diplaying * to hide the input. But the * for the last character entered is not appearing at the right place.
the code is below
int main(){
int choice = 0;
char pass[8];
FILE *input;
FILE *output;
struct termios initial_settings, new_settings;
if(!isatty(fileno(stdout))){
fprintf(stderr,"Not a terminal \n");
}
input = fopen("/dev/tty","r");
output = fopen("/dev/tty","w");
if(!input || !output){
fprintf(stderr,"error opening");
exit(1);
}
tcgetattr(fileno(input),&initial_settings);
new_settings = initial_settings;
new_settings.c_lflag &= ~ICANON;
new_settings.c_lflag &= ~ECHO;
new_settings.c_cc[VMIN] = 1;
new_settings.c_cc[VTIME] = 0;
new_settings.c_lflag &= ~ISIG;
if(tcsetattr(fileno(input), TCSANOW, &new_settings) != 0) {
fprintf(stderr,"could not set attributes\n");
}
int count = 0;
char ch;
printf("Please enter the password: ");
while (count<8){
ch = fgetc(input);
if(ch == '\n' || ch == '\r'){
break;
}else{
fputc('*',stdout);
pass[count] = ch;
count++;
}
tcdrain(fileno(stdout));
}
fprintf(output,"you have entered :%s \n",pass);
tcsetattr(fileno(input),TCSANOW,&initial_settings);
exit(0);
}
The output is as follows:
Please enter the password:* * * * * * *
you have entered :12345678
* pasman#pasman-laptop:~$
Its an 8 character password & Notice that 7 *s appear as expected but the last * is appearing at the end of main.

You're mixing stdio and another stream, output, talking directly to the tty. They have different buffers, and get flushed at different times. You really should just use one of them.

It's because you break before you write the last *: so
add
fputc('*',stdout);
before
tcdrain(fileno(stdout));

Related

How do I use escapeshellarg() on Windows but "aimed for Linux" (and vice versa)?

If PHP is running on Windows, escapeshellarg() escapes file names (for example) in a certain way and then adds " (DOUBLE) quotes around it.
If PHP is running on Linux, escapeshellarg() uses Linux-based escaping and then adds ' (SINGLE) quotes around it.
In my situation, I'm generating a SHA256SUMS file on Windows, but aimed for Linux. Since I use escapeshellarg() to escape the file name, I end up with a file like:
cabcdccas12exdqdqadanacvdkjsc123ccfcfq3rdwcndwf2qefcf "cool filename with spaces.zip"
However, Linux tools probably expect:
cabcdccas12exdqdqadanacvdkjsc123ccfcfq3rdwcndwf2qefcf 'cool filename with spaces.zip'
Looking in the manual, there seems to be no way to do something like: escapeshellarg($blabla, TARGET_OS_LINUX); in order for it to use the rules for Linux instead of the OS running the script (Windows).
I can't just str_replace the quotes because it would not take into consideration all the platform-specific rules.
Also, yes, I need spaces in the file name (and any other cross-platform-valid character).
I sadly found no mention whatsoever about the preferred quote style on the only source of information I have for this: https://help.ubuntu.com/community/HowToSHA256SUM
Maybe the SHA256 security verification tools which read that SHA256SUMS file understand and can parse both kinds?
The behavior of escapeshellarg() is hard-coded depending on whether PHP is running on Windows or any other operating system. You should reimplement escapeshellarg() for consistent behavior.
Here is my attempt at reimplementing escapeshellarg() with a Windows/other-OS toggle in PHP:
<?php namespace polyfill;
const TARGET_OS_WINDOWS = 1;
const TARGET_OS_UNIX = 2;
function escapeshellarg(string $input, int $os_mode = 0): string
{
if (false !== strpos($input, "\x00"))
{
throw new \UnexpectedValueException(__FUNCTION__ . '(): Argument #1 ($input) must not contain any null bytes');
}
if ($os_mode == 0)
{
$os_mode = TARGET_OS_UNIX;
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')
$os_mode = TARGET_OS_WINDOWS;
}
$maxlen = 4096;
if ($os_mode === TARGET_OS_WINDOWS) $maxlen = 8192;
if (strlen($input) > $maxlen - 2) return "";
if ($os_mode === TARGET_OS_WINDOWS)
{
$output =
str_replace(['"', '%', '!'],
[' ', ' ', ' '],
$input);
# https://bugs.php.net/bug.php?id=69646
if (substr($output, -1) === "\\")
{
$k = 0; $n = strlen($output) - 1;
for (; $n >= 0 && substr($output, $n, 1) === "\\"; $n--, $k++);
if ($k % 2) $output .= "\\";
}
$output = "\"$output\"";
}
else
{
$output = str_replace("'", "'\''", $input);
$output = "'$output'";
}
if (strlen($output) > $maxlen) return "";
return $output;
}
It should be almost functionally equivalent to the native PHP escapeshellarg(), except that:
it takes a second argument that sets whether you want the output in Windows mode or not Windows mode,
it raises an \UnexpectedValueException instead of some kind of PHP error if the input string contains null bytes,
it doesn't emit errors due to the input being too long, and
it has 4096 hard-coded as the maximum argument length on Unix-like platforms.
To use this replacement function:
# In Unix/Linux/macOS mode
\polyfill\escapeshellarg($blabla, \polyfill\TARGET_OS_UNIX);
# In Windows mode
\polyfill\escapeshellarg($blabla, \polyfill\TARGET_OS_WINDOWS);
# In auto-detect (running OS) mode
\polyfill\escapeshellarg($blabla);
Reference
Here is the full C implementation from PHP 7.3.10 (./ext/standard/exec.c):
PHPAPI zend_string *php_escape_shell_arg(char *str)
{
size_t x, y = 0;
size_t l = strlen(str);
zend_string *cmd;
uint64_t estimate = (4 * (uint64_t)l) + 3;
/* max command line length - two single quotes - \0 byte length */
if (l > cmd_max_len - 2 - 1) {
php_error_docref(NULL, E_ERROR, "Argument exceeds the allowed length of %zu bytes", cmd_max_len);
return ZSTR_EMPTY_ALLOC();
}
cmd = zend_string_safe_alloc(4, l, 2, 0); /* worst case */
#ifdef PHP_WIN32
ZSTR_VAL(cmd)[y++] = '"';
#else
ZSTR_VAL(cmd)[y++] = '\'';
#endif
for (x = 0; x < l; x++) {
int mb_len = php_mblen(str + x, (l - x));
/* skip non-valid multibyte characters */
if (mb_len < 0) {
continue;
} else if (mb_len > 1) {
memcpy(ZSTR_VAL(cmd) + y, str + x, mb_len);
y += mb_len;
x += mb_len - 1;
continue;
}
switch (str[x]) {
#ifdef PHP_WIN32
case '"':
case '%':
case '!':
ZSTR_VAL(cmd)[y++] = ' ';
break;
#else
case '\'':
ZSTR_VAL(cmd)[y++] = '\'';
ZSTR_VAL(cmd)[y++] = '\\';
ZSTR_VAL(cmd)[y++] = '\'';
#endif
/* fall-through */
default:
ZSTR_VAL(cmd)[y++] = str[x];
}
}
#ifdef PHP_WIN32
if (y > 0 && '\\' == ZSTR_VAL(cmd)[y - 1]) {
int k = 0, n = y - 1;
for (; n >= 0 && '\\' == ZSTR_VAL(cmd)[n]; n--, k++);
if (k % 2) {
ZSTR_VAL(cmd)[y++] = '\\';
}
}
ZSTR_VAL(cmd)[y++] = '"';
#else
ZSTR_VAL(cmd)[y++] = '\'';
#endif
ZSTR_VAL(cmd)[y] = '\0';
if (y > cmd_max_len + 1) {
php_error_docref(NULL, E_ERROR, "Escaped argument exceeds the allowed length of %zu bytes", cmd_max_len);
zend_string_release_ex(cmd, 0);
return ZSTR_EMPTY_ALLOC();
}
if ((estimate - y) > 4096) {
/* realloc if the estimate was way overill
* Arbitrary cutoff point of 4096 */
cmd = zend_string_truncate(cmd, y, 0);
}
ZSTR_LEN(cmd) = y;
return cmd;
}
// … [truncated] …
/* {{{ proto string escapeshellarg(string arg)
Quote and escape an argument for use in a shell command */
PHP_FUNCTION(escapeshellarg)
{
char *argument;
size_t argument_len;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STRING(argument, argument_len)
ZEND_PARSE_PARAMETERS_END();
if (argument) {
if (argument_len != strlen(argument)) {
php_error_docref(NULL, E_ERROR, "Input string contains NULL bytes");
return;
}
RETVAL_STR(php_escape_shell_arg(argument));
}
}
/* }}} */
The logic is fairly simple. Here are some equivalent functional test cases in prose:
The input string cannot contain NUL characters.
Applied to the input string,
in Windows mode,
Prepend a " character.
Replace all ", %, and ! characters with .
If the end consists of an odd number of \ characters, add one \ character to the end. (Bug #69646)
Append a " character.
in other platforms mode,
Prepend a ' character.
Replace all ' characters with '\''
Append a ' character.
On Windows, if the output is longer than 8192 characters, emit an E_ERROR and return an empty string.
On other platforms, if the output is longer than 4096 characters (or whatever the overridden maximum is at compile time), emit an E_ERROR and return an empty string.

How to return a int converted to char array back to main for displaying it

My doubts are as follows :
1 : how to send 'str' from function 'fun' , So that i can display it in main function.
2 : And is the return type correct in the code ?
2 : the current code is displaying some different output.
char * fun(int *arr)
{
char *str[5];
int i;
for(i=0;i<5;i++)
{
char c[sizeof(int)] ;
sprintf(c,"%d",arr[i]);
str[i] = malloc(sizeof(c));
strcpy(str[i],c);
}
return str;
}
int main()
{
int arr[] = {2,1,3,4,5},i;
char *str = fun(arr);
for(i=0;i<5;i++)
{
printf("%c",str[i]);
}
return 0;
}
how to send 'str' from function 'fun' , So that i can display it in main function.
This is the way:
char* str = malloc( size );
if( str == NULL ) {
fprintf( stderr,"Failed to malloc\n");
}
/* Do stuff with str, use str[index],
* remember to free it in main*/
free(str);
And is the return type correct in the code ?
No, Probably char** is the one you need to return.
the current code is displaying some different output.
Consider explaining what/why do you want to do ? The way you have written, seems completely messed up way to me. You're passing array of integer but not its length. How is the fun() supposed to know length of array? Another problem is array of pointers in fun().
You can't write a int to a char (See the both size). So I used char array instead.
However, I'm not sure if this is what you want to do (might be a quick and dirty way of doing it):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char**
fun(int *arr, int size)
{
char **str = malloc( sizeof(char*)*size );
if( str == NULL ) {
fprintf( stderr, "Failed malloc\n");
}
int i;
for(i=0;i<5;i++) {
str[i] = malloc(sizeof(int));
if( str == NULL ) {
fprintf( stderr, "Failed malloc\n");
}
sprintf(str[i],"%d",arr[i]);
}
return str;
}
int
main()
{
int arr[] = {2,1,3,4,5},i;
char **str = fun(arr, 5);
for(i=0;i<5;i++) {
printf("%s\n",str[i]);
free(str[i]);
}
free(str);
return 0;
}
I made these changes to your code to get it working:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **fun(int *arr)
{
char **str = malloc(sizeof(char *) * 5);
int i;
for(i = 0; i < 5; i++) {
if ((arr[i] >= 0) && (arr[i] <= 9)) {
char c[2] ;
sprintf(c, "%d", arr[i]);
str[i] = (char *) malloc(strlen(c) + 1);
strcpy(str[i],c);
}
}
return str;
}
int main()
{
int arr[] = {2, 1, 3, 4, 5}, i;
char **str = fun(arr);
for(i = 0; i < 5; i++) {
printf("%s", str[i]);
free(str[i]);
}
printf("\n");
free(str);
return 0;
}
Output
21345
I added a check to make sure that arr[i] is a single digit number. Also, returning a pointer to a stack variable will result in undefined behavior, so I changed the code to allocate an array of strings. I don't check the return value of the malloc calls, which means this program could crash due to a NULL pointer reference.
This solution differs from the others in that it attempts to answer your question based on the intended use.
how to send 'str' from function 'fun' , So that i can display it in main function.
First, you need to define a function that returns a pointer to array.
char (*fun(int arr[]))[]
Allocating variable length strings doesn't buy you anything. The longest string you'll need for 64bit unsigned int is 20 digits. All you need is to allocate an array of 5 elements of 2 characters long each. You may adjust the length to suit your need. This sample assumes 1 digit and 1 null character. Note the allocation is done only once. You may choose to use the length of 21 (20 digits and 1 null).
For readability on which values here are related to the number of digits including the terminator, I'll define a macro that you can modify to suit your needs.
#define NUM_OF_DIGITS 3
You can then use this macro in the whole code.
char (*str)[NUM_OF_DIGITS] = malloc(5 * NUM_OF_DIGITS);
Finally the receiving variable in main() can be declared and assigned the returned array.
char (*str)[NUM_OF_DIGITS] = fun(arr);
Your complete code should look like this:
Code
char (*fun(int arr[]))[]
{
char (*str)[NUM_OF_DIGITS] = malloc(5 * NUM_OF_DIGITS);
int i;
for(i=0;i<5;i++)
{
snprintf(str[i],NUM_OF_DIGITS,"%d",arr[i]); //control and limit to single digit + null
}
return str;
}
int main()
{
int arr[] = {24,1,33,4,5},i;
char (*str)[NUM_OF_DIGITS] = fun(arr);
for(i=0;i<5;i++)
{
printf("%s",str[i]);
}
free(str);
return 0;
}
Output
2413345
With this method you only need to free the allocated memory once.

Error trying to compile Linux Source Code

I'm not very good into coding/programming but I'm trying to compile Linux Source.
Following errormessage shows up:
error: invalid conversion from ‘const char*’ to ‘char*’ [-fpermissive]
char *ptr = strchr( in, ch );
While "googling" around I could't find a helpfull answer.
I guess this is the part where it fails:
//////////////////////////////////////////////////////////////////////////
/// Parses an IP address string
///
/// #param[out] out array containing the IP address in raw 4-byte format
/// #param in string containing an IP address in 'nnn.nnn.nnn.nnn'
/// notation
//////////////////////////////////////////////////////////////////////////
int parseIP( uint8_t *out, const char *in )
{
in_addr addr, haddr;
int c = 0;
int ch = '.';
char *ptr = strchr( in, ch );
while( ptr ) {
++c;
ptr = strchr( ptr + 1, ch );
}
if( c != 3 )
return -EINVAL;
if( inet_aton( in, &addr ) == 0 )
return -EINVAL;
haddr.s_addr = ntohl( addr.s_addr );
for( int i = 0; i < 4; ++i )
out[ i ] = ((uint8_t *)&haddr.s_addr)[ 3 - i ];
return 0;
}
Hopefully anyone can help.
Regards,
Mark
Hi David,
I've found the part were it's been called and tried to change it, but still same errormessage while using th 'make' command.
case 'i':
if( getuid() != 0 ) {
std::cerr << "Error: you need to have "
"root privileges in "
"order to use the "
"-i/--ipaddr option"
<< std::endl;
exit( 1 );
}
if( strncmp( optarg, "dhcp", 4 ) == 0 &&
strlen( optarg ) == 4 )
opt_devip_dhcp = 1;
else if( parseIP( opt_devip, (char *)optarg ) ) {
std::cerr << "Error: bad IP address" <<
std::endl;
exit( 3 );
}
opt_devip_set = 1;
break;
case 'm':
if( parseIP( opt_devmask, (char *)optarg ) ) {
std::cerr << "Error: bad network mask" <<
std::endl;
exit( 7 );
}
opt_devmask_set = 1;
break;
int parseIP( uint8_t *out, const char *in )
You need to find where parseIP is called in your main program. See above how the second argument is const char *in. You summize correctly that is probably where the error is generated. If you check in your main program where parseIP is called, you will probably find your program passing it a char * argument instead of const char *. You can correct this in the code by casting the value passed to parseIP to (char *) Example: if you find this:
somevar = parseIP( outvar, stringin )
Cast the second argument to (char *):
somevar = parseIP( outvar, (char *)stringin )
Or you can probably just cheat with the compiler. It is giving you a hint on how to do it. Notice the [-fpermissive] as part of the warning. You can more than likely just pass the -fpermissive flag to the compiler and have it work. If you were compiling with:
gcc -Wall -o outfile yourfile.cpp
Try it with:
gcc -Wall -o outfile yourfile.cpp -fpermissive
Now, all the legal qualifications and disclaimers apply, you are better fixing the reason you are getting that warning/error as set forth above, but you can also just pass -fpermissive as a temporary workaround most of the time.

How can I safely and simply read a line of text from a file or stdin?

Given that fgets only sometimes includes a linebreak, and fscanf is inherently unsafe, I would like a simple alternative to read text line-by-line from a file. Is this page a good place to find such a function?
Yes. The following function should satisfy this requirement without creating any damaging security flaws.
/* reads from [stream] into [buffer] until terminated by
* \r, \n or EOF, or [lastnullindex] is reached. Returns
* the number of characters read excluding the terminating
* character. [lastnullindex] refers to the uppermost index
* of the [buffer] array. If an error occurs or non-text
* characters (below space ' ' or above tilde '~') are
* detected, the buffer will be emptied and 0 returned.
*/
int readline(FILE *stream, char *buffer, int lastnullindex) {
if (!stream) return 0;
if (!buffer) return 0;
if (lastnullindex < 0) return 0;
int inch = EOF;
int chi = 0;
while (chi < lastnullindex) {
inch = fgetc(stream);
if (inch == EOF || inch == '\n' || inch == '\r') {
buffer[chi] = '\0';
break;
} else if (inch >= ' ' && inch <= '~') {
buffer[chi] = (char)inch;
chi++;
} else {
buffer[0] = '\0';
return 0;
}
}
if (chi < 0 || chi > lastnullindex) {
buffer[0] = '\0';
return 0;
} else {
buffer[chi] = '\0';
return chi;
}
}

Broken pipes in C -- pipe(), fork(), exec() program

I need to write a simple program: There will be a Parent and a few programs [children] (started via execl in Parent). Children communicate to one another in this way: Child I sens to Parent number J, Parent sends a message (something like -- "there is a message to you") to J, J send to Parent number K etc. etc.
And there is a problem -- my program (tested by strace command) tries to send a message to child and there comes the broken pipe error.
I will be grateful if somebody looks through the code and tells me what's wrong:
Here is the code:
/**
* Arbiter zabawy w Losia
*
wersja: Alfa 3b
początek edycji 25.01.2009
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "err.h"
pid_t pid;
FILE *a;
int main ()
{
// my N players
int N;
N = 10;
//write -- writing from parent to child
//read -- reading from child
int rurka_write[N+1][2];
int rurka_read[N+1][2];
//initiation of N players
int i;
for(i = 1; i <= N; i++)
{
//tworze lacza
if (pipe(rurka_write[i]) == -1)
printf("wystapil blad przy rurce %d\n", i);
if (pipe(rurka_read[i]) == -1)
printf("wystapil blad przy rurce %d\n", i);
}
for(i = 1; i <= N; i++)
{
switch(pid = fork())
{
case -1:
printf("wystapil blad przy forkowaniu");
case 0:
printf("potomek numer %d\n", i);
if (close(rurka_write[i][1]) == -1)
printf("zle zamykanie");
if (close(rurka_read[i][0]) == -1)
printf("zle zamykanie");
//closing useless descriptors
int j;
for(j = 1; j <= N; j++)
{
if (j != i)
{
close(rurka_read[j][0]);
close(rurka_read[j][1]);
close(rurka_write[j][0]);
close(rurka_write[j][1]);
}
}
char str_N[20];
char str_i[20];
char str_0[20];
char str_1[20];
sprintf(str_N, "%d", N);
sprintf(str_i, "%d", i);
sprintf(str_0, "%d", rurka_write[i][0]);
sprintf(str_1, "%d", rurka_read[i][1]);
printf("%d Executing execl\n", i);
execl("./ucz", str_N, str_i, str_0, str_1, NULL);
printf("execl executed\n");
// execv("./ucz", str_N, str_i, str_0, str_1, NULL);
//exit(0);
default:
//closing useless pipes
if (close(rurka_read[i][1]) == -1)
printf("zle zamykanie rurki do czytania z potomkna\n");
if (close(rurka_write[i][0]) == -1)
printf("zle zamykanie rurki do pisania do potomka\n");
} //end of switch
} //end of for
//if I am in parent, I'm starting the game
if (pid != 0)
// delay(100);
{
printf("PLAY\n");
int l = 1;
while(l > 0)
{
printf("sending to player %d\n", l);
a = fdopen(rurka_write[l][1], "w");
printf("sending: Wake up");
fprintf(a, "Wake up\n");
printf("flushing");
fflush(a);
char k[20];
printf("reading");
read(rurka_read[l][0], k, 20);
l = k;
}
}
}
Besides the fact that you do not end your cases with a break (as noted by strager), the main problem is the statement l = k;. Note that k is a char[20] and, when assigned to a int, you don't assign any of the contents of k to l. Instead l will contain (the value of) the pointer to the array. You will have to do something different here to get the value that is in the array; what exactly depends on that ucz sends back.
After fixing this and making my own ucz, the program seems to work without any problem. Of course, it might also be that there is another problem in your version of ucz.
About ./ucz -- it takes 4 parameters -- 1st -- number of players, 2nd -- player number, 3rd -- number of descriptor to read from parent, 4th -- number of descriptor to write to parent.
Adding exit(0), return(0), break after exec (or in the end of "case: 0") doesn't help.

Resources