UNDERCODE COMMUNITY
2.69K subscribers
1.23K photos
31 videos
2.65K files
80.5K links
πŸ¦‘ Undercode Cyber World!
@UndercodeCommunity


1️⃣ World first platform which Collect & Analyzes every New hacking method.
+ AI Pratice
@Undercode_Testing

2️⃣ Cyber & Tech NEWS:
@Undercode_News

3️⃣ CVE @Daily_CVE

✨ Web & Services:
β†’ Undercode.help
Download Telegram
πŸ¦‘ MOST REQUESTED PAID PDFs
This media is not supported in your browser
VIEW IN TELEGRAM
πŸ¦‘ programming tutorials now :
▁ β–‚ β–„ ο½•π•Ÿπ”»β’Ίπ«Δ†π”¬π““β“” β–„ β–‚ ▁

πŸ¦‘Programming Technology-Process and Thread Programming by undercode :
t.me/UndercodeTesting

look at the relationship between processes and Mach tasks and threads in UNIX systems. In a UNIX system, a process includes an executable program and a series of resources, such as a file descriptor table and address space. In Mach, a task includes only a series of resources; threads process all executable code. A Mach task can have any number of threads associated with it, and each thread must be associated with a task. All threads related to a given task share the task's resources. In this way, a thread is a program counter, a stack and a series of registers. All data structures that need to be used are tasks. A process in a UNIX system corresponds to a task and a separate thread in Mach.

[Directory]

----------------------------------------------- ---------------------------------


Original pipeline It is

more complicated to use C language to create pipeline than to use pipeline under shell. If you want to use C language to create a simple pipeline, you can use the system call pipe (). It accepts a parameter, which is an array of two integers. If the system call is successful, this array will include the two file descriptors used by the pipeline. After creating a pipeline, the process will generally generate a new process.
You can create a bidirectional pipe by opening two pipes. But the file description needs to be set correctly in the child process. Pipe () must be called in the fork () system call, otherwise the child process will not inherit the file descriptor. When using a half-duplex pipeline, any associated process must share an associated ancestor process. Because the pipeline exists in the system kernel, any process that is not among the ancestors of the process that created the pipeline will not be able to address it. This is not the case in named pipes.

written by undercode
▁ β–‚ β–„ ο½•π•Ÿπ”»β’Ίπ«Δ†π”¬π““β“” β–„ β–‚ ▁
This media is not supported in your browser
VIEW IN TELEGRAM
▁ β–‚ β–„ ο½•π•Ÿπ”»β’Ίπ«Δ†π”¬π““β“” β–„ β–‚ ▁

πŸ¦‘ MORE PROGRAMMING :

Directory]

----------------------------------------------- ---------------------------------


pipe ()

system call: pipe ();
prototype: intpipe (intfd [2 ]);
Return value: If the system call is successful, return 0
If the system call fails, return -1: errno = EMFILE (no free file descriptor)
EMFILE (system file table is full)
EFAULT (fd array is invalid)
Note fd [0 ] Is used to read the pipeline, and fd [1] is used to write the pipeline.
#include <stdio.h>
#include <unistd.h>
#include <sys / types.h>
main ()
{
intfd [2];
pipe (fd);
..
}
Once the pipeline is created, we can create one New child process:
#include <stdio.h>
#include <unistd.h>
#include <sys / types.h>
main ()
{
intfd [2];
pid_t childpid;
pipe (fd);
if ((childpid = fork ()) ==-1)
{
perror ("fork");
exit (1);
} ..
}
If the parent process wants to read data from the child process, then it should close fd1, and at the same time The child process closes fd0. Conversely, if the parent process wishes to send data to the child process, then it should close fd0 and the child process closes fd1. Because the file descriptor is shared between the parent process and the child process, we must promptly close the end of the unnecessary pipeline. From a technical point of view, if one end of the pipe is not closed properly, you will not get an EOF.

#include <stdio.h>
#include <unistd.h>
#include <sys / types.h>
main ()
{
intfd [2];
pid_t childpid;
pipe (fd);
if ((childpid = fork ()) = = -1)
{
perror ("fork");
exit (1);
}
if (childpid == 0)
{
/ * Child process closes up in put side of pipe * /
close (fd [0]);
}
else
{
/ * Parent process closes up out put put of side of pipe * /
close (fd [1]);
} ..
}

