[GRASS-dev] [GRASS GIS] #3167: db.connect: connection to remote database does not work

#3167: db.connect: connection to remote database does not work
-----------------------------------+-------------------------
Reporter: mlennert | Owner: grass-dev@…
     Type: defect | Status: new
Priority: blocker | Milestone: 7.0.5
Component: Database | Version: unspecified
Keywords: postgresql db.connect | CPU: Unspecified
Platform: Unspecified |
-----------------------------------+-------------------------
In a freshly compiled 70release:

{{{
createdb -h myRemoteServer testgrass
grass70 -c /data/GRASS/DATA7/nc_spm_08/postgres_test
db.connect driver=pg database="host=myRemoteServer,dbname=testgrass"
> db.tables -p
DBMI-PostgreSQL erreur de pilote :
Connection failed.
FATAL: la base de données « testgrass » n'existe pas

DBMI-PostgreSQL erreur de pilote :
Connection failed.
FATAL: la base de données « testgrass » n'existe pas

ERREUR :Unable to open database
         <host=myRemoteServer,dbname=testgrass>
}}}

and

{{{
> g.copy vect=boundary_county,bc
Copy vector <boundary_county@PERMANENT> to current mapset as <bc>
DBMI-PostgreSQL driver error:
Connection failed.
FATAL: la base de données « testgrass » n'existe pas

DBMI-PostgreSQL driver error:
Connection failed.
FATAL: la base de données « testgrass » n'existe pas

WARNING: Unable to open database
          <host=myRemoteServer,dbname=testgrass> by driver
          <pg>
no database is open
no database is open
WARNING: Unable to copy table <bc>
WARNING: Unable to copy table <boundary_county> for layer 1 from
          <boundary_county@PERMANENT> to <bc>
}}}

but

{{{
> psql -h myRemoteServer -l | grep testgrass
  testgrass | mlennert | UTF8 | C | C |
}}}

--
Ticket URL: <https://trac.osgeo.org/grass/ticket/3167&gt;
GRASS GIS <https://grass.osgeo.org>

#3167: db.connect: connection to remote database does not work
--------------------------+-----------------------------------
  Reporter: mlennert | Owner: grass-dev@…
      Type: defect | Status: new
  Priority: blocker | Milestone: 7.0.5
Component: Database | Version: unspecified
Resolution: | Keywords: postgresql db.connect
       CPU: Unspecified | Platform: Unspecified
--------------------------+-----------------------------------

Comment (by mlennert):

{{{
g.gisenv set=DEBUG=3
db.tables -p
D1/3: G_set_program_name(): db.tables
D2/3: G_file_name(): path = /data/GRASS/DATA7/nc_spm_08/postgres_test
D2/3: dbDbmscap(): opendir
[/data/home/mlennert/SRC/GRASS/grass70_release/dist.x86_64-pc-linux-
gnu/driver/db/]
D2/3: dbDbmscap(): opendir
[/data/home/mlennert/SRC/GRASS/grass70_release/dist.x86_64-pc-linux-
gnu/driver/db/]
D1/3: db_d_init_error(): PostgreSQL
D3/3: db_get_login(): drv=[pg] db=[host=myRemoteServer,dbname=testgrass]
D3/3: read_file(): DB login file = </home/mlennert/.grass7/dblogin>
D3/3: login file does not exist
D3/3: db_driver_open_database(): driver=pg database definition =
'host=myRemoteServer,dbname=testgrass'
D3/3: parse_conn: 'host=myRemoteServer,dbname=testgrass'
D3/3: token 0 : host=myRemoteServer
D3/3: token 1 : dbname=testgrass
D3/3: db_get_login(): drv=[pg] db=[host=myRemoteServer,dbname=testgrass]
D3/3: read_file(): DB login file = </home/mlennert/.grass7/dblogin>
D3/3: login file does not exist
D3/3: db_driver_open_database(): host = (null), port = (null), options =
(null), tty = (null), dbname = testgrass, user = (null), password = (null)
schema = (null)
}}}

