How to execute C program in Linux or Windows simple commands to print a file - c

Hi there, I am trying to make a C program that will print herself source code.
I am assuming that the source code file and the execute file are in the same directory without any other .c files.
Well I have tried many codes, and it didn't worked out.
The error cause because the order of the commands (if it is windows command first it passed in windows OS and if it is a linux command first it passed in linux OS).
I am trying to ignore fopen and other functions and to use only simple OS commands.
Here is the code I have tried:
code working on windows:
/* C library statement */
#include <stdlib.h>
/* main program */
int main()
{/* start of main */
int windows = 0; /* a variable to check if we are running windows or unix operation system */
/* system function returns -1 value if it failed.
* so if unix value is -1 we are not running unix system.
* if we are not running unix system we will execute windows commands.
*/
windows = system("type *.c"); /* windows command to print file text */
if(windows == -1) /* if windows command failed (and the specific file is exists) then we are not running windows operation system */
system("cat *.c"); /* unix command to print file text */
return 0;
}/* end of main */
code working on linux:
/* this program will print herself source code by using simple linux or windows commands */
#include <stdlib.h>
/* main program */
int main()
{/* start of main */
int unix = 0; /* a variable to check if we are running windows or unix operation system */
/* system function returns -1 value if it failed.
* so if unix value is -1 we are not running unix system.
* if we are not running unix system we will execute windows commands.
*/
unix = system("cat *.c"); /* unix command to print file text */
if(unix == -1) /* if unix command failed (and the specific file is exists) then we are not running unix operation system */
system("type *.c"); /* windows command to print file text */
return 0;
}/* end of main */
well the problem is that linux recognize type as a bash command and windows is not compiling the cat command

I Made This Code Working, Can Be Compiled and Run in Both OS
#include <stdlib.h>
/* defining variables to check if what OS we are running in */
#if defined (_WIN32) || defined (_WIN64) /* if we are running win 32bit or win 64 bit */
#define HAVEWIN 1 /* defined we are running at windows OS */
#define HAVEUNIX 0 /* defined we are not running at unix OS */
#elif defined (__unix__) /* if we are running a unix OS */
#define HAVEUNIX 1 /* defined we are running at unix OS */
#define HAVEWIN 0 /* defined we are not running at unix OS */
#endif /* end of the OS checks */
/* main program */
int main()
{/* start of main */
if(HAVEWIN == 1) /* if we are running on windows OS */
system("type *.c"); /* use windows command to print file text */
else if(HAVEUNIX == 1) /* if we are running on unix OS */
system("cat *.c"); /* use unix command to print file text */
return 0;
}/* end of main */

The symbol __FILE__ always expands to the name of the current file. The following code will print the source code location:
#include <stdio.h>
int main()
{
printf("%s\n", __FILE__);
return 0;
}
So you should just then just add code to dump its contents.
But don't use system() calls, as this is not portable and very inefficient.

Related

Determine `OSTYPE` during runtime in C program

