gzread fails after successful gzdopen on mswin32 - zlib

There seems to be something broken in the windows build for zlib 1.2.8. According to USAGE.txt in http://zlib.net/zlib128-dll.zip (from zlib.net) and the man pages for gzread and gzdopen, the code should work. Can anyone enlighten me, please? BTW, I have tested this code on darwin (using zlib 1.2.5) and linux (using zlib 1.2.1) where gzdopen works.
Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include "zlib.h"
int main(int argc, char *argv[]) {
char buffer[500];
int len;
gzFile gin;
const char *errmsg;
int errnum;
char *fun = argv[1];
char *filename = argv[2];
printf("fun: %s filename: %s\n", fun, filename);
printf("zlib version: %s\n", zlibVersion());
if (!strcmp(fun, "gzdopen")) {
int fd = open(filename, O_RDONLY);
printf("open returned %d\n", fd);
gin = gzdopen(fd, "rb");
}
if (!strcmp(fun, "gzopen"))
gin = gzopen(filename, "rb");
printf("gzopen returned %p\n", gin);
len = gzread(gin, buffer, sizeof(buffer));
fprintf(stderr, "gzread() returned %d\n", len);
errmsg = gzerror(gin, &errnum);
fprintf(stderr, "gzerror() returned '%s'; errnum=%d\n", errmsg, errnum);
return 0;
}
And here's what I did:
C:\decompress> cl test.c /Iinclude lib/zdll.lib
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.
test.c
Microsoft (R) Incremental Linker Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
C:\decompress> gzip -c < test.c > test.c.gz
C:\decompress>test gzdopen test.c.gz
fun: gzdopen filename: test.c.gz
zlib version: 1.2.8
open returned 3
gzopen returned 00332CE0
gzread() returned -1
gzerror() returned '<fd:3>: Bad file descriptor'; errnum=-1
C:\decompress>test gzopen test.c.gz
fun: gzopen filename: test.c.gz
zlib version: 1.2.8
gzopen returned 00332CC0
gzread() returned 500
gzerror() returned ''; errnum=0

Related

Bluetooth C program cannot find library -lbluetooth

I am using this tutorial to learn how to use bluetooth in c on my raspberry pi:
https://people.csail.mit.edu/albert/bluez-intro/c404.html
I am currently trying to get running simplescan.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
int main(int argc, char **argv)
{
inquiry_info *ii = NULL;
int max_rsp, num_rsp;
int dev_id, sock, len, flags;
int i;
char addr[19] = { 0 };
char name[248] = { 0 };
dev_id = hci_get_route(NULL);
sock = hci_open_dev( dev_id );
if (dev_id < 0 || sock < 0) {
perror("opening socket");
exit(1);
}
len = 8;
max_rsp = 255;
flags = IREQ_CACHE_FLUSH;
ii = (inquiry_info*)malloc(max_rsp * sizeof(inquiry_info));
num_rsp = hci_inquiry(dev_id, len, max_rsp, NULL, &ii, flags);
if( num_rsp < 0 ) perror("hci_inquiry");
for (i = 0; i < num_rsp; i++) {
ba2str(&(ii+i)->bdaddr, addr);
memset(name, 0, sizeof(name));
if (hci_read_remote_name(sock, &(ii+i)->bdaddr, sizeof(name),
name, 0) < 0)
strcpy(name, "[unknown]");
printf("%s %s\n", addr, name);
}
free( ii );
close( sock );
return 0;
}
When I compile using this command:
gcc -o simplescan simplescan.c -lbluetooth
I get this error:
/usr/bin/ld: cannot find -lbluetooth
collect2: error: ld returned 1 exit status
EDIT: For some reason now when I try to compile the error has changed to this:
simplescan.c:5:10: fatal error: bluetooth/bluetooth.h: No such file or directory
#include <bluetooth/bluetooth.h>
I have read that BlueZ comes pre-installed on Raspbian, and I have the newest version, but I can't seem to find the bluetooth library folder or any of the .h files in it.
This tutorial might be old so things might have moved around.
Does the bluetooth library come preinstalled along with bluez? If so, where should I look to confirm?
If this library is not on my RPI where should I get it from?
That tutorial is out of date as BlueZ has moved on since then. Back in 2012 there was major development to move to new APIs
Then in 2017 8 tools were deprecated from Bluez.
The API's to use now are the mgmt API which focused on system level functionality and is documented at: https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/mgmt-api.txt
For application level, it is the D-Bus API's that you should be using. These are spread across a number of documents in: https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc
There are not many C examples around. The examples in the source tree are for the D-Bus API and all use Python: https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/test
Looking at the code for the bluetoothctl tool might give you better examples. This code is available at: https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/client