{{{
db.login driver=pg database=host=myRemoteServer,dbname=testgrass
db.tables -pD1/3: G_set_program_name(): db.tables
D2/3: G_file_name(): path = /data/GRASS/DATA7/nc_spm_08/postgres_test
D2/3: dbDbmscap(): opendir
[/data/home/mlennert/SRC/GRASS/grass70_release/dist.x86_64-pc-linux-
gnu/driver/db/]
D2/3: dbDbmscap(): opendir
[/data/home/mlennert/SRC/GRASS/grass70_release/dist.x86_64-pc-linux-
gnu/driver/db/]
D1/3: db_d_init_error(): PostgreSQL
D3/3: db_get_login(): drv=[pg] db=[host=myRemoteServer,dbname=testgrass]
D3/3: read_file(): DB login file = </home/mlennert/.grass7/dblogin>
D3/3: ret = 2 : drv=[pg] db=[host=myRemoteServer,dbname=testgrass] usr=
pwd= host=, port=
D3/3: db_driver_open_database(): driver=pg database definition =
'host=myRemoteServer,dbname=testgrass'
D3/3: parse_conn: 'host=myRemoteServer,dbname=testgrass'
D3/3: token 0 : host=myRemoteServer
D3/3: token 1 : dbname=testgrass
D3/3: db_get_login(): drv=[pg] db=[host=myRemoteServer,dbname=testgrass]
D3/3: read_file(): DB login file = </home/mlennert/.grass7/dblogin>
D3/3: ret = 2 : drv=[pg] db=[host=myRemoteServer,dbname=testgrass] usr=
pwd= host=, port=
D3/3: db_driver_open_database(): host = (null), port = (null), options =
(null), tty = (null), dbname = testgrass, user = (null), password = (null)
schema = (null)
}}}

So the host name gets lost somewhere on the way.

--
Ticket URL: <https://trac.osgeo.org/grass/ticket/3167#comment:1&gt;
GRASS GIS <https://grass.osgeo.org>

#3167: db.connect: connection to remote database does not work
--------------------------+-----------------------------------
  Reporter: mlennert | Owner: grass-dev@…
      Type: defect | Status: new
  Priority: blocker | Milestone: 7.0.5
Component: Database | Version: unspecified
Resolution: | Keywords: postgresql db.connect
       CPU: Unspecified | Platform: Unspecified
--------------------------+-----------------------------------

Comment (by martinl):

Replying to [ticket:3167 mlennert]:
> {{{
> createdb -h myRemoteServer testgrass
> grass70 -c /data/GRASS/DATA7/nc_spm_08/postgres_test
> db.connect driver=pg database="host=myRemoteServer,dbname=testgrass"
> }}}

did you tried

{{{
db.connect driver=pg database=testgrass
db.connect driver=pg database=testgrass host=myRemoteServer
}}}

? Martin

--
Ticket URL: <https://trac.osgeo.org/grass/ticket/3167#comment:2&gt;
GRASS GIS <https://grass.osgeo.org>

#3167: db.connect: connection to remote database does not work
--------------------------+-----------------------------------
  Reporter: mlennert | Owner: grass-dev@…
      Type: defect | Status: new
  Priority: blocker | Milestone: 7.0.5
Component: Database | Version: unspecified
Resolution: | Keywords: postgresql db.connect
       CPU: Unspecified | Platform: Unspecified
--------------------------+-----------------------------------

Comment (by mlennert):

Replying to [comment:2 martinl]:
> Replying to [ticket:3167 mlennert]:
> > {{{
> > createdb -h myRemoteServer testgrass
> > grass70 -c /data/GRASS/DATA7/nc_spm_08/postgres_test
> > db.connect driver=pg database="host=myRemoteServer,dbname=testgrass"
> > }}}
>
> did you tried
>
> {{{
> db.connect driver=pg database=testgrass
> db.login driver=pg database=testgrass host=myRemoteServer
> }}}
>

Doesn't work:

{{{
rm .grass7/dblogin
db.connect driver=pg database=testgrass
db.login driver=pg database=testgrass host=myRemoteServer
db.tables -p
DBMI-PostgreSQL erreur de pilote :
Connection failed.
FATAL: la base de données « testgrass » n'existe pas

DBMI-PostgreSQL erreur de pilote :
Connection failed.
FATAL: la base de données « testgrass » n'existe pas

ERREUR :Unable to open database <testgrass>
}}}

and with DEBUG=3