As mentioned before, once the pipeline is created, the file descriptor used by the pipeline is the same as the normal file The file descriptor is the same.

#include <stdio.h>
#include <unistd.h>
#include <sys / types.h>
intmain (void)
{
intfd [2], nbytes;
pid_tchildpid;
charstring [] = "Hello, world!";
charreadbuffer [ 80];
pipe (fd);
if ((childpid = fork ()) ==-1)
{
perror ("fork");
exit (1);
}
if (childpid == 0)
{
/ * Child process closes up in put side of pipe * /
close (fd [0]);
/ * Send "string" through the out put side of pipe * /
write (fd [1], string, strlen (string));
exit (0);
}
else
{
/ * Parent process closes up out put side of pipe * /
close (fd [1]);
/ * Readinastringfromthepipe * /
nbytes = read (fd [0], readbuffer, sizeof (readbuffer)) ;
printf ("Receivedstring:% s", readbuffer);
}
return (0);
} In

general, the file descriptor in the child process will be copied to the standard input and output. This way the child process can use exec () to execute another program, which inherits the standard data flow.




[Directory]

----------------------------------------------- ---------------------------------


dup ()

system call: dup ();
prototype: inddup (intoldfd);
Return: If the system call succeeds, a new file descriptor
is returned. If the system call fails, -1 is returned: errno = EBADF (oldfd is not a valid file descriptor)
EBADF (newfd is out of range)
EMFILE (process file descriptors too many)
Note that the old file descriptor oldfd is not closed. Although the old file descriptor and the newly created file descriptor can be used interchangeably, in general, you need to close one first. The system call dup () uses the free file descriptor with the smallest number.
Look at the following program again:
..
childpid = fork ();
if (childpid == 0)
{
/ * Close up standard input of the child * /
close (0);
/ * Dup licate the input side of pipe to stdin * /
DUP (FD [0]);
execlp ( "Sort", "Sort", NULL);
.
}
as the file descriptor 0 (stdin) is closed, the DUP () of the feed line descriptor copied to its standard Entering. This way we can call execlp () and use the sort program to overwrite the text segment of the child process. Because the newly created program inherits the standard input / output stream from its parent process, it actually inherits the input end of the pipe as its standard input end. Now, any data sent by the original parent process to the pipeline will be sent directly to the sort function.




[Directory]

----------------------------------------------- ---------------------------------


dup2 ()

system call: dup2 ();
prototype: inddup2 (intoldfd, intnewfd );
Return value: If the call is successful, return a new file descriptor
If the call fails, return -1: errno = EBADF (oldfd is not a valid file descriptor)
EBADF (newfd out of range)
EMFILE (process file descriptors too many)
Note that dup2 () will close the old file descriptor.
Using this system call, the close operation and file descriptor copy operation can be integrated into one system call. In addition, this system call ensures the automatic operation of the operation, which means that the operation cannot be interrupted by other signals. This operation will be completed before returning to the system kernel. If the previous system call dup () is used, the programmer has to perform a close () operation before that. Please see the following program:
..

childpid = fork ();
if (childpid == 0)
{
/ * Close stdin, dup licate the input side of pipe to stdin * /
dup2 (0, fd [0]);
execlp ( "sort", "sort", NULL);
..
}




[Directory]

--------------------------------- -----------------------------------------------


popen () And pclose ()

If you think the above method of creating and using pipes is too cumbersome, you can also use the following simple method:
library functions: popen () and pclose ();
prototype: FILE * popen (char * command, char * type);
Return value: If successful, return a new file stream.
If the process or pipeline cannot be created, NULL is returned.
This standard library function creates a half-duplex pipe by calling pipe () inside the system, then it creates a child process, starts a shell, and finally executes the command in the command parameter on the shell. The direction of the data flow in the pipeline is controlled by the second parameter type. This parameter can be r or w, representing read or write, respectively. It cannot be read and written at the same time. Under the linux system, the pipeline will be opened in the way represented by the first character in the parameter type. So, if you write rw in the parameter type, the pipe will be opened for reading.

Although the usage of this library function is simple, there are some disadvantages. For example, it loses some control over the system when using the system call pipe (). Despite this, because shell commands can be used directly, some wildcards and other extended symbols in the shell can be used in the command parameter.
Pipelines created using popen () must be closed using pclose (). In fact, popen / pclose is very similar to fopen () / fclose () in the standard file input / output stream.