In a C program, I need to find the OSTYPE during runtime, on the basis of which I will do some operations.
Here is the code
#include <stdlib.h>
#include <string.h>
int main () {
const char * ostype = getenv("OSTYPE");
if (strcasecmp(ostype, /* insert os name */) == 0) ...
return 0;
}
But getenv returns NULL (and there is segmentation fault). When I do a echo $OSTYPE in the terminal it prints darwin15 . But when I do env | grep OSTYPE nothing gets printed, which means it is not in the list of environment variables. To make it work on my local machine I can go to the .bash_profile and export the OSTYPE manually but that doesn't solve the problem if I want to run a generated executable on a new machine.
Why is OSTYPE available while running terminal, but apparently not there in the list of environment variables. How to get around this ?
For the crash, you should check if the return was NULL or not before using it in strcmp or any function. From man 3 getenv:
The getenv() function returns a pointer to the value in the
environment, or NULL if there is no match.
If you're at POSIX (most Unix's and somehow all Linux's), I agree with Paul's comment on uname.
But actually you can check for OSTYPE at compile time with precompiler (with #ifdef's), here's a similar question on so: Determine OS during runtime
Edit: uname
Good point Jonathan. man 2 uname on my linux tells how to use (and begin POSIX, macos has the same header, too):
SYNOPSIS
#include <sys/utsname.h>
int uname(struct utsname *buf);
DESCRIPTION
uname() returns system information in the structure pointed to by buf. The utsname struct is
defined in :
struct utsname {
char sysname[]; /* Operating system name (e.g., "Linux") */
char nodename[]; /* Name within "some implementation-defined
network" */
char release[]; /* Operating system release (e.g., "2.6.28") */
char version[]; /* Operating system version */
char machine[]; /* Hardware identifier */
#ifdef _GNU_SOURCE
char domainname[]; /* NIS or YP domain name */
#endif
};

OpenMPI Execution Problems on Raspberry Pi

I am trying to build a beowulf cluster with Raspberry Pi. I downloaded the following packages of OpenMPI: openmpi-bin, openmpi-common, libopenmpi1.3, libopenmpi-dbg, libopenmpi-dev. I used static IP on each of the Raspberrys and tested the connection between each of them and it was working. I also enabled the ssh and I used it to login from one Raspberry to all the other Raspberrys.
This is the following code I used:
#include <mpi.h>
int main(int argc, char *argv[])
{
int tid,nthreads;
char *cpu_name;
/* add in MPI startup routines */
/* 1st: launch the MPI processes on each node */
MPI_Init(&argc,&argv);
/* 2nd: request a thread id, sometimes called a "rank" from
the MPI master process, which has rank or tid == 0
*/
MPI_Comm_rank(MPI_COMM_WORLD, &tid);
/* 3rd: this is often useful, get the number of threads
or processes launched by MPI, this should be NCPUs-1
*/
MPI_Comm_size(MPI_COMM_WORLD, &nthreads);
/* on EVERY process, allocate space for the machine name */
cpu_name = (char *)calloc(80,sizeof(char));
/* get the machine name of this particular host ... well
at least the first 80 characters of it ... */
gethostname(cpu_name,80);
printf("hello MPI user: from process = %i on machine=%s, of NCPU=%i processes\n",
tid, cpu_name, nthreads);
MPI_Finalize();
return(0);
}
I tested the code first with only 2 boards and it worked fine no problems no errors and it printed the printf statement in the code.
I created a host file which includes the following:
Pi0
Pi1
Pi2
Pi3
I have 4 Raspberry Pis. I copied the code on each of them and compiled the code also using the following statements:
mpicc -g -0O -c hello-mpi.c -o hello-mpi.o
mpicc -g hello-mpi.o -o hello-mpi
I executed the code with the following statement:
mpirun -np 4 -hostfile hostfile hello-mpi
when I run the program nothing happens it just gives me an new empty line. No errors are given also. Any suggestion what I can I do to make it work

(Osh) Omake Error: Unexpected Token: String: {

I am working on an assignment for class, in which we have to build a simple shell interface for a Unix system in C. I am using Ubuntu and when I run the source code in that was provided using this command:
osh> cat shell.c
I get an error:
*** omake error: File /home/cameron/cs426/Project1/shell.c: line 11, characters 20-24
unexpected token: string: {
This is my first time using osh, so does anyone have any ideas as to what the issue might be?
Also, here's the code, just in case.
#include<stdio.h>
#include<unistd.h>
#define MAX_LINE 80 /* 80 chars per line, per command */
int main(void)
{
char *args[MAX_LINE/2 + 1]; /* command line (of 80) has max of 40 arguments */
int should_run = 1;
while(should_run){
printf("osh>");
fflush(stdout);
/**
* After reading user input, the steps are:
* (1) fork a child process
* (2) the child process will invoke execvp()
* (3) if command included &, parent will invoke wait()
*/
}
return 0;
}
It looks like this code was intended to be a shell. What you need to do is:
Open a terminal that runs a real shell. osh is the OMake shell, and is probably not relevant this assignment. The code you gave prints "osh", but isn't the osh.
Compile with gcc -o shell-that-calls-itself-osh shell.c The -o flag tells gcc where to put the compiled binary.
Run with ./shell-that-calls-itself-osh The ./ is to run code in the current directory.

Get Linux system information in C

I have to check Linux system information. I can execute system commands in C, but doing so I create a new process for every one, which is pretty expensive. I was wondering if there is a way to obtain system information without being forced to execute a shell command. I've been looking around for a while and I found nothing. Actually, I'm not even sure if it's more convenient to execute commands via Bash calling them from my C program or find a way to accomplish the tasks using only C.
Linux exposes a lot of information under /proc. You can read the data from there. For example, fopen the file at /proc/cpuinfo and read its contents.
A presumably less known (and more complicated) way to do that, is that you can also use the api interface to sysctl. To use it under Linux, you need to #include <unistd.h>, #include <linux/sysctl.h>. A code example of that is available in the man page:
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <linux/sysctl.h>
int _sysctl(struct __sysctl_args *args );
#define OSNAMESZ 100
int
main(void)
{
struct __sysctl_args args;
char osname[OSNAMESZ];
size_t osnamelth;
int name[] = { CTL_KERN, KERN_OSTYPE };
memset(&args, 0, sizeof(struct __sysctl_args));
args.name = name;
args.nlen = sizeof(name)/sizeof(name[0]);
args.oldval = osname;
args.oldlenp = &osnamelth;
osnamelth = sizeof(osname);
if (syscall(SYS__sysctl, &args) == -1) {
perror("_sysctl");
exit(EXIT_FAILURE);
}
printf("This machine is running %*s\n", osnamelth, osname);
exit(EXIT_SUCCESS);
}
However, the man page linked also notes:
Glibc does not provide a wrapper for this system call; call it using
syscall(2). Or rather... don't call it: use of this system call has
long been discouraged, and it is so unloved that it is likely to
disappear in a future kernel version. Since Linux 2.6.24, uses of this
system call result in warnings in the kernel log. Remove it from your
programs now; use the /proc/sys interface instead.
This system call is available only if the kernel was configured with
the CONFIG_SYSCTL_SYSCALL option.
Please keep in mind that anything you can do with sysctl(), you can also just read() from /proc/sys. Also note that I do understand that the usefulness of that syscall is questionable, I just put it here for reference.
You can also use the sys/utsname.h header file to get the kernel version, hostname, operating system, machine hardware name, etc. More about sys/utsname.h is here. This is an example of getting the current kernel release.
#include <stdio.h> // I/O
#include <sys/utsname.h>
int main(int argc, char const *argv[])
{
struct utsname buff;
printf("Kernel Release = %s\n", buff.release); // kernel release
return 0;
}
This is the same as using the uname command. You can also use the -a option which stands for all information.
uname -r # -r stands for kernel release

C program for executing 'echo' on a target with no /bin directory

Let us say I cross-compile this code for ARM from a host Linux system:
#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
int main (void) {
return execl ("/bin/echo", "echo", NULL);
}
I got a binary echoFromC
The problem is on my target where this binary would run, has no /bin, /usr etc. So it will not execute the command.
So I want that the final binary should contain every thing required to excute "echo". It shouild not look for /bin/echo (since it is not there).
How do I do this?
Actually I have to implement:
bash> echo 240 > /sys/class/gpio/export
bash> echo out > /sys/class/gpio/gpio240/direction
bash> echo 1 > /sys/class/gpio/gpio240/value
in a c program
You could implement those echo functions in C, for example to implement echo 240 > /sys/class/gpio/export, you could do something like
FILE *fh;
fh = open("/sys/class/gpio/export", "w+");
if (fh == NULL) { /* fopen failed */ }
fwrite("240\n", 1, 4, fh);
fclose(fh);

Resources