{{{
D1/3: G_set_program_name(): db.tables
D2/3: G_file_name(): path = /data/GRASS/DATA7/nc_spm_08/postgres_test
D2/3: dbDbmscap(): opendir
[/data/home/mlennert/SRC/GRASS/grass70_release/dist.x86_64-pc-linux-
gnu/driver/db/]
D2/3: dbDbmscap(): opendir
[/data/home/mlennert/SRC/GRASS/grass70_release/dist.x86_64-pc-linux-
gnu/driver/db/]
D1/3: db_d_init_error(): PostgreSQL
D3/3: db_get_login(): drv=[pg] db=[testgrass]
D3/3: read_file(): DB login file = </home/mlennert/.grass7/dblogin>
D3/3: ret = 2 : drv=[pg] db=[testgrass] usr= pwd= host=, port=
D3/3: db_driver_open_database(): driver=pg database definition =
'testgrass'
D3/3: parse_conn: 'testgrass'
D3/3: db_get_login(): drv=[pg] db=[testgrass]
D3/3: read_file(): DB login file = </home/mlennert/.grass7/dblogin>
D3/3: ret = 2 : drv=[pg] db=[testgrass] usr= pwd= host=, port=
D3/3: db_driver_open_database(): host = (null), port = (null), options =
(null), tty = (null), dbname = testgrass, user = (null), password = (null)
schema = (null)
}}}

--
Ticket URL: <https://trac.osgeo.org/grass/ticket/3167#comment:3&gt;
GRASS GIS <https://grass.osgeo.org>

#3167: db.connect: connection to remote database does not work
--------------------------+-----------------------------------
  Reporter: mlennert | Owner: grass-dev@…
      Type: defect | Status: new
  Priority: blocker | Milestone: 7.0.5
Component: Database | Version: unspecified
Resolution: | Keywords: postgresql db.connect
       CPU: Unspecified | Platform: Unspecified
--------------------------+-----------------------------------

Comment (by mlennert):

Replying to [comment:2 martinl]:
> Replying to [ticket:3167 mlennert]:
> > {{{
> > createdb -h myRemoteServer testgrass
> > grass70 -c /data/GRASS/DATA7/nc_spm_08/postgres_test
> > db.connect driver=pg database="host=myRemoteServer,dbname=testgrass"
> > }}}
>
> did you tried
>
> {{{
> db.connect driver=pg database=testgrass
> db.login driver=pg database=testgrass host=myRemoteServer
> }}}
>

And if this is how it is supposed to be done, then we need to change the
man page.

It just seems a bit redundant to have to indicate driver and database
twice...

--
Ticket URL: <https://trac.osgeo.org/grass/ticket/3167#comment:4&gt;
GRASS GIS <https://grass.osgeo.org>

#3167: db.connect: connection to remote database does not work
--------------------------+-----------------------------------
  Reporter: mlennert | Owner: grass-dev@…
      Type: defect | Status: new
  Priority: blocker | Milestone: 7.0.5
Component: Database | Version: unspecified
Resolution: | Keywords: postgresql db.connect
       CPU: Unspecified | Platform: Unspecified
--------------------------+-----------------------------------

Comment (by mlennert):

The VAR file in the mapset contains this:

{{{
DB_DRIVER: pg
DB_DATABASE: testgrass
}}}

i.e. no info about the host. Is this normal ?

--
Ticket URL: <https://trac.osgeo.org/grass/ticket/3167#comment:5&gt;
GRASS GIS <https://grass.osgeo.org>

#3167: db.connect: connection to remote database does not work
--------------------------+-----------------------------------
  Reporter: mlennert | Owner: grass-dev@…
      Type: defect | Status: new
  Priority: blocker | Milestone: 7.0.5
Component: Database | Version: unspecified
Resolution: | Keywords: postgresql db.connect
       CPU: Unspecified | Platform: Unspecified
--------------------------+-----------------------------------

Comment (by mlennert):

Replying to [comment:5 mlennert]:
> The VAR file in the mapset contains this:
>
>
> {{{
> DB_DRIVER: pg
> DB_DATABASE: testgrass
> }}}
>
> i.e. no info about the host. Is this normal ?

Replying to myself: this is when I use db.connect without 'host=' in the
database string. When I use 'host=', I get:

DB_DRIVER: pg
DB_DATABASE: host=myRemoteHost,dbname=testgrass

--
Ticket URL: <https://trac.osgeo.org/grass/ticket/3167#comment:6&gt;
GRASS GIS <https://grass.osgeo.org>

