~ubuntu-branches/ubuntu/precise/smb4k/precise

« back to all changes in this revision

Viewing changes to utilities/smb4k_sudowriter.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Richard A. Johnson
  • Date: 2008-11-23 12:14:34 UTC
  • mfrom: (1.1.14 upstream)
  • Revision ID: james.westby@ubuntu.com-20081123121434-88cpidapbcqteud1
Tags: 0.10.1-0ubuntu1
* New upstream release for KDE 4
* Closes
  - (LP: #238011)
  - (LP: #248510)
  - (LP: #261803)
  - (LP: #262225)
  - (LP: #275539)
* Updated debian/
  - control: updated for new deps and removed old deps, bumped versions,
    modified Maintainer
  - rules: removed all but the kde4.mk for cdbs

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
    smb4k_sudowriter  -  This program writes to the sudoers file. It
 
3
    belongs to the utility programs of Smb4K.
 
4
                             -------------------
 
5
    begin                : Di Jul 29 2008
 
6
    copyright            : (C) 2008 by Alexander Reinholdt
 
7
    email                : dustpuppy@users.berlios.de
 
8
 ***************************************************************************/
 
9
 
 
10
/***************************************************************************
 
11
 *   This program is free software; you can redistribute it and/or modify  *
 
12
 *   it under the terms of the GNU General Public License as published by  *
 
13
 *   the Free Software Foundation; either version 2 of the License, or     *
 
14
 *   (at your option) any later version.                                   *
 
15
 *                                                                         *
 
16
 *   This program is distributed in the hope that it will be useful, but   *
 
17
 *   WITHOUT ANY WARRANTY; without even the implied warranty of            *
 
18
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
 
19
 *   General Public License for more details.                              *
 
20
 *                                                                         *
 
21
 *   You should have received a copy of the GNU General Public License     *
 
22
 *   along with this program; if not, write to the                         *
 
23
 *   Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,   *
 
24
 *   MA  02111-1307 USA                                                    *
 
25
 ***************************************************************************/
 
26
 
 
27
// Qt includes
 
28
#include <QDir>
 
29
#include <QFile>
 
30
#include <QTextCodec>
 
31
#include <QString>
 
32
#include <QByteArray>
 
33
#include <QStringList>
 
34
 
 
35
// KDE includes
 
36
#include <kaboutdata.h>
 
37
#include <kcmdlineargs.h>
 
38
#include <kapplication.h>
 
39
#include <kdebug.h>
 
40
#include <klocale.h>
 
41
#include <kuser.h>
 
42
#include <kstandarddirs.h>
 
43
 
 
44
// system includes
 
45
#include <stdlib.h>
 
46
#include <sys/types.h>
 
47
#include <sys/stat.h>
 
48
#include <unistd.h>
 
49
#include <errno.h>
 
50
#include <pwd.h>
 
51
#include <iostream>
 
52
 
 
53
using namespace std;
 
54
 
 
55
static QFile lock_file;
 
56
 
 
57
static const char description[] =
 
58
  I18N_NOOP( "This program writes to the sudoers file." );
 
59
 
 
60
static const char authors[] =
 
61
  I18N_NOOP( "(c) 2008, Alexander Reinholdt" );
 
62
 
 
63
int createLockFile()
 
64
{
 
65
  // Determine the directory where to write the lock file. First, try
 
66
  // /var/lock and than /var/tmp. If that does not work either, fall
 
67
  // back to /tmp.
 
68
  QList<QByteArray> dirs;
 
69
  dirs << "/var/lock";
 
70
  dirs << "/var/tmp";
 
71
  dirs << "/tmp";
 
72
 
 
73
  struct stat buf;
 
74
 
 
75
  for ( int i = 0; i < dirs.size(); ++i )
 
76
  {
 
77
    // First check if the directory is available and writable
 
78
    if ( lstat( dirs.at( i ), &buf ) == -1 )
 
79
    {
 
80
      int error_number = errno;
 
81
 
 
82
      if ( error_number != EACCES && error_number != ENOENT )
 
83
      {
 
84
        return error_number;
 
85
      }
 
86
    }
 
87
    else
 
88
    {
 
89
      // Continue
 
90
    }
 
91
 
 
92
    // Get the ids of the groups the user is in and check if
 
93
    // on of them matches buf.st_gid.
 
94
    KUser user( geteuid() );
 
95
    QList<KUserGroup> gids = user.groups();
 
96
    gid_t sup_gid = 65534; // set this to gid 'nobody' for initialization
 
97
    bool found_gid = false;
 
98
 
 
99
    for ( int j = 0; j < gids.size(); ++j )
 
100
    {
 
101
      if ( gids.at( j ).gid() == buf.st_gid )
 
102
      {
 
103
        sup_gid = gids.at( j ).gid();
 
104
        found_gid = false;
 
105
 
 
106
        break;
 
107
      }
 
108
      else
 
109
      {
 
110
        continue;
 
111
      }
 
112
    }
 
113
 
 
114
    // Check whether we are stat'ing a directory and that the
 
115
    // user has read/write permissions.
 
116
    if ( S_ISDIR( buf.st_mode ) /* is directory */ &&
 
117
        ((buf.st_uid == getuid() && (buf.st_mode & 00600) == (S_IWUSR | S_IRUSR)) /* user */ ||
 
118
        (found_gid && buf.st_gid == sup_gid && (buf.st_mode & 00060) == (S_IWGRP | S_IRGRP)) /* group */ ||
 
119
        ((buf.st_mode & 00006) == (S_IWOTH | S_IROTH)) /* others */) )
 
120
    {
 
121
      lock_file.setFileName( dirs.at( i )+"/smb4k.lock" );
 
122
 
 
123
      break;
 
124
    }
 
125
    else
 
126
    {
 
127
      continue;
 
128
    }
 
129
  }
 
130
 
 
131
  if ( !lock_file.exists() )
 
132
  {
 
133
    if ( lock_file.open( QIODevice::WriteOnly | QIODevice::Text ) )
 
134
    {
 
135
      QTextStream ts( &lock_file );
 
136
      // Note: With Qt 4.3 this seems to be obsolete, we'll keep
 
137
      // it for now.
 
138
      ts.setCodec( QTextCodec::codecForLocale() );
 
139
 
 
140
#if QT_VERSION >= 0x040400
 
141
      if ( kapp )
 
142
      {
 
143
        ts << kapp->applicationPid() << endl;
 
144
      }
 
145
      else
 
146
      {
 
147
        ts << "0" << endl;
 
148
      }
 
149
#else
 
150
      ts << "0" << endl;
 
151
#endif
 
152
 
 
153
      lock_file.close();
 
154
    }
 
155
    else
 
156
    {
 
157
      return 1;
 
158
    }
 
159
  }
 
160
  else
 
161
  {
 
162
    return 2;
 
163
  }
 
164
 
 
165
  return 0;
 
166
}
 
167
 
 
168
void removeLockFile()
 
169
{
 
170
  // Just remove the lock file. No further checking is needed.
 
171
  if ( lock_file.exists() )
 
172
  {
 
173
    lock_file.remove();
 
174
  }
 
175
  else
 
176
  {
 
177
    // Do nothing
 
178
  }
 
179
}
 
180
 
 
181
const QByteArray findFile( const QString &filename )
 
182
{
 
183
  QStringList paths;
 
184
  paths << "/etc";
 
185
  paths << "/usr/local/etc";
 
186
 
 
187
  QString canonical_path;
 
188
 
 
189
  for ( int i = 0; i < paths.size(); ++i )
 
190
  {
 
191
    QDir::setCurrent( paths.at( i ) );
 
192
 
 
193
    if ( QFile::exists( filename ) )
 
194
    {
 
195
      canonical_path = QDir::current().canonicalPath()+QDir::separator()+filename;
 
196
 
 
197
      break;
 
198
    }
 
199
    else
 
200
    {
 
201
      continue;
 
202
    }
 
203
  }
 
204
 
 
205
  return canonical_path.toLocal8Bit();
 
206
}
 
207
 
 
208
bool checkUsers( const QStringList &list )
 
209
{
 
210
  for ( int i = 0; i < list.size(); ++i )
 
211
  {
 
212
    if ( getpwnam( list.at( i ).toLocal8Bit() ) == NULL )
 
213
    {
 
214
      return false;
 
215
    }
 
216
    else
 
217
    {
 
218
      continue;
 
219
    }
 
220
  }
 
221
 
 
222
  return true;
 
223
}
 
224
 
 
225
int checkFile( const QByteArray &path )
 
226
{
 
227
  // Stat the file, so that we know that it is safe to
 
228
  // read from and write to it and whether we need to
 
229
  // ask for the super user's password:
 
230
  struct stat buf;
 
231
 
 
232
  if ( lstat( path, &buf ) == -1 )
 
233
  {
 
234
    return errno;
 
235
  }
 
236
  else
 
237
  {
 
238
    // Do nothing
 
239
  }
 
240
 
 
241
  // Get the ids of the groups the user is in and check if
 
242
  // on of them matches buf.st_gid.
 
243
  KUser user( geteuid() );
 
244
  QList<KUserGroup> gids = user.groups();
 
245
  gid_t sup_gid = 65534; // set this to gid 'nobody' for initialization
 
246
  bool found_gid = false;
 
247
 
 
248
  for ( int i = 0; i < gids.size(); ++i )
 
249
  {
 
250
    if ( gids.at( i ).gid() == buf.st_gid )
 
251
    {
 
252
      sup_gid = gids.at( i ).gid();
 
253
      found_gid = false;
 
254
 
 
255
      break;
 
256
    }
 
257
    else
 
258
    {
 
259
      continue;
 
260
    }
 
261
  }
 
262
 
 
263
  if ( !S_ISREG( buf.st_mode ) || S_ISFIFO( buf.st_mode ) || S_ISLNK( buf.st_mode ) )
 
264
  {
 
265
    return 1;
 
266
  }
 
267
  else
 
268
  {
 
269
    // Do nothing
 
270
  }
 
271
 
 
272
  // Check the access rights. We need to read the file.
 
273
  if ( buf.st_uid != geteuid() && !found_gid &&
 
274
       (buf.st_mode & 00004) != (S_IWOTH | S_IROTH) /* others */ )
 
275
  {
 
276
    return 2;
 
277
  }
 
278
  else
 
279
  {
 
280
    // Do nothing
 
281
  }
 
282
 
 
283
  return 0;
 
284
}
 
285
 
 
286
bool findUtilityPrograms()
 
287
{
 
288
  if ( KGlobal::dirs()->findResource( "exe", "smb4k_kill" ).isEmpty() ||
 
289
       KGlobal::dirs()->findResource( "exe", "smb4k_umount" ).isEmpty() ||
 
290
       KGlobal::dirs()->findResource( "exe", "smb4k_mount" ).isEmpty() )
 
291
  {
 
292
    return false;
 
293
  }
 
294
  else
 
295
  {
 
296
    // Do nothing
 
297
  }
 
298
 
 
299
  return true;
 
300
}
 
301
 
 
302
int main ( int argc, char *argv[] )
 
303
{
 
304
  KAboutData aboutData( "smb4k_sudowriter",
 
305
                        "smb4k",
 
306
                        ki18n( "smb4k_sudowriter" ),
 
307
                        "0.2",
 
308
                        ki18n( description ),
 
309
                        KAboutData::License_GPL_V2,
 
310
                        ki18n( authors ),
 
311
                        KLocalizedString(),
 
312
                        "http://smb4k.berlios.de",
 
313
                        "smb4k-bugs@lists.berlios.de" );
 
314
 
 
315
  KCmdLineArgs::init( argc, argv, &aboutData );
 
316
 
 
317
  KCmdLineOptions options;
 
318
  options.add( "adduser <user>",
 
319
               ki18n( "Adds an user to the sudoers file" ),
 
320
               0 );
 
321
  options.add( "removeuser <user>",
 
322
               ki18n( "Removes an user from the sudoers file" ),
 
323
               0 );
 
324
 
 
325
  KCmdLineArgs::addCmdLineOptions( options );
 
326
 
 
327
  KApplication app( false /* no GUI */ );
 
328
 
 
329
  // Before doing anything else, create the lock file.
 
330
  int return_value = 0;
 
331
 
 
332
  if ( (return_value = createLockFile()) != 0 )
 
333
  {
 
334
    switch ( return_value )
 
335
    {
 
336
      case 1:
 
337
      {
 
338
        cerr << argv[0] << ": " << I18N_NOOP( "The lock file could not be created." ) << endl;
 
339
        break;
 
340
      }
 
341
      case 2:
 
342
      {
 
343
        cerr << argv[0] << ": " << I18N_NOOP( "Another user is currently editing the sudoers file." ) << endl;
 
344
        break;
 
345
      }
 
346
      default:
 
347
      {
 
348
        cerr << argv[0] << ": " << strerror( return_value ) << endl;
 
349
        break;
 
350
      }
 
351
    }
 
352
 
 
353
    cerr << argv[0] << ": " << I18N_NOOP( "Aborting." ) << endl;
 
354
    exit( EXIT_FAILURE );
 
355
  }
 
356
  else
 
357
  {
 
358
    // Do nothing
 
359
  }
 
360
 
 
361
  KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
 
362
 
 
363
  // Check that everything is OK.
 
364
  QStringList adduser    = args->getOptionList( "adduser" );
 
365
  QStringList removeuser = args->getOptionList( "removeuser" );
 
366
 
 
367
  // Throw an error if no argument was provided.
 
368
  if ( adduser.isEmpty() && removeuser.isEmpty() )
 
369
  {
 
370
    KCmdLineArgs::usageError( i18n( "No arguments given." ) );
 
371
    removeLockFile();
 
372
    exit( EXIT_FAILURE );
 
373
  }
 
374
  else
 
375
  {
 
376
    // Do nothing
 
377
  }
 
378
 
 
379
  // Check that the given users are all valid.
 
380
  if ( !checkUsers( adduser ) || !checkUsers( removeuser ) )
 
381
  {
 
382
    cerr << argv[0] << ": " << I18N_NOOP( "An invalid user name has been provided." ) << endl;
 
383
    cerr << argv[0] << ": " << I18N_NOOP( "Aborting." ) << endl;
 
384
    removeLockFile();
 
385
    exit( EXIT_FAILURE );
 
386
  }
 
387
  else
 
388
  {
 
389
    // Do nothing
 
390
  }
 
391
 
 
392
  // Find the sudoers file.
 
393
  QByteArray path = findFile( "sudoers" );
 
394
 
 
395
  if ( path.isEmpty() )
 
396
  {
 
397
    cerr << argv[0] << ": " << I18N_NOOP( "The sudoers file was not found." ) << endl;
 
398
    cerr << argv[0] << ": " << I18N_NOOP( "Aborting." ) << endl;
 
399
    removeLockFile();
 
400
    exit( EXIT_FAILURE );
 
401
  }
 
402
  else
 
403
  {
 
404
    // Do nothing
 
405
  }
 
406
 
 
407
  // Check that the file is regular.
 
408
  if ( (return_value = checkFile( path )) != 0 )
 
409
  {
 
410
    switch ( return_value )
 
411
    {
 
412
      case 1:
 
413
      {
 
414
        cerr << argv[0] << ": " << I18N_NOOP( "The sudoers file is irregular." ) << endl;
 
415
        break;
 
416
      }
 
417
      case 2:
 
418
      {
 
419
        cerr << argv[0] << ": " << I18N_NOOP( "Cannot access sudoers file." ) << endl;
 
420
        break;
 
421
      }
 
422
      default:
 
423
      {
 
424
        cerr << argv[0] << ": " << strerror( return_value ) << endl;
 
425
        break;
 
426
      }
 
427
    }
 
428
 
 
429
    cerr << argv[0] << ": " << I18N_NOOP( "Aborting." ) << endl;
 
430
    removeLockFile();
 
431
    exit( EXIT_FAILURE );
 
432
  }
 
433
  else
 
434
  {
 
435
    // Do nothing
 
436
  }
 
437
 
 
438
  // Check that the utility programs can actually be found.
 
439
  if ( !findUtilityPrograms() )
 
440
  {
 
441
    cerr << argv[0] << ": " << I18N_NOOP( "One or more utility programs could not be found." ) << endl;
 
442
    cerr << argv[0] << ": " << I18N_NOOP( "Aborting." ) << endl;
 
443
    removeLockFile();
 
444
    exit( EXIT_FAILURE );
 
445
  }
 
446
  else
 
447
  {
 
448
    // Do nothing
 
449
  }
 
450
 
 
451
  // Now work with the sudoers file.
 
452
  QFile file( path );
 
453
 
 
454
  // Save the original permissions for later.
 
455
  QFile::Permissions perms = file.permissions();
 
456
 
 
457
  // Temporarily give the *owner* the permission to
 
458
  // write to the file.
 
459
  file.setPermissions( QFile::WriteOwner | QFile::ReadOwner );
 
460
 
 
461
  QStringList contents;
 
462
 
 
463
  if ( file.open( QIODevice::ReadOnly | QIODevice::Text ) )
 
464
  {
 
465
    QTextStream ts( &file );
 
466
    // Note: With Qt 4.3 this seems to be obsolete, we'll keep
 
467
    // it for now.
 
468
    ts.setCodec( QTextCodec::codecForLocale() );
 
469
 
 
470
    while ( !ts.atEnd() )
 
471
    {
 
472
      contents.append( ts.readLine( 0 ) );
 
473
    }
 
474
 
 
475
    file.close();
 
476
    file.setPermissions( perms );
 
477
  }
 
478
  else
 
479
  {
 
480
    file.setPermissions( perms );
 
481
    cerr << argv[0] << ": " << file.errorString().toLocal8Bit().data() << endl;
 
482
    removeLockFile();
 
483
    exit( EXIT_FAILURE );
 
484
  }
 
485
 
 
486
  // Find the beginning and the end of the entries in
 
487
  // the sudoers file:
 
488
  int begin = contents.indexOf( "# Entries for Smb4K users.", 0 );
 
489
  int end = contents.lastIndexOf( "# End of Smb4K user entries.", -1 );
 
490
 
 
491
  bool write = false;
 
492
 
 
493
  // Add user(s).
 
494
  if ( !adduser.isEmpty() )
 
495
  {
 
496
    if ( begin == -1 && end == -1 )
 
497
    {
 
498
      // Get the hostname.
 
499
      size_t hostnamelen = 255;
 
500
      char *hn = new char[hostnamelen];
 
501
 
 
502
      if ( gethostname( hn, hostnamelen ) == -1 )
 
503
      {
 
504
        int error_number = errno;
 
505
        cerr << argv[0] << ": " << strerror( error_number ) << endl;
 
506
        removeLockFile();
 
507
        exit( EXIT_FAILURE );
 
508
      }
 
509
      else
 
510
      {
 
511
        // Do nothing
 
512
      }
 
513
 
 
514
      QString hostname( hn );
 
515
      delete [] hn;
 
516
 
 
517
      // Add the new entries.
 
518
      if ( !contents.last().trimmed().isEmpty() )
 
519
      {
 
520
        contents.append( "" );
 
521
      }
 
522
      else
 
523
      {
 
524
        // Do not add empty line to the end.
 
525
      }
 
526
 
 
527
      contents.append( "# Entries for Smb4K users." );
 
528
      contents.append( "# Generated by Smb4K. Please do not modify!" );
 
529
      contents.append( "User_Alias\tSMB4KUSERS = "+QString( "%1" ).arg( adduser.join( "," ) ) );
 
530
      contents.append( "Defaults:SMB4KUSERS\tenv_keep += \"PASSWD USER\"" );
 
531
      contents.append( "SMB4KUSERS\t"+hostname+" = NOPASSWD: "
 
532
                       +KGlobal::dirs()->findResource( "exe", "smb4k_kill" ) );
 
533
      contents.append( "SMB4KUSERS\t"+hostname+" = NOPASSWD: "
 
534
                       +KGlobal::dirs()->findResource( "exe", "smb4k_umount" ) );
 
535
      contents.append( "SMB4KUSERS\t"+hostname+" = NOPASSWD: "
 
536
                       +KGlobal::dirs()->findResource( "exe", "smb4k_mount" ) );
 
537
      contents.append( "# End of Smb4K user entries." );
 
538
 
 
539
      write = true;
 
540
    }
 
541
    else if ( begin != -1 && end != -1 )
 
542
    {
 
543
      for ( int i = begin; i != end; ++i )
 
544
      {
 
545
        if ( contents.at( i ).startsWith( "User_Alias\tSMB4KUSERS" ) )
 
546
        {
 
547
          for ( int j = 0; j < adduser.size(); ++j )
 
548
          {
 
549
            if ( !contents.at( i ).contains( adduser.at( j ) ) )
 
550
            {
 
551
              contents[i].append( ","+adduser.at( j ) );
 
552
              continue;
 
553
            }
 
554
            else
 
555
            {
 
556
              continue;
 
557
            }
 
558
          }
 
559
 
 
560
          write = true;
 
561
          break;
 
562
        }
 
563
        else
 
564
        {
 
565
          continue;
 
566
        }
 
567
      }
 
568
    }
 
569
    else
 
570
    {
 
571
      cerr << argv[0] << ": " << I18N_NOOP( "The Smb4K section does not conform with the required format." ) << endl;
 
572
      cerr << argv[0] << ": " << I18N_NOOP( "Aborting." ) << endl;
 
573
      removeLockFile();
 
574
      exit( EXIT_FAILURE );
 
575
    }
 
576
  }
 
577
  else
 
578
  {
 
579
    // Do nothing
 
580
  }
 
581
 
 
582
  // Remove user(s).
 
583
  if ( !removeuser.isEmpty() )
 
584
  {
 
585
    if ( begin != -1 && end != -1 )
 
586
    {
 
587
      for ( int i = begin; i != end; ++i )
 
588
      {
 
589
        if ( contents.at( i ).startsWith( "User_Alias\tSMB4KUSERS" ) )
 
590
        {
 
591
          QString users = contents.at( i ).section( "=", 1, 1 ).trimmed();
 
592
 
 
593
          if ( !users.contains( "," ) )
 
594
          {
 
595
            // In this case, there is only one user in the list. Check if
 
596
            // it is the user who requested the removal:
 
597
            for ( int j = 0; j < removeuser.size(); ++j )
 
598
            {
 
599
              if ( QString::compare( users, removeuser.at( j ) ) == 0 )
 
600
              {
 
601
                // They are equal. Remove all entries:
 
602
                int k = begin;
 
603
 
 
604
                while ( k != end + 1 ) // We want to remove line 'end' as well.
 
605
                {
 
606
                  contents.removeAt( begin );
 
607
 
 
608
                  k++;
 
609
                }
 
610
 
 
611
                write = true;
 
612
 
 
613
                break;
 
614
              }
 
615
              else
 
616
              {
 
617
                // They are not equal: Do nothing.
 
618
                break;
 
619
              }
 
620
            }
 
621
 
 
622
            break;
 
623
          }
 
624
          else
 
625
          {
 
626
            // In this case there is more than one user in the list.
 
627
            // Remove the user who requested the removal:
 
628
            QStringList list = users.split( ",", QString::SkipEmptyParts );
 
629
            int index = 0;
 
630
 
 
631
            for ( int j = 0; j < removeuser.size(); ++j )
 
632
            {
 
633
              index = list.indexOf( removeuser.at( j ), 0 );
 
634
 
 
635
              if ( index != -1 )
 
636
              {
 
637
                list.removeAt( index );
 
638
                contents[i].replace( users, list.join( "," ) );
 
639
 
 
640
                write = true;
 
641
 
 
642
                continue;
 
643
              }
 
644
              else
 
645
              {
 
646
                continue;
 
647
              }
 
648
            }
 
649
 
 
650
            break;
 
651
          }
 
652
 
 
653
          break;
 
654
        }
 
655
        else
 
656
        {
 
657
          continue;
 
658
        }
 
659
      }
 
660
    }
 
661
    else if ( begin == -1 && end == -1 )
 
662
    {
 
663
      // Do nothing
 
664
    }
 
665
    else
 
666
    {
 
667
      cerr << argv[0] << ": " << I18N_NOOP( "The Smb4K section does not conform with the required format." ) << endl;
 
668
      cerr << argv[0] << ": " << I18N_NOOP( "Aborting." ) << endl;
 
669
      removeLockFile();
 
670
      exit( EXIT_FAILURE );
 
671
    }
 
672
  }
 
673
  else
 
674
  {
 
675
    // Nothing to do.
 
676
  }
 
677
 
 
678
  if ( write )
 
679
  {
 
680
    // Temporarily give the *owner* the permission to
 
681
    // write to the file.
 
682
    file.setPermissions( QFile::WriteOwner | QFile::ReadOwner );
 
683
 
 
684
    if ( file.open( QIODevice::WriteOnly | QIODevice::Text ) )
 
685
    {
 
686
      QTextStream ts( &file );
 
687
      // Note: With Qt 4.3 this seems to be obsolete, we'll keep
 
688
      // it for now.
 
689
      ts.setCodec( QTextCodec::codecForLocale() );
 
690
 
 
691
      ts << contents.join( "\n" ) << endl;
 
692
 
 
693
      file.close();
 
694
      file.setPermissions( perms );
 
695
    }
 
696
    else
 
697
    {
 
698
      file.setPermissions( perms );
 
699
      cerr << argv[0] << ": " << file.errorString().toLocal8Bit().data() << endl;
 
700
      removeLockFile();
 
701
      exit( EXIT_FAILURE );
 
702
    }
 
703
  }
 
704
  else
 
705
  {
 
706
    // No modifications are needed.
 
707
  }
 
708
 
 
709
  // File permissions were fixed above.
 
710
 
 
711
  args->clear();
 
712
 
 
713
  removeLockFile();
 
714
 
 
715
  app.exit( EXIT_SUCCESS );
 
716
}