Printing to stdout returning gibbersih

I am using gcc 10.1.1 on Fedora 32.
The following program is to read from a file given by the user and print it into stdout. The code is an example in Modern C by Jens Gusdets.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
enum { buf_max = 32,};
int main(int argc, char* argv[argc +1]){
int ret = EXIT_FAILURE;
char buffer[buf_max] = {0};
for(int i = 0; i<argc ; ++i){
FILE* instream = fopen(argv[i] , "r");
if(instream){
while(fgets(buffer , buf_max , instream)){
fputs(buffer, stdout);
}
fclose(instream);
ret = EXIT_SUCCESS;
} else{
fprintf(stderr, "Could not open %s: ", argv[i]);
perror(0);
errno = 0;
}
}
return ret;
}
But when I run the program it is printing some gibberish like :
$ ./read some.txt
ELFDib64/ld-linux-x86-64.so.2Co.6locationderrGLIBC_2.2.5###/��^H��H���PTI��##H=X##�H��H�H��t�f.��z������UH��H��#�}�H�u��E����`..��������ATA��UH�-T+t1��u�H�[]A\A]A^A_�ff.������A�C
G#n8A0A(B BB���oGCC: (GNU) 10.1.1 20200507 (Red Hat 10.1.1-1)�#�#�#�#�#�#�#�#1�# gcc 10.1.1 2020050730k_clashectionYSSERTIONSGA!stack_realign�# gcc 10.1.1 2020050730k_cl#Z�##nux/10/../../../../lib64/crt1.oc_endbin_init.c_end.hott.c.unlikelyd.unlikelytupinit.c_end.exit_reloc.cc_endothotikelynd.unlikelyoc.c.startuploc.c_end.startupic_reloc.c.exit_reloc.c_end.exitrelocate_static_pie.startbin__dl_relocate_static_pie.endsed.0_array_entrye_dummy_init_array_entry__FRAME_END___DYNAMICNU_EH_FRAME_HDRTABLE_location##GLIBC_2.2.5LIBC_2.2.5_2.2.5c_start_main##GLIBC_2.2.5##GLIBC_2.2.5ntf##GLIBC_2.2.5libc_csu_initic_pieGLIBC_2.2.55nterpABI-tagtr.rela.dynh_framebsstesuh #�?#0yey my c program worked.
some.txt = yey my c program worked.
argv[0] is always the program name. You're printing the contents of your executable in addition to any extra files identified by the filenames passed in the arguments by starting your for loop at i = 0.
If you start at i = 1, it will exclude your executable.

Executing binary/elf-file directly from (shared)-memory in C