#3167: db.connect: connection to remote database does not work
--------------------------+-----------------------------------
  Reporter: mlennert | Owner: grass-dev@…
      Type: defect | Status: new
  Priority: blocker | Milestone: 7.0.5
Component: Database | Version: unspecified
Resolution: | Keywords: postgresql db.connect
       CPU: Unspecified | Platform: Unspecified
--------------------------+-----------------------------------

Comment (by mlennert):

Replying to [comment:4 mlennert]:
> Replying to [comment:2 martinl]:
> > Replying to [ticket:3167 mlennert]:
> > > {{{
> > > createdb -h myRemoteServer testgrass
> > > grass70 -c /data/GRASS/DATA7/nc_spm_08/postgres_test
> > > db.connect driver=pg database="host=myRemoteServer,dbname=testgrass"
> > > }}}
> >
> > did you tried
> >
> > {{{
> > db.connect driver=pg database=testgrass
> > db.login driver=pg database=testgrass host=myRemoteServer
> > }}}
> >
>

I just noticed that the first sentence with the most important information
is missing:

Yes, I tried, but it didn't make a difference. Exact same error as before
and DEBUG=3 gives me:

D3/3: db_driver_open_database(): host = (null), port = (null), options =
(null), tty = (null), dbname = testgrass, user = (null), password = (null)
schema = (null)

> And if this is how it is supposed to be done, then we need to change the
man page.
>
> It just seems a bit redundant to have to indicate driver and database
twice...

--
Ticket URL: <https://trac.osgeo.org/grass/ticket/3167#comment:7&gt;
GRASS GIS <https://grass.osgeo.org>

#3167: db.connect: connection to remote database does not work
--------------------------+-----------------------------------
  Reporter: mlennert | Owner: grass-dev@…
      Type: defect | Status: new
  Priority: blocker | Milestone: 7.0.5
Component: Database | Version: unspecified
Resolution: | Keywords: postgresql db.connect
       CPU: Unspecified | Platform: Unspecified
--------------------------+-----------------------------------

Comment (by mlennert):

BTW: I get the same errors in trunk.

--
Ticket URL: <https://trac.osgeo.org/grass/ticket/3167#comment:8&gt;
GRASS GIS <https://grass.osgeo.org>

#3167: db.connect: connection to remote database does not work
--------------------------+-----------------------------------
  Reporter: mlennert | Owner: grass-dev@…
      Type: defect | Status: new
  Priority: blocker | Milestone: 7.0.5
Component: Database | Version: unspecified
Resolution: | Keywords: postgresql db.connect
       CPU: Unspecified | Platform: Unspecified
--------------------------+-----------------------------------

Comment (by mlennert):

Getting closer:

The issue seems to be in the reading of the dblogin file.

My file contains;

{{{
pg|testgrass|||myRemoteHost|
}}}

But the debug message show:

{{{
D3/3: read_file(): DB login file = </home/mlennert/.grass7/dblogin>
D3/3: ret = 2 : drv=[pg] db=[testgrass] usr= pwd= host=, port=
}}}

