📜 ⬆️ ⬇️

Change UID & GID user and his files

reuid.png - image uploaded to Picamatic
I got here the task to change the user's UID and GID and correctly change the owner of all files.
The fact is that I work on two computers alternately, and the mysql files are on my flash drive. It turned out that the user id of mysql on both computers is different and the muscle cannot access its files. Assigning permissions to 0666 is boring, and on this occasion I decided to learn how to correctly change the user's uid :)

It would seem that everything is simple, but there are two nuances that must be considered:
  1. UID and GID are not always the same for a user and his group.
  2. Not all files belong simultaneously to the user mysql and the mysql group: files for chown need to be looked for separately
The article is written for those who have not done anything like this yet, and also who want to learn the advanced use of the find command and find out what xargs is.


')
Change user id and group

The first step is the simplest and much has been written about it on the Internet. In the first two lines, we store useful data in variables: the name, the new id, and the old id for the user and for the group. This will be useful to us later when searching files, as well as simplify the reuse of the script. Everything is indicated separately in view of the first nuance: the UID and GID may differ.
Next is a trivial change of identifiers with standard Linux commands:
user = mysql new_uid = 600 old_uid = $ ( id -u $ user )
group = mysql new_gid = 600 old_gid = $ ( id -g $ user )
sudo usermod -u $ new_uid $ user
sudo groupmod -g $ new_gid $ group


Search for orphaned files

If we now look at one of the folders with the mysql files (for example, ls -lah /var/lib/mysql ), we will see that the files belong to the suspicious user 112 and the suspicious group 127. We will look for such files in order to adopt them :)

The first thing that comes to mind is to find all the files belonging to the user $old_uid or the group $old_group , and collect all the found files (using xargs) as arguments to the chown $user:$group . find is executed from root to ensure that it can get into all even the most severely protected folders and find everything it needs. xargs collects strings from pipe and passes them to the command specified in the argument (chown). I note that xargs can execute a command several times to avoid an argument string that is too long.
For example:
sudo find / -user $ old_uid -or -group $ old_gid -print0 | xargs -0 sudo chown $ user : $ group

Immediately pay attention to the flags find -print0 and find -print0 xargs -0 : this is such a struggle with possible spaces in the file names. Such files can be perceived chown 'ohm as two different. The first flag causes find to display every found file with zero at the end (the end-of-line character in C), and the second flag tells xargs that it needs to separate files from each other not by line breaks, but by this very zero, which guarantees correct processing of even the most tricky file names :)

However, this method will not bring the desired result: some files owned by 'mysql: root' will belong to 'mysql: mysql'. After all, we agreed to do everything perfectly right :) Therefore, the search by user and by group must be conducted separately.

You can execute two find commands in succession:
sudo find / -user $ old_uid -print0 | xargs -0 sudo chown $ user
sudo find / -group $ old_gid -print0 | xargs -0 sudo chown : $ group

and it will be much closer to the truth, but then find 'u will have to rustle twice over the entire hard disk.

There is a way to force the find to perform two operations for us in parallel, reducing the number of reads from the disk exactly twice. To do this, we use the grouping of conditions and find commands with parentheses (not forgetting to screen them: otherwise the shell will be taken for them) and sending the operator “comma” between them: then both brackets will be executed for each file.
We will create two separate files: in the first there will be a list of files with -user=$old_uid , and in the second - with -group=$old_gid , and we will process these files separately. The search condition is now divided into two brackets for each file, and if the condition is met, the -fprint0 command writes the path to the found orphaned file to the corresponding temporary file.
chownlist = $ ( tempfile ) chgrplist = $ ( tempfile )
sudo find / \
\ ( -user $ old_uid -fprint0 " $ chownlist " \ ) , \ ( -group $ old_gid -fprint0 " $ chgrplist " \ )

After a short search all files will be found.

The last moment of the search: the forums often ask the question how to exclude folders from the find list so that it does not climb there at all. This is done using a combination of the -path "folder" condition and the -prune , which prevents find climbing into folders in the condition. We exclude from the search the folders '/ proc' and '/ sys'.
To do this, add another grouping in brackets to the conditions, separating them from the already existing brackets with the -or operator. This operator will fulfill the first condition, and the second only if the first one does not work. So, find will check if the directory excluded from the listing (in which it will not search) has got to it, and if it does not, it will make lists of files.
This is done like this:
chownlist = $ ( tempfile ) chgrplist = $ ( tempfile )
sudo find / \
\ ( \ ( -path "/ proc" -or -path "/ sys" \ ) -prune \ ) -or \ # exclude folders
\ ( \ ( -user $ old_uid -fprint0 " $ chownlist " \ ) , \ ( -group $ old_gid -fprint0 " $ chgrplist " \ ) \ )


Also in the exceptions, you can make the path to the disk with backup (because you have it, right?;), Mounted network spheres, and so on.

The finish

Everything lists are compiled. Now for each list of files we execute chown . Let me remind you that we tried to fully retain the owner of the files, taking into account the possibly different user and group.
cat " $ chownlist " | xargs -0 sudo chown $ user
cat " $ chgrplist " | xargs -0 sudo chown : $ group
sudo rm " $ chownlist " " $ chgrplist " # Do not forget to clean up


Check

Finally, let's check if there are any files with unknown UIDs or GIDs left somewhere. There are two useful conditions for this: find -nouser and find -nogroup . It is also useful to refine the search by excluding the notorious '/ proc' and '/ sys' from the search:
sudo find / -nouser -or -nogroup -print

If everything was done correctly (and there were no orphaned files in the system), the team should not output anything.

Full script code


I hope the article will be useful. I recommend closer familiarization with the syntax of this command: it is much more powerful than you think :)
Finally, I will provide the full script code for changing the UID & GID of the user and his files:

# === Settings
user = mysql new_uid = 600 old_uid = $ ( id -u $ user ) # name, new and old UID
group = mysql new_gid = 600 old_gid = $ ( id -g $ user ) # name, new and old GID
# === UID & GID change
sudo usermod -u $ new_uid $ user
sudo groupmod -g $ new_gid $ group
# === Search for files
chownlist = $ ( tempfile ) chgrplist = $ ( tempfile ) sudo find / \
\ ( \ ( -path "/ proc" -or -path "/ sys" \ ) -prune \ ) -or \
\ ( \ ( -user $ old_uid -fprint0 " $ chownlist " \ ) , \ ( -group $ old_gid -fprint0 " $ chgrplist " \ ) \ )
# === chown and brush
cat " $ chownlist " | xargs -0 sudo chown $ user
cat " $ chgrplist " | xargs -0 sudo chown : $ group
sudo rm " $ chownlist " " $ chgrplist "

Source: https://habr.com/ru/post/81715/


All Articles