we are trying to copy a binary/elf file into a shared-memory region of our system and then execute it thereafter. We don't want to call our "client"-program directly, since we need to execute it from the memory itself for our purpose.
While we know that our approach (described below) won't really work, we are (obviously) trying to get it to work. How would it be possible to copy a binary/elf/etc. file directly into the (shared)-memory and execute it thereafter? Maybe we just compiled it in the wrong way? Or something else was done wrong?
We also don't want to convert it into hex/shell-code, we already did that. We are looking for an easier and more practical solution.
Is anyone able to help? Would be much appreciated!
Two programs:
"Host"-Program (copy & execute client-program in shared memory)
"Client"-Program (basically a hello-world echo)
"Client"-Program:
#include <stdio.h>
int main()
{
printf("Hello, World!\n");
return 0;
}
Compiled with gcc -o binfile clientprogram.c -static.
"Host"-Program:
#include <string.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
FILE *fp; //filepointer
size_t size; //filesize
unsigned char *buffer; //buffer
fp = fopen("binfile","rb");
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
buffer = (unsigned char *) malloc(size);
if (fp == NULL){ //file empty?
printf("Error: There was an Error reading the file %s \n", "binfile");
exit(1);
}
else if (fread(buffer, sizeof *buffer, size, fp) != size){
printf("Error: There was an Error reading the file %s\n", "binfile");
exit(1);
}else{
int i;
// for(i=0; i<size;i++){
// printf("%02x", buffer[i]);
// }
}
void *mem = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
memcpy(mem, buffer, size);
mprotect(mem, size, PROT_READ|PROT_WRITE|PROT_EXEC);
void (*func)();
func = (void (*)()) buffer;
func();
munmap(mem, size);
fclose(fp);
free(buffer);
return 0;
}
Compiled with gcc hostprogram.c.
Build the client as a PIE, with -rdynamic. Then you'll be able to dlopen() it and dlsym() its main symbol (dlopen() will do the mmaping and mprotecting for you, as you'll be able to see if you strace the program), after which you'll be able to run its main from within the address space of the host.
Example:
#!/bin/sh
cat > client.c <<EOF
#include <stdio.h>
#include <unistd.h>
int main()
{
printf("Hello, World!: from %ld\n", (long)getpid());
return 0;
}
EOF
gcc -fpic -c client.c
gcc -pie -rdynamic -o client client.o
cat > host.c <<EOF
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
printf("Hello, I'm your host: %ld\n", (long)getpid()); ;
void *client_hndl;
typedef int main_t(int, char**);
main_t *client_main;
client_hndl = dlopen("./client", RTLD_LAZY);
if (!client_hndl){
fprintf(stderr, "%s\n", dlerror());
exit(1);
}
client_main = (main_t*)dlsym(client_hndl, "main");
if (!client_main){
fprintf(stderr, "%s\n", dlerror());
exit(2);
}
return client_main(1, (char*[]){"client", 0});
}
EOF
gcc host.c -ldl
./client
echo =============
./a.out
Example output:
Hello, World!: from 14520
=============
Hello, I'm your host: 14521
Hello, World!: from 14521
You are looking for a solution to this GLIBC feature request.
This feature request is 7 years old, and it's somewhat unlikely that anything will happen with it any time soon.
Your best bet is probably to do roughly what you are already doing (building a fully-static binary).
Your approach doesn't work because the executable you built requires to be loaded at the address it was linked at (visible in readelf -l binfile as the address of the first PT_LOAD segment. You would need to mmap your binfile there with MAP_FIXED, no other address will do.
You also need to read and decode the Elf{32,64}_Ehdr that is found at the beginning of the file to find entry point to jump to. You currently are jumping to the ELF header itself, but that header is not where the execution should start.

How to get device name on which a file is located from its path in c?

Let's say I have a file in Linux with this path:
/path/to/file/test.mp3
I want to know the path to its device. For example I want to get something like:
/dev/sdb1
How do I do this with the C programming language?
I know the terminal command to do it, but I need C functions that will do the job.
EDIT:
I have read this question before asking mine. It doesn't concretly mention code in C, it's more related to bash than to the C language.
Thanks.
You need to use stat on the file path, and get the device ID st_dev and match that to a device in /proc/partitions
Read this for how to interpret st_dev: https://web.archive.org/web/20171013194110/http://www.makelinux.net:80/ldd3/chp-3-sect-2
I just needed that inside a program I am writing...
So instead of running "df" and parsing the output, I wrote it from scratch.
Feel free to contribute!
To answer the question:
You first find the device inode using stat() then iterate and parse /proc/self/mountinfo to find the inode and get the device name.
/*
Get physical device from file or directory name.
By Zibri <zibri AT zibri DOT org>
https://github.com/Zibri/get_device
*/
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <libgen.h>
int get_device(char *name)
{
struct stat fs;
if (stat(name, &fs) < 0) {
fprintf(stderr, "%s: No such file or directory\n", name);
return -1;
}
FILE *f;
char sline[256];
char minmaj[128];
sprintf(minmaj, "%d:%d ", (int) fs.st_dev >> 8, (int) fs.st_dev & 0xff);
f = fopen("/proc/self/mountinfo", "r");
if (f == NULL) {
fprintf(stderr, "Failed to open /proc/self/mountinfo\n");
exit(-1);
}
while (fgets(sline, 256, f)) {
char *token;
char *where;
token = strtok(sline, "-");
where = strstr(token, minmaj);
if (where) {
token = strtok(NULL, " -:");
token = strtok(NULL, " -:");
printf("%s\n", token);
break;
}
}
fclose(f);
return -1;
}
int main(int argc, char **argv)
{
if (argc != 2) {
fprintf(stderr, "Usage:\n%s FILE OR DIRECTORY...\n", basename(argv[0]));
return -1;
}
get_device(argv[1]);
return 0;
}
output is just the device name.
Example:
$ gcc -O3 getdevice.c -o gd -Wall
$ ./gd .
/dev/sda4
$ ./gd /mnt/C
/dev/sda3
$ ./gd /mnt/D
/dev/sdb1
$
Use this command to print the partition path:
df -P <pathname> | awk 'END{print $1}'

How to get the path to the current file (pwd) in Linux from C?