Looking at the sscanf call that reads the data from the file (in
lib/db/dbmi_base/login.c, line 118, I see:

{{{
         ret = sscanf(buf, "%[^|]|%[^|]|%[^|]|%[^|]|%[^|]|%[^\n]",
                      dr, db, usr, pwd, host, port);
}}}

Somehow this doesn't seem to read the line as it should...

--
Ticket URL: <https://trac.osgeo.org/grass/ticket/3167#comment:9&gt;
GRASS GIS <https://grass.osgeo.org>

#3167: db.connect: connection to remote database does not work
--------------------------+-----------------------------------
  Reporter: mlennert | Owner: grass-dev@…
      Type: defect | Status: new
  Priority: blocker | Milestone: 7.0.5
Component: Database | Version: unspecified
Resolution: | Keywords: postgresql db.connect
       CPU: Unspecified | Platform: Unspecified
--------------------------+-----------------------------------

Comment (by mlennert):

The issue arises when some of the fields are empty, as for usr and pwd in
my example. Anything from that point on is ignored. When I set a username
and password with db.login, my db.tables example works like a charm.

See [http://stackoverflow.com/questions/1508754/how-do-i-parse-out-the-
fields-in-a-comma-separated-string-using-sscanf-while-sup here] for a
discussion of the issue. Would using strtok be an alternative, here ? Or
better yet: G_tokenize() ?

--
Ticket URL: <https://trac.osgeo.org/grass/ticket/3167#comment:10&gt;
GRASS GIS <https://grass.osgeo.org>

#3167: db.connect: connection to remote database does not work
--------------------------+-----------------------------------
  Reporter: mlennert | Owner: grass-dev@…
      Type: defect | Status: new
  Priority: blocker | Milestone: 7.0.5
Component: Database | Version: unspecified
Resolution: | Keywords: postgresql db.connect
       CPU: Unspecified | Platform: Unspecified
--------------------------+-----------------------------------
Changes (by mlennert):

* Attachment "dbmi_base_login.diff" added.

very crude patch to show path to solution

--
Ticket URL: <http://trac.osgeo.org/grass/ticket/3167&gt;
GRASS GIS <https://grass.osgeo.org>

#3167: db.connect: connection to remote database does not work
--------------------------+-----------------------------------
  Reporter: mlennert | Owner: grass-dev@…
      Type: defect | Status: new
  Priority: blocker | Milestone: 7.0.5
Component: Database | Version: unspecified
Resolution: | Keywords: postgresql db.connect
       CPU: Unspecified | Platform: Unspecified
--------------------------+-----------------------------------

Comment (by mlennert):

Replying to [comment:10 mlennert]:
> The issue arises when some of the fields are empty, as for usr and pwd
in my example. Anything from that point on is ignored. When I set a
username and password with db.login, my db.tables example works like a
charm.
>
> See [http://stackoverflow.com/questions/1508754/how-do-i-parse-out-the-
fields-in-a-comma-separated-string-using-sscanf-while-sup here] for a
discussion of the issue. Would using strtok be an alternative, here ? Or
better yet: G_tokenize() ?

I've attached a proof-of-concept patch that solves the problem for me, but
it hardcodes the number of tokens. I don't know what forms login strings
can potentially take, so this definitely needs to be revised to take into
account different scenarios.

--
Ticket URL: <https://trac.osgeo.org/grass/ticket/3167#comment:11&gt;
GRASS GIS <https://grass.osgeo.org>

#3167: db.connect: connection to remote database does not work
--------------------------+-----------------------------------
  Reporter: mlennert | Owner: grass-dev@…
      Type: defect | Status: new
  Priority: blocker | Milestone: 7.0.5
Component: Database | Version: unspecified
Resolution: | Keywords: postgresql db.connect
       CPU: Unspecified | Platform: Unspecified
--------------------------+-----------------------------------

Comment (by mlennert):

Another issue linked to the wxGUI (reported by Stefan Lüdtke - I can
confirm):

"If everything is in db.login, I can connect to the db (as reported
earlier) and list tables. However I can neither link nor import them
because they are not listed in the gui box."

I can see the database in the list, but once I select it, no tables are
listed.

Using

{{{
v.in.ogr input="PG:dbname=testgrass host=myRemoteServer"
layer=boundary_county out=bc
}}}

I can import a layer, but not using

{{{
v.in.ogr input="PG:dbname=testgrass" layer=boundary_county out=bc
}}}

I imagine v.in.ogr does not take into account the .grass7/dblogin file.

--
Ticket URL: <https://trac.osgeo.org/grass/ticket/3167#comment:12&gt;
GRASS GIS <https://grass.osgeo.org>

#3167: db.connect: connection to remote database does not work
--------------------------+-----------------------------------
  Reporter: mlennert | Owner: grass-dev@…
      Type: defect | Status: new
  Priority: blocker | Milestone: 7.0.5
Component: Database | Version: unspecified
Resolution: | Keywords: postgresql db.connect
       CPU: Unspecified | Platform: Unspecified
--------------------------+-----------------------------------

Comment (by mlennert):

One question about the new db.connect + db.login combination: if host
information is stored in .grass7/dblogin file indexed by database, how
does the system deal with two databases of the same name on two different
hosts ?

--
Ticket URL: <https://trac.osgeo.org/grass/ticket/3167#comment:13&gt;
GRASS GIS <https://grass.osgeo.org>

#3167: db.connect: connection to remote database does not work
--------------------------+-----------------------------------
  Reporter: mlennert | Owner: grass-dev@…
      Type: defect | Status: new
  Priority: blocker | Milestone: 7.0.5