Library function: pclose ();
Prototype: intpclose (FILE * stream);
Return value: Returns the state of the system call wait4 ().
If the stream is invalid, or the system call wait4 () fails, it returns -1.
Note that this library function waits for the pipeline process to finish, and then closes the file stream. The library function pclose () executes the wait4 () function on the process created with popen (). When it returns, it will destroy the pipeline and file system.
In the following example, a pipeline is opened with the sort command, and then a character array is sorted:
#include <stdio.h>
# defineMAXSTRS5
intmain (void)
{
intcntr;
FILE * pipe_fp;
char * strings [MAXSTRS] = {"echo", "bravo", "alpha",
"charlie", "delta"};
/ * Createonewaypipelinewithcalltopopen () * /
if (( pipe_fp = popen ("sort", "w")) == NULL)
{
perror ("popen");
exit (1);
}
/ * Processingloop * /
for (cntr = 0; cntr <MAXSTRS; cntr ++) {
fputs (strings [cntr], pipe_fp);
fputc ('', pipe_fp);
}
/ * Closethepipe * /
pclose (pipe_fp);
return (0);
}
Because popen () uses the shell to execute commands, all shell extensions and Wildcards can be used. In addition, it can also use redirection and output pipeline functions with popen (). Look at the following example again:
popen ("ls ~ scottb", "r");


The following program is another example using popen (), which opens two pipes (one for the ls command and the other for the
sort command):
#include <stdio.h>
intmain (void)
{
FILE * pipein_fp, * pipeout_fp;
charreadbuf [80];
/ * Createonewaypipelinewithcalltopopen () * /
if ((pipein_fp = popen ("ls", "r")) == NULL)
{
perror ("popen");
exit (1);
}
/ * Createonewaypipelinewithcalltopopen () * /
if ((pipeout_fp = popen ("sort", "w")) == NULL)
{
perror ("popen");
exit (1);
}
/ * Processingloop * /
while (fgets (readbuf, 80, pipein_fp))
fputs (readbuf, pipeout_fp);
/ * Closethepipes * /
pclose (pipein_fp);
pclose (pipeout_fp);
return (0);
}
Finally, let's look at another example using popen (). This program is used to create a pipeline between a command and a file:
#include <stdio.h>
intmain (intargc, char * argv [])
{
FILE * pipe_fp, * infile;
charreadbuf [80];
if (argc! = 3 ) {
fprintf (stderr, "USAGE: popen3 [command] [filename]");
exit (1);
}
/ * Open up input file * /
if ((infile = fopen (argv [2], "rt")) == NULL)
{
perror ("fopen");
exit (1);
}
/ * Create one way pipe line with call topopen () * /
if ((pipe_fp = popen (argv [1], "w")) = = NULL)
{
perror ("popen");
exit (1);
}
/ * Processingloop * /
do {
fgets (readbuf, 80, infile);
if (feof (infile)) break;
fputs (readbuf, pipe_fp);
} while (! feof (infile));
fclose (infile);
pclose (pipe_fp);
return (0);
}
The following is an example of using this program:
popen3sortpopen3.c
popen3catpopen3.c
popen3morepopen3.c
popen3catpopen3.c | grepmain




[directory]

------------------------------------------ --------------------------------------


Named pipes

Named pipes are basically the same as general pipes, but There are also some significant differences:
* Named pipes exist as a special device file in the file system.
* Data can be shared between processes of different ancestors through pipes.
* When the shared pipe process has performed all I / O operations, the named pipe will continue to be saved in the file system for later use.

A pipe must have both a reading process and a writing process. If a process attempts to write to a pipe that has no read process, the system kernel will generate a SIGPIPE signal. This is especially important when more than two processes use pipes at the same time.


[Directory]

----------------------------------------------- ---------------------------------




There are several ways to create a FIFO to create a named pipe. The first two methods can use the shell.
mknodMYFIFOp
mkfifoa = rwMYFIFO
The two names above perform the same operation, but there is one difference. The command mkfifo provides a way to directly change the access rights of the FIFO file after creation, and the command mknod needs to call the command chmod.
A physical file system can easily distinguish a FIFO file through the p indicator.

$ ls-lMYFIFO
prw-r--r--1rootroot0Dec1422: 15MYFIFO |