I'd like to know if it is somehow possible to run system("pwd") on the current DIR. So for example let's have this folder structure:
example
>test
>>file
>test2
>>file3
>>file4
And with opendir() and readdir() I'll get to file3, and I want to use system("pwd") to get the path ..../example/test2/file3. Is this somehow possible, or will pwd return the path to main.c all the time?
Simply opening and reading directories does not change the current working directory. However, changing directory in your program will.
for reference,
#include <unistd.h>
#include <stdio.h>
int main() {
char cwd[1024];
chdir("/path/to/change/directory/to");
getcwd(cwd, sizeof(cwd));
printf("Current working dir: %s\n", cwd);
}
For POSIX systems I found three solutions:
Get value from an environment variables "PWD"
#include <stdio.h>
#include <stdlib.h>
#ifdef __unix__
#define IS_POSIX 1
#else
#define IS_POSIX 0
#endif
int main (int argv, char **argc)
{
if (IS_POSIX == 1) {
puts("Path info by use environment variable PWD:");
printf("\tWorkdir: %s\n", getenv("PWD"));
printf("\tFilepath: %s/%s\n", getenv("PWD"), __FILE__);
}
return 0;
}
Result:
Path info by use environment variable PWD:
Workdir: /media/setivolkylany/WorkDisk/Programming/Projects/c-utils
Filepath: /media/setivolkylany/WorkDisk/Programming/Projects/c-utils/main.c
Use getcwd()
#include <stdio.h>
#include <stdlib.h>
#ifdef __unix__
#define IS_POSIX 1
#include <unistd.h>
#else
#define IS_POSIX 0
#endif
int main (int argv, char **argc)
{
if (IS_POSIX == 1) {
char cwd[1024];
getcwd(cwd, sizeof(cwd));
puts("Path info by use getcwd():");
printf("\tWorkdir: %s\n", cwd);
printf("\tFilepath: %s/%s\n", cwd, __FILE__);
}
return 0;
}
Result
Path info by use getcwd():
Workdir: /media/setivolkylany/WorkDisk/Programming/Projects/c-utils
Filepath: /media/setivolkylany/WorkDisk/Programming/Projects/c-utils/main.c
Execute system command "pwd" and read output
#ifdef __unix__
#define IS_POSIX 1
#define _BSD_SOURCE
#else
#define IS_POSIX 0
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argv, char **argc)
{
if (IS_POSIX == 1) {
char buffer[500];
FILE *output;
// read output of a command
output = popen("/bin/pwd", "r");
char *pwd = fgets(buffer, sizeof(buffer), output);
// strip '\n' on ending of a line
pwd = strtok(pwd, "\n");
puts("Path info by execute shell command 'pwd':");
printf("\tWorkdir: %s\n", pwd);
printf("\tFilepath: %s/%s\n", pwd, __FILE__);
}
return 0;
}
Result:
Path info by execute shell command 'pwd':
Workdir: /media/setivolkylany/WorkDisk/Programming/Projects/c-utils
Filepath: /media/setivolkylany/WorkDisk/Programming/Projects/c-utils/main.c
You can use chdir(2) to change dir from C, then system("pwd"); will give you what ever directory you chdir'ed to.
The C-equvivalent of the pwd-command is getcwd(3).
When you use system(...) call with Windows and Linux it just executes one command. It is possible to do the same using file with commands (you can create it with C code), but my oppinion is, that you should use nftw() to get dirrectories and after that use opendir()/readdir().
How to not hardcode the path length with pathconf
I believe this is the correct way to do it:
#define _XOPEN_SOURCE 700
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main(void) {
long n;
char *buf;
n = pathconf(".", _PC_PATH_MAX);
assert(n != -1);
buf = malloc(n * sizeof(*buf));
assert(buf);
if (getcwd(buf, n) == NULL) {
perror("getcwd");
exit(EXIT_FAILURE);
} else {
printf("%s\n", buf);
}
free(buf);
return EXIT_SUCCESS;
}
GitHub upstream.
Compile and run:
gcc -Wall -Wextra -std=c11 -pedantic-errors -o getcwd.out getcwd.c
./getcwd.out
POSIX describes _PC_PATH_MAX it as:
The value returned for the variable {PATH_MAX} indicates the longest relative pathname that could be given if the specified directory is the process' current working directory. A process may not always be able to generate a name that long and use it if a subdirectory in the pathname crosses into a more restrictive file system.
Tested on Ubuntu 18.10, n == 4096 in this implementation.

Resources