Component: Database | Version: unspecified
Resolution: | Keywords: postgresql db.connect
       CPU: Unspecified | Platform: Unspecified
--------------------------+-----------------------------------

Comment (by martinl):

Replying to [comment:11 mlennert]:
> I've attached a proof-of-concept patch that solves the problem for me,
but it hardcodes the number of tokens. I don't know what forms login
strings can potentially take, so this definitely needs to be revised to
take into account different scenarios.

Please review attachment:dbmi_base_login2.diff

--
Ticket URL: <http://trac.osgeo.org/grass/ticket/3167#comment:14&gt;
GRASS GIS <https://grass.osgeo.org>

#3167: db.connect: connection to remote database does not work
--------------------------+-----------------------------------
  Reporter: mlennert | Owner: grass-dev@…
      Type: defect | Status: new
  Priority: blocker | Milestone: 7.0.5
Component: Database | Version: unspecified
Resolution: | Keywords: postgresql db.connect
       CPU: Unspecified | Platform: Unspecified
--------------------------+-----------------------------------
Changes (by martinl):

* Attachment "dbmi_base_login2.diff" added.

--
Ticket URL: <http://trac.osgeo.org/grass/ticket/3167&gt;
GRASS GIS <https://grass.osgeo.org>

#3167: db.connect: connection to remote database does not work
--------------------------+-----------------------------------
  Reporter: mlennert | Owner: grass-dev@…
      Type: defect | Status: new
  Priority: blocker | Milestone: 7.0.5
Component: Database | Version: unspecified
Resolution: | Keywords: postgresql db.connect
       CPU: Unspecified | Platform: Unspecified
--------------------------+-----------------------------------

Comment (by mlennert):

Replying to [comment:14 martinl]:
> Replying to [comment:11 mlennert]:
> > I've attached a proof-of-concept patch that solves the problem for me,
but it hardcodes the number of tokens. I don't know what forms login
strings can potentially take, so this definitely needs to be revised to
take into account different scenarios.
>
> Please review attachment:dbmi_base_login2.diff

Seems to work nicely, and much more elegant than my hack, thanks !

--
Ticket URL: <https://trac.osgeo.org/grass/ticket/3167#comment:15&gt;
GRASS GIS <https://grass.osgeo.org>

#3167: db.connect: connection to remote database does not work
--------------------------+-----------------------------------
  Reporter: mlennert | Owner: grass-dev@…
      Type: defect | Status: new
  Priority: blocker | Milestone: 7.0.5
Component: Database | Version: unspecified
Resolution: | Keywords: postgresql db.connect
       CPU: Unspecified | Platform: Unspecified
--------------------------+-----------------------------------

Comment (by martinl):

Replying to [comment:13 mlennert]:
> One question about the new db.connect + db.login combination: if host
information is stored in .grass7/dblogin file indexed by database, how
does the system deal with two databases of the same name on two different
hosts ?

Currently it's not possible, items in the file are indexed by
driver/database. Probably we could disable indexing at all. Please fill
new ticket for that.

--
Ticket URL: <https://trac.osgeo.org/grass/ticket/3167#comment:16&gt;
GRASS GIS <https://grass.osgeo.org>

#3167: db.connect: connection to remote database does not work
--------------------------+-----------------------------------
  Reporter: mlennert | Owner: grass-dev@…
      Type: defect | Status: new
  Priority: blocker | Milestone: 7.0.5
Component: Database | Version: unspecified
Resolution: | Keywords: postgresql db.connect
       CPU: Unspecified | Platform: Unspecified
--------------------------+-----------------------------------

Comment (by mlennert):

Replying to [comment:15 mlennert]:
> Replying to [comment:14 martinl]:
> > Replying to [comment:11 mlennert]:
> > > I've attached a proof-of-concept patch that solves the problem for
me, but it hardcodes the number of tokens. I don't know what forms login
strings can potentially take, so this definitely needs to be revised to
take into account different scenarios.
> >
> > Please review attachment:dbmi_base_login2.diff
>
> Seems to work nicely, and much more elegant than my hack, thanks !

P.S. Someone should probably check for mysql or other db backends, or ?

--
Ticket URL: <https://trac.osgeo.org/grass/ticket/3167#comment:17&gt;
GRASS GIS <https://grass.osgeo.org>