Please note the pipe symbol "|" after the file name.
We can use the system call mknod () to create a FIFO pipeline:

library function: mknod ();
prototype: intmknod (char * pathname, mode_tmode, dev_tdev);
return value: if successful, return 0
if failed, return -1: errno = EFAULT (invalid path name)
EACCES (no access permission)
ENAMETOOLONG (path name too long)
ENOENT (invalid path name)
ENOTDIR (invalid path name)

Let's look at an example of using C language to create a FIFO pipeline:
mknod ("/ tmp / MYFIFO ", S_IFIFO | 0666,0);

In this example, the file / tmp / MYFIFO is the FIFO file to be created. Its access authority is 0666. Access permissions
can also be modified using umask:

final_umask = requested_permissions & ~ original_umask

A commonly used method of using system call umask () is to temporarily clear the value of
umask : umask (0);
mknod ("/ tmp / MYFIFO", S_IFIFO | 0666,0);

In addition, mknod () The third parameter in can only be used when creating a device file. It includes the
major and minor device numbers of the device file .
}
}






[Directory]

--------------------------------------------- -----------------------------------


Operation FIFO

I / O operation on FIFO and I on normal pipeline / O operations are basically the same, with one major difference. The system call open is used to physically open a pipe. In a half-duplex pipeline, this is unnecessary. Because the pipeline is in the system kernel, not in a physical file system. In our example, we will use the pipeline like a file stream, that is, use fopen () to open the pipeline and fclose () to close it.
Look at the following simple service program process:
#include <stdio.h>
#include <stdlib.h>
#include <sys / stat.h>
#include <unistd.h>
#include <linux / stat.h>
# defineFIFO_FILE "MYFIFO"

{
FILE * fp;
charreadbuf [80];
/ * CreatetheFIFOifitdoesnotexist * /
umask (0);
mknod (FIFO_FILE, S_IFIFO | 0666,0);
while (1)
{
fp = fopen (FIFO_FILE, "r");
fgets (readbuf , 80, fp);
printf ("Receivedstring:% s", readbuf);
fclose (fp);
return (0);
Because the FIFO pipeline has a blocking function by default, you can run this program in the background:
$ fifoserver &
Let's take a look at the following simple client program:
#include <stdio.h>
#include <stdlib.h>
#defineFIFO_FILE "MYFIFO"
intmain (int argc, char * argv [])
{
FILE * fp;
if (argc! = 2) {
printf ("USAGE: fifoclient [string]");
exit (1);
}
if ((fp = fopen (FIFO_FILE, "w")) == NULL) {
perror ("fopen");
exit (1);
}
fputs (argv [1], fp);
fclose (fp);
return (0);
}


[directory]

------------- -------------------------------------------------- -----------------


Blocking FIFO

Under normal circumstances, there will be blocking on the FIFO pipeline. In other words, if a FIFO pipe is opened for reading, it will block until other processes open the pipe to write information. This process is also reversed. If you don't need a blocking function, you can set the O_NONBLOCK flag in the system call open (), which will cancel the default blocking function.



[Directory]

----------------------------------------------- ---------------------------------


message queue

in SystemV versions of UNIX, aT & T introduced three new forms of IPC Features (message queue, semaphore, and shared memory). But the BSD version of UNIX uses sockets as the main form of IPC. The Linux system supports both versions.

[Directory]

----------------------------------------------- ---------------------------------


msgget ()

system call msgget ()
If you want to create a new message queue, or want to access an existing message queue, you can use the system call msgget ().

System call: msgget ();
Prototype: intmsgget (key_t key, int msgflg);
Return value: If successful, return message queue identifier
If it fails, return -1: errno = EACCESS (permission not allowed)
EEXIST (queue already exists , Cannot be created)
EIDRM (the queue flag is deleted)
ENOENT (the queue does not exist)
ENOMEM (the memory is not enough when creating the queue)
ENOSPC (the maximum queue limit is exceeded

) The first parameter in the system call msgget () is the keyword value (usually Returned by ftok ()). Then this keyword value will be compared with other keyword values ​​already in the system kernel. At this time, the opening and access operations are related to the content of the parameter msgflg.
IPC_CREAT Create this queue if it is not in the kernel.
IPC_EXCL, when used with IPC_CREAT, fails if the queue already exists.